Implementation of multi-sprites in mbgl-core (#1858)
Co-authored-by: Christophe Brasseur <christophe.brasseur@geolives.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Bart Louwers <bart.louwers@gmail.com> Co-authored-by: Bart Louwers <bart@emeel.net>
This commit is contained in:
2
.github/workflows/ios-ci.yml
vendored
2
.github/workflows/ios-ci.yml
vendored
@@ -96,7 +96,7 @@ jobs:
|
||||
- name: Build RenderTest .ipa and .xctest for AWS Device Farm
|
||||
run: |
|
||||
set -e
|
||||
bazel run --//:renderer=metal //platform/ios:xcodeproj
|
||||
bazel run //platform/ios:xcodeproj --@rules_xcodeproj//xcodeproj:extra_common_flags="--//:renderer=metal"
|
||||
build_dir="$(mktemp -d)"
|
||||
xcodebuild build-for-testing -scheme RenderTest -project MapLibre.xcodeproj -derivedDataPath "$build_dir"
|
||||
render_test_app_dir="$(dirname "$(find "$build_dir" -name RenderTestApp.app)")"
|
||||
|
||||
@@ -700,6 +700,7 @@ list(APPEND SRC_FILES
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/style/collection.hpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/style/conversion/color_ramp_property_value.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/style/conversion/constant.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/style/conversion/sprite.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/style/conversion/coordinate.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/style/conversion/custom_geometry_source_options.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/style/conversion/filter.cpp
|
||||
@@ -759,6 +760,8 @@ list(APPEND SRC_FILES
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/style/expression/within.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/style/filter.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/style/image.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/style/sprite.hpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/style/sprite.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/style/image_impl.cpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/style/image_impl.hpp
|
||||
${PROJECT_SOURCE_DIR}/src/mbgl/style/layer.cpp
|
||||
|
||||
@@ -396,6 +396,8 @@ MLN_CORE_SOURCE = [
|
||||
"src/mbgl/style/conversion/stringify.hpp",
|
||||
"src/mbgl/style/conversion/tileset.cpp",
|
||||
"src/mbgl/style/conversion/transition_options.cpp",
|
||||
"src/mbgl/style/conversion/sprite.hpp",
|
||||
"src/mbgl/style/conversion/sprite.cpp",
|
||||
"src/mbgl/style/custom_tile_loader.cpp",
|
||||
"src/mbgl/style/custom_tile_loader.hpp",
|
||||
"src/mbgl/style/expression/assertion.cpp",
|
||||
@@ -437,6 +439,8 @@ MLN_CORE_SOURCE = [
|
||||
"src/mbgl/style/expression/value.cpp",
|
||||
"src/mbgl/style/expression/within.cpp",
|
||||
"src/mbgl/style/filter.cpp",
|
||||
"src/mbgl/style/sprite.hpp",
|
||||
"src/mbgl/style/sprite.cpp",
|
||||
"src/mbgl/style/image.cpp",
|
||||
"src/mbgl/style/image_impl.cpp",
|
||||
"src/mbgl/style/image_impl.hpp",
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"network": [
|
||||
[
|
||||
"probeNetwork - default - end",
|
||||
2,
|
||||
35923
|
||||
],
|
||||
[
|
||||
"probeNetwork - default - start",
|
||||
0,
|
||||
0
|
||||
]
|
||||
],
|
||||
"gfx": [
|
||||
[
|
||||
"probeGFX - default - end",
|
||||
1,
|
||||
4,
|
||||
9,
|
||||
1,
|
||||
[
|
||||
22080,
|
||||
22080
|
||||
],
|
||||
[
|
||||
46,
|
||||
46
|
||||
],
|
||||
[
|
||||
384,
|
||||
384
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"network": [
|
||||
[
|
||||
"probeNetwork - default - end",
|
||||
4,
|
||||
247582
|
||||
],
|
||||
[
|
||||
"probeNetwork - default - start",
|
||||
0,
|
||||
0
|
||||
]
|
||||
],
|
||||
"gfx": [
|
||||
[
|
||||
"probeGFX - default - end",
|
||||
2,
|
||||
6,
|
||||
13,
|
||||
1,
|
||||
[
|
||||
28480,
|
||||
28480
|
||||
],
|
||||
[
|
||||
46,
|
||||
46
|
||||
],
|
||||
[
|
||||
384,
|
||||
384
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,56 @@
|
||||
{
|
||||
"version": 8,
|
||||
"metadata": {
|
||||
"test": {
|
||||
"pixelRatio": 1,
|
||||
"width": 128,
|
||||
"height": 64
|
||||
}
|
||||
},
|
||||
"center": [
|
||||
0,
|
||||
0
|
||||
],
|
||||
"zoom": 0,
|
||||
"sources": {
|
||||
"geojson": {
|
||||
"type": "geojson",
|
||||
"data": {
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [25, 0]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [-25, 0]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"sprite": [{
|
||||
"id": "default",
|
||||
"url": "local://sprites/emerald"
|
||||
}],
|
||||
"layers": [
|
||||
{
|
||||
"id": "default",
|
||||
"type": "symbol",
|
||||
"source": "geojson",
|
||||
"layout": {
|
||||
"symbol-placement": "point",
|
||||
"icon-image": "post_icon"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,79 @@
|
||||
{
|
||||
"version": 8,
|
||||
"metadata": {
|
||||
"test": {
|
||||
"pixelRatio": 1,
|
||||
"width": 128,
|
||||
"height": 64
|
||||
}
|
||||
},
|
||||
"center": [
|
||||
0,
|
||||
0
|
||||
],
|
||||
"zoom": 0,
|
||||
"sources": {
|
||||
"source-one": {
|
||||
"type": "geojson",
|
||||
"data": {
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [25, 0]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"source-two": {
|
||||
"type": "geojson",
|
||||
"data": {
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [-25, 0]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"sprite": [
|
||||
{
|
||||
"id": "default",
|
||||
"url": "local://sprites/emerald"
|
||||
},
|
||||
{
|
||||
"id": "sprite",
|
||||
"url": "local://sprites/sprite"
|
||||
}
|
||||
],
|
||||
"layers": [
|
||||
{
|
||||
"id": "default-sprite-features",
|
||||
"type": "symbol",
|
||||
"source": "source-one",
|
||||
"layout": {
|
||||
"symbol-placement": "point",
|
||||
"icon-image": "post_icon"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "sprite-sprite-features",
|
||||
"type": "symbol",
|
||||
"source": "source-two",
|
||||
"layout": {
|
||||
"symbol-placement": "point",
|
||||
"icon-image": "sprite:night-lighthouse-12"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"network": [
|
||||
[
|
||||
"probeNetwork - default - end",
|
||||
2,
|
||||
35923
|
||||
],
|
||||
[
|
||||
"probeNetwork - default - start",
|
||||
0,
|
||||
0
|
||||
]
|
||||
],
|
||||
"gfx": [
|
||||
[
|
||||
"probeGFX - default - end",
|
||||
1,
|
||||
4,
|
||||
9,
|
||||
1,
|
||||
[
|
||||
22080,
|
||||
22080
|
||||
],
|
||||
[
|
||||
46,
|
||||
46
|
||||
],
|
||||
[
|
||||
384,
|
||||
384
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"network": [
|
||||
[
|
||||
"probeNetwork - default - end",
|
||||
4,
|
||||
247582
|
||||
],
|
||||
[
|
||||
"probeNetwork - default - start",
|
||||
0,
|
||||
0
|
||||
]
|
||||
],
|
||||
"gfx": [
|
||||
[
|
||||
"probeGFX - default - end",
|
||||
2,
|
||||
6,
|
||||
13,
|
||||
1,
|
||||
[
|
||||
28480,
|
||||
28480
|
||||
],
|
||||
[
|
||||
46,
|
||||
46
|
||||
],
|
||||
[
|
||||
384,
|
||||
384
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
- Add support for the [`slice` expression](https://maplibre.org/maplibre-style-spec/expressions/#slice) ([#1113](https://github.com/maplibre/maplibre-native/pull/1133))
|
||||
- Add support for the [`index-of` expression](https://maplibre.org/maplibre-style-spec/expressions/#index-of) ([#1113](https://github.com/maplibre/maplibre-native/pull/1113))
|
||||
- Add support for [multi sprites](https://github.com/maplibre/maplibre-native/pull/1858). More information on this feature can be found in the [Style Spec Documentation](https://maplibre.org/maplibre-style-spec/sprite/#multiple-sprite-sources).
|
||||
- Change to a more natural fling animation and allow setting `flingThreshold` and `flingAnimationBaseTime` in `UiSettings` ([#963](https://github.com/maplibre/maplibre-native/pull/963))
|
||||
|
||||
- 💥 Breaking: Change package of all classes from `com.mapbox.mapboxsdk` to `org.maplibre.android` ([#1201](https://github.com/maplibre/maplibre-native/pull/1201)). This means you will need to fix your imports.
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <mbgl/style/sources/image_source.hpp>
|
||||
#include <mbgl/style/conversion/json.hpp>
|
||||
#include <mbgl/style/conversion/tileset.hpp>
|
||||
#include <mbgl/style/sprite.hpp>
|
||||
#include <mbgl/text/glyph.hpp>
|
||||
#include <mbgl/util/i18n.hpp>
|
||||
#include <mbgl/util/mapbox.hpp>
|
||||
@@ -223,8 +224,8 @@ OfflineRegionStatus OfflineDownload::getStatus() const {
|
||||
: NON_IDEOGRAPH_GLYPH_RANGES_PER_FONT_STACK);
|
||||
}
|
||||
|
||||
if (!parser.spriteURL.empty()) {
|
||||
result->requiredResourceCount += 4;
|
||||
if (!parser.sprites.empty()) {
|
||||
result->requiredResourceCount += 4 * parser.sprites.size();
|
||||
}
|
||||
|
||||
return *result;
|
||||
@@ -246,7 +247,6 @@ void OfflineDownload::activateDownload() {
|
||||
parser.parse(*styleResponse.data);
|
||||
|
||||
auto tileServerOptions = onlineFileSource.getResourceOptions().tileServerOptions();
|
||||
parser.spriteURL = util::mapbox::canonicalizeSpriteURL(tileServerOptions, parser.spriteURL);
|
||||
parser.glyphURL = util::mapbox::canonicalizeGlyphURL(tileServerOptions, parser.glyphURL);
|
||||
|
||||
for (const auto& source : parser.sources) {
|
||||
@@ -343,12 +343,15 @@ void OfflineDownload::activateDownload() {
|
||||
}
|
||||
}
|
||||
|
||||
if (!parser.spriteURL.empty()) {
|
||||
if (!parser.sprites.empty()) {
|
||||
// Always request 1x and @2x sprite images for portability.
|
||||
queueResource(Resource::spriteImage(parser.spriteURL, 1));
|
||||
queueResource(Resource::spriteImage(parser.spriteURL, 2));
|
||||
queueResource(Resource::spriteJSON(parser.spriteURL, 1));
|
||||
queueResource(Resource::spriteJSON(parser.spriteURL, 2));
|
||||
for (const auto& sprite : parser.sprites) {
|
||||
std::string spriteURL = util::mapbox::canonicalizeSpriteURL(tileServerOptions, sprite.spriteURL);
|
||||
queueResource(Resource::spriteImage(spriteURL, 1));
|
||||
queueResource(Resource::spriteImage(spriteURL, 2));
|
||||
queueResource(Resource::spriteJSON(spriteURL, 1));
|
||||
queueResource(Resource::spriteJSON(spriteURL, 2));
|
||||
}
|
||||
}
|
||||
|
||||
continueDownload();
|
||||
|
||||
@@ -4,6 +4,10 @@ MapLibre welcomes participation and contributions from everyone. Please read [`C
|
||||
|
||||
## main
|
||||
|
||||
## 6.2.0
|
||||
|
||||
- Add support for [multi sprites](https://github.com/maplibre/maplibre-native/pull/1858). More information on this feature can be found in the [Style Spec Documentation](https://maplibre.org/maplibre-style-spec/sprite/#multiple-sprite-sources).
|
||||
|
||||
## 6.1.1
|
||||
|
||||
- Tighten camera equality requirements ([#2139](https://github.com/maplibre/maplibre-native/pull/2139)).
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <mbgl/style/conversion/layer.hpp>
|
||||
#include <mbgl/style/conversion/light.hpp>
|
||||
#include <mbgl/style/conversion/source.hpp>
|
||||
#include <mbgl/style/conversion/sprite.hpp>
|
||||
#include <mbgl/style/layer.hpp>
|
||||
#include <mbgl/style/light.hpp>
|
||||
#include <mbgl/style/source.hpp>
|
||||
|
||||
@@ -55,7 +55,7 @@ void Map::Impl::onUpdate() {
|
||||
timePoint,
|
||||
transform.getState(),
|
||||
style->impl->getGlyphURL(),
|
||||
style->impl->spriteLoaded,
|
||||
style->impl->areSpritesLoaded(),
|
||||
style->impl->getTransitionOptions(),
|
||||
style->impl->getLight()->impl,
|
||||
style->impl->getImageImpls(),
|
||||
|
||||
@@ -33,48 +33,56 @@ SpriteLoader::SpriteLoader(float pixelRatio_)
|
||||
|
||||
SpriteLoader::~SpriteLoader() = default;
|
||||
|
||||
void SpriteLoader::load(const std::string& url, FileSource& fileSource) {
|
||||
if (url.empty()) {
|
||||
void SpriteLoader::load(const std::optional<style::Sprite> sprite, FileSource& fileSource) {
|
||||
if (!sprite) {
|
||||
// Treat a non-existent sprite as a successfully loaded empty sprite.
|
||||
observer->onSpriteLoaded({});
|
||||
observer->onSpriteLoaded(std::nullopt, {});
|
||||
return;
|
||||
}
|
||||
|
||||
data = std::make_unique<Data>();
|
||||
std::string id = sprite->id;
|
||||
std::string url = sprite->spriteURL;
|
||||
|
||||
data->jsonRequest = fileSource.request(Resource::spriteJSON(url, pixelRatio), [this](Response res) {
|
||||
dataMap[id] = std::make_unique<Data>();
|
||||
dataMap[id]->jsonRequest = fileSource.request(Resource::spriteJSON(url, pixelRatio), [this, sprite](Response res) {
|
||||
std::lock_guard<std::mutex> lock(dataMapMutex);
|
||||
Data* data = dataMap[sprite->id].get();
|
||||
if (res.error) {
|
||||
observer->onSpriteError(std::make_exception_ptr(std::runtime_error(res.error->message)));
|
||||
observer->onSpriteError(*sprite, std::make_exception_ptr(std::runtime_error(res.error->message)));
|
||||
} else if (res.notModified) {
|
||||
return;
|
||||
} else if (res.noContent) {
|
||||
data->json = std::make_shared<std::string>();
|
||||
emitSpriteLoadedIfComplete();
|
||||
emitSpriteLoadedIfComplete(*sprite);
|
||||
} else {
|
||||
// Only trigger a sprite loaded event we got new data.
|
||||
assert(data->json != res.data);
|
||||
data->json = std::move(res.data);
|
||||
emitSpriteLoadedIfComplete();
|
||||
emitSpriteLoadedIfComplete(*sprite);
|
||||
}
|
||||
});
|
||||
|
||||
data->spriteRequest = fileSource.request(Resource::spriteImage(url, pixelRatio), [this](Response res) {
|
||||
dataMap[id]->spriteRequest = fileSource.request(
|
||||
Resource::spriteImage(url, pixelRatio), [this, sprite](Response res) {
|
||||
std::lock_guard<std::mutex> lock(dataMapMutex);
|
||||
Data* data = dataMap[sprite->id].get();
|
||||
if (res.error) {
|
||||
observer->onSpriteError(std::make_exception_ptr(std::runtime_error(res.error->message)));
|
||||
observer->onSpriteError(*sprite, std::make_exception_ptr(std::runtime_error(res.error->message)));
|
||||
} else if (res.notModified) {
|
||||
return;
|
||||
} else if (res.noContent) {
|
||||
data->image = std::make_shared<std::string>();
|
||||
emitSpriteLoadedIfComplete();
|
||||
emitSpriteLoadedIfComplete(*sprite);
|
||||
} else {
|
||||
assert(data->image != res.data);
|
||||
assert(dataMap[sprite->id]->image != res.data);
|
||||
data->image = std::move(res.data);
|
||||
emitSpriteLoadedIfComplete();
|
||||
emitSpriteLoadedIfComplete(*sprite);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void SpriteLoader::emitSpriteLoadedIfComplete() {
|
||||
void SpriteLoader::emitSpriteLoadedIfComplete(style::Sprite sprite) {
|
||||
Data* data = dataMap[sprite.id].get();
|
||||
assert(data);
|
||||
if (!data->image || !data->json) {
|
||||
return;
|
||||
@@ -85,22 +93,22 @@ void SpriteLoader::emitSpriteLoadedIfComplete() {
|
||||
std::exception_ptr error;
|
||||
};
|
||||
|
||||
auto parseClosure = [image = data->image, json = data->json]() -> ParseResult {
|
||||
auto parseClosure = [sprite = sprite, image = data->image, json = data->json]() -> ParseResult {
|
||||
try {
|
||||
return {parseSprite(*image, *json), nullptr};
|
||||
return {parseSprite(sprite.id, *image, *json), nullptr};
|
||||
} catch (...) {
|
||||
return {{}, std::current_exception()};
|
||||
}
|
||||
};
|
||||
|
||||
auto resultClosure = [this, weak = weakFactory.makeWeakPtr()](ParseResult result) {
|
||||
auto resultClosure = [this, sprite = sprite, weak = weakFactory.makeWeakPtr()](ParseResult result) {
|
||||
if (!weak) return; // This instance has been deleted.
|
||||
|
||||
if (result.error) {
|
||||
observer->onSpriteError(result.error);
|
||||
observer->onSpriteError(std::optional(sprite), result.error);
|
||||
return;
|
||||
}
|
||||
observer->onSpriteLoaded(std::move(result.images));
|
||||
observer->onSpriteLoaded(std::optional(sprite), std::move(result.images));
|
||||
};
|
||||
|
||||
threadPool->scheduleAndReplyValue(parseClosure, resultClosure);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/style/image.hpp>
|
||||
#include <mbgl/style/sprite.hpp>
|
||||
#include <mapbox/std/weak.hpp>
|
||||
|
||||
#include <string>
|
||||
@@ -21,12 +22,12 @@ public:
|
||||
SpriteLoader(float pixelRatio);
|
||||
~SpriteLoader();
|
||||
|
||||
void load(const std::string& url, FileSource&);
|
||||
void load(const std::optional<style::Sprite> sprite, FileSource&);
|
||||
|
||||
void setObserver(SpriteLoaderObserver*);
|
||||
|
||||
private:
|
||||
void emitSpriteLoadedIfComplete();
|
||||
void emitSpriteLoadedIfComplete(style::Sprite sprite);
|
||||
|
||||
// Invoked by SpriteAtlasWorker
|
||||
friend class SpriteLoaderWorker;
|
||||
@@ -34,7 +35,8 @@ private:
|
||||
const float pixelRatio;
|
||||
|
||||
struct Data;
|
||||
std::unique_ptr<Data> data;
|
||||
std::map<std::string, std::unique_ptr<Data>> dataMap;
|
||||
std::mutex dataMapMutex;
|
||||
|
||||
SpriteLoaderObserver* observer = nullptr;
|
||||
std::shared_ptr<Scheduler> threadPool;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <mbgl/style/image.hpp>
|
||||
#include <mbgl/util/immutable.hpp>
|
||||
#include <mbgl/style/sprite.hpp>
|
||||
|
||||
#include <exception>
|
||||
#include <vector>
|
||||
@@ -17,9 +18,9 @@ public:
|
||||
virtual ~SpriteLoaderObserver() = default;
|
||||
|
||||
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
||||
virtual void onSpriteLoaded(std::vector<Immutable<style::Image::Impl>>) {}
|
||||
virtual void onSpriteLoaded(std::optional<style::Sprite>, std::vector<Immutable<style::Image::Impl>>) {}
|
||||
|
||||
virtual void onSpriteError(std::exception_ptr) {}
|
||||
virtual void onSpriteError(std::optional<style::Sprite>, std::exception_ptr) {}
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -152,7 +152,9 @@ std::optional<style::ImageContent> getContent(const JSValue& value, const char*
|
||||
|
||||
} // namespace
|
||||
|
||||
std::vector<Immutable<style::Image::Impl>> parseSprite(const std::string& encodedImage, const std::string& json) {
|
||||
std::vector<Immutable<style::Image::Impl>> parseSprite(const std::string& id,
|
||||
const std::string& encodedImage,
|
||||
const std::string& json) {
|
||||
const PremultipliedImage raster = decodeImage(encodedImage);
|
||||
|
||||
JSDocument doc;
|
||||
@@ -170,6 +172,11 @@ std::vector<Immutable<style::Image::Impl>> parseSprite(const std::string& encode
|
||||
images.reserve(properties.MemberCount());
|
||||
for (const auto& property : properties) {
|
||||
const std::string name = {property.name.GetString(), property.name.GetStringLength()};
|
||||
std::string completeName = name;
|
||||
if (id != "default") {
|
||||
completeName = id + ":";
|
||||
completeName += name;
|
||||
}
|
||||
const JSValue& value = property.value;
|
||||
|
||||
if (value.IsObject()) {
|
||||
@@ -183,8 +190,17 @@ std::vector<Immutable<style::Image::Impl>> parseSprite(const std::string& encode
|
||||
style::ImageStretches stretchY = getStretches(value, "stretchY", name.c_str());
|
||||
std::optional<style::ImageContent> content = getContent(value, "content", name.c_str());
|
||||
|
||||
auto image = createStyleImage(
|
||||
name, raster, x, y, width, height, pixelRatio, sdf, std::move(stretchX), std::move(stretchY), content);
|
||||
auto image = createStyleImage(completeName,
|
||||
raster,
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
pixelRatio,
|
||||
sdf,
|
||||
std::move(stretchX),
|
||||
std::move(stretchY),
|
||||
content);
|
||||
if (image) {
|
||||
images.push_back(std::move(image->baseImpl));
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ std::unique_ptr<style::Image> createStyleImage(const std::string& id,
|
||||
const std::optional<style::ImageContent>& content = std::nullopt);
|
||||
|
||||
// Parses an image and an associated JSON file and returns the sprite objects.
|
||||
std::vector<Immutable<style::Image::Impl>> parseSprite(const std::string& image, const std::string& json);
|
||||
std::vector<Immutable<style::Image::Impl>> parseSprite(const std::string& id,
|
||||
const std::string& image,
|
||||
const std::string& json);
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
34
src/mbgl/style/conversion/sprite.cpp
Normal file
34
src/mbgl/style/conversion/sprite.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#include <mbgl/style/conversion/sprite.hpp>
|
||||
#include <mbgl/style/conversion/constant.hpp>
|
||||
#include <mbgl/style/conversion_impl.hpp>
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace mbgl {
|
||||
namespace style {
|
||||
namespace conversion {
|
||||
|
||||
std::optional<Sprite> Converter<Sprite>::operator()(const Convertible& value, Error& error) const {
|
||||
std::optional<std::string> id;
|
||||
auto idValue = objectMember(value, "id");
|
||||
if (!idValue) {
|
||||
error.message = "id must be defined for sprite object";
|
||||
return std::nullopt;
|
||||
}
|
||||
id = toString(*idValue);
|
||||
|
||||
std::optional<std::string> spriteURL;
|
||||
auto urlValue = objectMember(value, "url");
|
||||
if (!urlValue) {
|
||||
error.message = "url must be defined for sprite object";
|
||||
return std::nullopt;
|
||||
}
|
||||
spriteURL = toString(*urlValue);
|
||||
|
||||
const Sprite sprite(*id, *spriteURL);
|
||||
return sprite;
|
||||
}
|
||||
|
||||
} // namespace conversion
|
||||
} // namespace style
|
||||
} // namespace mbgl
|
||||
21
src/mbgl/style/conversion/sprite.hpp
Normal file
21
src/mbgl/style/conversion/sprite.hpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/style/sprite.hpp>
|
||||
#include <mbgl/style/conversion.hpp>
|
||||
|
||||
#include <optional>
|
||||
#include <memory>
|
||||
|
||||
namespace mbgl {
|
||||
namespace style {
|
||||
namespace conversion {
|
||||
|
||||
template <>
|
||||
struct Converter<Sprite> {
|
||||
public:
|
||||
std::optional<Sprite> operator()(const Convertible& value, Error& error) const;
|
||||
};
|
||||
|
||||
} // namespace conversion
|
||||
} // namespace style
|
||||
} // namespace mbgl
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <mbgl/style/conversion/source.hpp>
|
||||
#include <mbgl/style/conversion/layer.hpp>
|
||||
#include <mbgl/style/conversion/light.hpp>
|
||||
#include <mbgl/style/conversion/sprite.hpp>
|
||||
#include <mbgl/style/conversion/transition_options.hpp>
|
||||
#include <mbgl/style/conversion_impl.hpp>
|
||||
|
||||
@@ -17,7 +18,9 @@
|
||||
#include <rapidjson/error/en.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace mbgl {
|
||||
namespace style {
|
||||
@@ -103,10 +106,7 @@ StyleParseResult Parser::parse(const std::string& json) {
|
||||
}
|
||||
|
||||
if (document.HasMember("sprite")) {
|
||||
const JSValue& sprite = document["sprite"];
|
||||
if (sprite.IsString()) {
|
||||
spriteURL = {sprite.GetString(), sprite.GetStringLength()};
|
||||
}
|
||||
parseSprites(document["sprite"]);
|
||||
}
|
||||
|
||||
if (document.HasMember("glyphs")) {
|
||||
@@ -165,6 +165,40 @@ void Parser::parseSources(const JSValue& value) {
|
||||
}
|
||||
}
|
||||
|
||||
void Parser::parseSprites(const JSValue& value) {
|
||||
if (value.IsString()) {
|
||||
std::string url = {value.GetString(), value.GetStringLength()};
|
||||
auto sprite = Sprite("default", url);
|
||||
sprites.emplace_back(sprite);
|
||||
} else if (value.IsArray()) {
|
||||
std::unordered_set<std::string> spriteIds;
|
||||
for (auto& spriteValue : value.GetArray()) {
|
||||
if (!spriteValue.IsObject()) {
|
||||
Log::Warning(Event::ParseStyle, "sprite child must be an object");
|
||||
continue;
|
||||
}
|
||||
|
||||
conversion::Error error;
|
||||
std::optional<Sprite> sprite = conversion::convert<Sprite>(spriteValue, error);
|
||||
if (!sprite) {
|
||||
Log::Warning(Event::ParseStyle, error.message);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (spriteIds.find(sprite->id) != spriteIds.end()) {
|
||||
Log::Warning(Event::ParseStyle, "sprite ids must be unique");
|
||||
continue;
|
||||
}
|
||||
|
||||
spriteIds.insert(sprite->id);
|
||||
sprites.emplace_back(*sprite);
|
||||
}
|
||||
} else {
|
||||
Log::Warning(Event::ParseStyle, "sprite must be an object or string");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Parser::parseLayers(const JSValue& value) {
|
||||
std::vector<std::string> ids;
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/style/layer.hpp>
|
||||
#include <mbgl/style/sprite.hpp>
|
||||
#include <mbgl/style/source.hpp>
|
||||
#include <mbgl/style/light.hpp>
|
||||
|
||||
#include <mbgl/util/constants.hpp>
|
||||
#include <mbgl/util/rapidjson.hpp>
|
||||
#include <mbgl/util/font_stack.hpp>
|
||||
@@ -27,7 +27,7 @@ public:
|
||||
|
||||
StyleParseResult parse(const std::string&);
|
||||
|
||||
std::string spriteURL;
|
||||
std::vector<Sprite> sprites;
|
||||
std::string glyphURL;
|
||||
|
||||
std::vector<std::unique_ptr<Source>> sources;
|
||||
@@ -49,6 +49,7 @@ private:
|
||||
void parseTransition(const JSValue&);
|
||||
void parseLight(const JSValue&);
|
||||
void parseSources(const JSValue&);
|
||||
void parseSprites(const JSValue&);
|
||||
void parseLayers(const JSValue&);
|
||||
void parseLayer(const std::string& id, const JSValue&, std::unique_ptr<Layer>&);
|
||||
|
||||
|
||||
14
src/mbgl/style/sprite.cpp
Normal file
14
src/mbgl/style/sprite.cpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#include <mbgl/style/sprite.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace style {
|
||||
|
||||
Sprite::~Sprite() = default;
|
||||
|
||||
Sprite::Sprite(std::string id_, std::string spriteURL_) {
|
||||
this->id = id_;
|
||||
this->spriteURL = spriteURL_;
|
||||
}
|
||||
|
||||
} // namespace style
|
||||
} // namespace mbgl
|
||||
18
src/mbgl/style/sprite.hpp
Normal file
18
src/mbgl/style/sprite.hpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace mbgl {
|
||||
namespace style {
|
||||
|
||||
class Sprite {
|
||||
public:
|
||||
Sprite(std::string, std::string);
|
||||
~Sprite();
|
||||
|
||||
std::string id;
|
||||
std::string spriteURL;
|
||||
};
|
||||
|
||||
} // namespace style
|
||||
} // namespace mbgl
|
||||
@@ -118,11 +118,22 @@ void Style::Impl::parse(const std::string& json_) {
|
||||
|
||||
setLight(std::make_unique<Light>(parser.light));
|
||||
|
||||
spriteLoaded = false;
|
||||
if (fileSource) {
|
||||
spriteLoader->load(parser.spriteURL, *fileSource);
|
||||
if (parser.sprites.empty()) {
|
||||
// We identify no sprite with 'default' as string in the sprite loading status.
|
||||
spritesLoadingStatus["default"] = false;
|
||||
spriteLoader->load(std::nullopt, *fileSource);
|
||||
} else {
|
||||
onSpriteError(std::make_exception_ptr(std::runtime_error("Unable to find resource provider for sprite url.")));
|
||||
for (const auto& sprite : parser.sprites) {
|
||||
spritesLoadingStatus[sprite.id] = false;
|
||||
spriteLoader->load(std::optional(sprite), *fileSource);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// We identify no sprite with 'default' as string in the sprite loading status.
|
||||
spritesLoadingStatus["default"] = false;
|
||||
onSpriteError(std::nullopt,
|
||||
std::make_exception_ptr(std::runtime_error("Unable to find resource provider for sprite url.")));
|
||||
}
|
||||
glyphURL = parser.glyphURL;
|
||||
|
||||
@@ -255,12 +266,24 @@ Source* Style::Impl::getSource(const std::string& id) const {
|
||||
return sources.get(id);
|
||||
}
|
||||
|
||||
bool Style::Impl::areSpritesLoaded() const {
|
||||
if (spritesLoadingStatus.empty()) {
|
||||
return false; // If nothing is stored inside, sprites are not yet loaded.
|
||||
}
|
||||
for (const auto& entry : spritesLoadingStatus) {
|
||||
if (!entry.second) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Style::Impl::isLoaded() const {
|
||||
if (!loaded) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!spriteLoaded) {
|
||||
if (!areSpritesLoaded()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -338,7 +361,8 @@ void Style::Impl::onSourceDescriptionChanged(Source& source) {
|
||||
}
|
||||
}
|
||||
|
||||
void Style::Impl::onSpriteLoaded(std::vector<Immutable<style::Image::Impl>> images_) {
|
||||
void Style::Impl::onSpriteLoaded(std::optional<style::Sprite> sprite,
|
||||
std::vector<Immutable<style::Image::Impl>> images_) {
|
||||
auto newImages = makeMutable<ImageImpls>(*images);
|
||||
assert(std::is_sorted(newImages->begin(), newImages->end()));
|
||||
|
||||
@@ -358,16 +382,24 @@ void Style::Impl::onSpriteLoaded(std::vector<Immutable<style::Image::Impl>> imag
|
||||
newImages->end(), std::make_move_iterator(images_.begin()), std::make_move_iterator(images_.end()));
|
||||
std::sort(newImages->begin(), newImages->end());
|
||||
images = std::move(newImages);
|
||||
spriteLoaded = true;
|
||||
if (sprite) {
|
||||
spritesLoadingStatus[sprite->id] = true;
|
||||
} else {
|
||||
spritesLoadingStatus["default"] = true;
|
||||
}
|
||||
observer->onUpdate(); // For *-pattern properties.
|
||||
}
|
||||
|
||||
void Style::Impl::onSpriteError(std::exception_ptr error) {
|
||||
void Style::Impl::onSpriteError(std::optional<style::Sprite> sprite, std::exception_ptr error) {
|
||||
lastError = error;
|
||||
Log::Error(Event::Style, "Failed to load sprite: " + util::toString(error));
|
||||
observer->onResourceError(error);
|
||||
if (sprite) {
|
||||
spritesLoadingStatus[sprite->id] = true;
|
||||
} else {
|
||||
spritesLoadingStatus["default"] = false;
|
||||
}
|
||||
// Unblock rendering tiles (even though sprite request has failed).
|
||||
spriteLoaded = true;
|
||||
observer->onUpdate();
|
||||
}
|
||||
|
||||
|
||||
@@ -86,10 +86,10 @@ public:
|
||||
Immutable<std::vector<Immutable<Layer::Impl>>> getLayerImpls() const;
|
||||
|
||||
void dumpDebugLogs() const;
|
||||
bool areSpritesLoaded() const;
|
||||
|
||||
bool mutated = false;
|
||||
bool loaded = false;
|
||||
bool spriteLoaded = false;
|
||||
|
||||
private:
|
||||
void parse(const std::string&);
|
||||
@@ -108,14 +108,15 @@ private:
|
||||
Collection<Layer> layers;
|
||||
TransitionOptions transitionOptions;
|
||||
std::unique_ptr<Light> light;
|
||||
std::unordered_map<std::string, bool> spritesLoadingStatus;
|
||||
|
||||
// Defaults
|
||||
std::string name;
|
||||
CameraOptions defaultCamera;
|
||||
|
||||
// SpriteLoaderObserver implementation.
|
||||
void onSpriteLoaded(std::vector<Immutable<style::Image::Impl>>) override;
|
||||
void onSpriteError(std::exception_ptr) override;
|
||||
void onSpriteLoaded(std::optional<style::Sprite> sprite, std::vector<Immutable<style::Image::Impl>>) override;
|
||||
void onSpriteError(std::optional<style::Sprite> sprite, std::exception_ptr) override;
|
||||
|
||||
// SourceObserver implementation.
|
||||
void onSourceLoaded(Source&) override;
|
||||
|
||||
8
test/fixtures/style_parser/sprites-missing-fields.info.json
vendored
Normal file
8
test/fixtures/style_parser/sprites-missing-fields.info.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"default": {
|
||||
"log": [
|
||||
[1, "WARNING", "ParseStyle", "id must be defined for sprite object"],
|
||||
[1, "WARNING", "ParseStyle", "url must be defined for sprite object"]
|
||||
]
|
||||
}
|
||||
}
|
||||
4
test/fixtures/style_parser/sprites-missing-fields.style.json
vendored
Normal file
4
test/fixtures/style_parser/sprites-missing-fields.style.json
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"version": 8,
|
||||
"sprite": [{"id": "default"},{"url": "https://example.com"}]
|
||||
}
|
||||
7
test/fixtures/style_parser/sprites-not-same-ids.info.json
vendored
Normal file
7
test/fixtures/style_parser/sprites-not-same-ids.info.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"default": {
|
||||
"log": [
|
||||
[1, "WARNING", "ParseStyle", "sprite ids must be unique"]
|
||||
]
|
||||
}
|
||||
}
|
||||
11
test/fixtures/style_parser/sprites-not-same-ids.style.json
vendored
Normal file
11
test/fixtures/style_parser/sprites-not-same-ids.style.json
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"version": 8,
|
||||
"sprite": [{
|
||||
"id": "default",
|
||||
"url": "https://example.com"
|
||||
},
|
||||
{
|
||||
"id": "default",
|
||||
"url": "https://example2.com"
|
||||
}]
|
||||
}
|
||||
@@ -24,7 +24,8 @@ TEST(ImageManager, Basic) {
|
||||
FixtureLog log;
|
||||
ImageManager imageManager;
|
||||
|
||||
auto images = parseSprite(util::read_file("test/fixtures/annotations/emerald.png"),
|
||||
auto images = parseSprite("default",
|
||||
util::read_file("test/fixtures/annotations/emerald.png"),
|
||||
util::read_file("test/fixtures/annotations/emerald.json"));
|
||||
for (auto& image : images) {
|
||||
imageManager.addImage(image);
|
||||
|
||||
@@ -18,7 +18,8 @@ TEST(PatternAtlas, Basic) {
|
||||
FixtureLog log;
|
||||
PatternAtlas patternAtlas;
|
||||
|
||||
auto images = parseSprite(util::read_file("test/fixtures/annotations/emerald.png"),
|
||||
auto images = parseSprite("default",
|
||||
util::read_file("test/fixtures/annotations/emerald.png"),
|
||||
util::read_file("test/fixtures/annotations/emerald.json"));
|
||||
for (auto& image : images) {
|
||||
if (image->id == "metro") {
|
||||
|
||||
@@ -17,11 +17,11 @@ using namespace mbgl::style;
|
||||
|
||||
class StubSpriteLoaderObserver : public SpriteLoaderObserver {
|
||||
public:
|
||||
void onSpriteLoaded(std::vector<Immutable<style::Image::Impl>> images) override {
|
||||
void onSpriteLoaded(std::optional<Sprite>, std::vector<Immutable<style::Image::Impl>> images) override {
|
||||
if (spriteLoaded) spriteLoaded(std::move(images));
|
||||
}
|
||||
|
||||
void onSpriteError(std::exception_ptr error) override {
|
||||
void onSpriteError(std::optional<Sprite>, std::exception_ptr error) override {
|
||||
if (spriteError) spriteError(error);
|
||||
}
|
||||
|
||||
@@ -43,7 +43,9 @@ public:
|
||||
Log::setObserver(std::make_unique<Log::NullObserver>());
|
||||
|
||||
spriteLoader.setObserver(&observer);
|
||||
spriteLoader.load("test/fixtures/resources/sprite", fileSource);
|
||||
|
||||
Sprite sprite = Sprite("default", "test/fixtures/resources/sprite");
|
||||
spriteLoader.load(sprite, fileSource);
|
||||
|
||||
loop.run();
|
||||
}
|
||||
|
||||
@@ -256,7 +256,7 @@ TEST(Sprite, SpriteParsing) {
|
||||
const auto image_1x = util::read_file("test/fixtures/annotations/emerald.png");
|
||||
const auto json_1x = util::read_file("test/fixtures/annotations/emerald.json");
|
||||
|
||||
const auto images = parseSprite(image_1x, json_1x);
|
||||
const auto images = parseSprite("default", image_1x, json_1x);
|
||||
|
||||
std::set<std::string> names;
|
||||
std::transform(
|
||||
@@ -352,7 +352,7 @@ TEST(Sprite, SpriteParsingInvalidJSON) {
|
||||
const auto json_1x = R"JSON({ "image": " })JSON";
|
||||
|
||||
try {
|
||||
parseSprite(image_1x, json_1x);
|
||||
parseSprite("default", image_1x, json_1x);
|
||||
FAIL() << "Expected exception";
|
||||
} catch (std::runtime_error& err) {
|
||||
EXPECT_STREQ(
|
||||
@@ -367,7 +367,7 @@ TEST(Sprite, SpriteParsingInvalidStretches) {
|
||||
|
||||
const auto image_1x = util::read_file("test/fixtures/annotations/emerald.png");
|
||||
|
||||
parseSprite(image_1x, R"JSON({
|
||||
parseSprite("default", image_1x, R"JSON({
|
||||
"interstate_1": {
|
||||
"width": 40,
|
||||
"height": 42,
|
||||
@@ -385,7 +385,7 @@ TEST(Sprite, SpriteParsingInvalidStretches) {
|
||||
"an array"}));
|
||||
EXPECT_EQ(0u, log.uncheckedCount());
|
||||
|
||||
parseSprite(image_1x, R"JSON({
|
||||
parseSprite("default", image_1x, R"JSON({
|
||||
"interstate_1": {
|
||||
"width": 40,
|
||||
"height": 42,
|
||||
@@ -403,7 +403,7 @@ TEST(Sprite, SpriteParsingInvalidStretches) {
|
||||
"be an array of two numbers"}));
|
||||
EXPECT_EQ(0u, log.uncheckedCount());
|
||||
|
||||
parseSprite(image_1x, R"JSON({
|
||||
parseSprite("default", image_1x, R"JSON({
|
||||
"interstate_1": {
|
||||
"width": 40,
|
||||
"height": 42,
|
||||
@@ -427,7 +427,7 @@ TEST(Sprite, SpriteParsingInvalidContent) {
|
||||
|
||||
const auto image_1x = util::read_file("test/fixtures/annotations/emerald.png");
|
||||
|
||||
parseSprite(image_1x, R"JSON({
|
||||
parseSprite("default", image_1x, R"JSON({
|
||||
"interstate_1": {
|
||||
"width": 40,
|
||||
"height": 42,
|
||||
@@ -445,7 +445,7 @@ TEST(Sprite, SpriteParsingInvalidContent) {
|
||||
"an array of four numbers"}));
|
||||
EXPECT_EQ(0u, log.uncheckedCount());
|
||||
|
||||
parseSprite(image_1x, R"JSON({
|
||||
parseSprite("default", image_1x, R"JSON({
|
||||
"interstate_1": {
|
||||
"width": 40,
|
||||
"height": 42,
|
||||
@@ -469,7 +469,7 @@ TEST(Sprite, SpriteParsingStretchAndContent) {
|
||||
|
||||
const auto image_1x = util::read_file("test/fixtures/annotations/emerald.png");
|
||||
|
||||
const auto images = parseSprite(image_1x, R"JSON({
|
||||
const auto images = parseSprite("default", image_1x, R"JSON({
|
||||
"image": {
|
||||
"width": 16,
|
||||
"height": 16,
|
||||
@@ -494,7 +494,7 @@ TEST(Sprite, SpriteParsingEmptyImage) {
|
||||
const auto image_1x = util::read_file("test/fixtures/annotations/emerald.png");
|
||||
const auto json_1x = R"JSON({ "image": {} })JSON";
|
||||
|
||||
const auto images = parseSprite(image_1x, json_1x);
|
||||
const auto images = parseSprite("default", image_1x, json_1x);
|
||||
EXPECT_EQ(0u, images.size());
|
||||
|
||||
EXPECT_EQ(1u,
|
||||
@@ -513,7 +513,7 @@ TEST(Sprite, SpriteParsingSimpleWidthHeight) {
|
||||
const auto image_1x = util::read_file("test/fixtures/annotations/emerald.png");
|
||||
const auto json_1x = R"JSON({ "image": { "width": 32, "height": 32 } })JSON";
|
||||
|
||||
const auto images = parseSprite(image_1x, json_1x);
|
||||
const auto images = parseSprite("default", image_1x, json_1x);
|
||||
EXPECT_EQ(1u, images.size());
|
||||
}
|
||||
|
||||
@@ -523,7 +523,7 @@ TEST(Sprite, SpriteParsingWidthTooBig) {
|
||||
const auto image_1x = util::read_file("test/fixtures/annotations/emerald.png");
|
||||
const auto json_1x = R"JSON({ "image": { "width": 65536, "height": 32 } })JSON";
|
||||
|
||||
const auto images = parseSprite(image_1x, json_1x);
|
||||
const auto images = parseSprite("default", image_1x, json_1x);
|
||||
EXPECT_EQ(0u, images.size());
|
||||
|
||||
EXPECT_EQ(1u,
|
||||
@@ -550,7 +550,7 @@ TEST(Sprite, SpriteParsingNegativeWidth) {
|
||||
const auto image_1x = util::read_file("test/fixtures/annotations/emerald.png");
|
||||
const auto json_1x = R"JSON({ "image": { "width": -1, "height": 32 } })JSON";
|
||||
|
||||
const auto images = parseSprite(image_1x, json_1x);
|
||||
const auto images = parseSprite("default", image_1x, json_1x);
|
||||
EXPECT_EQ(0u, images.size());
|
||||
|
||||
EXPECT_EQ(1u,
|
||||
@@ -577,7 +577,7 @@ TEST(Sprite, SpriteParsingNullRatio) {
|
||||
const auto image_1x = util::read_file("test/fixtures/annotations/emerald.png");
|
||||
const auto json_1x = R"JSON({ "image": { "width": 32, "height": 32, "pixelRatio": 0 } })JSON";
|
||||
|
||||
const auto images = parseSprite(image_1x, json_1x);
|
||||
const auto images = parseSprite("default", image_1x, json_1x);
|
||||
EXPECT_EQ(0u, images.size());
|
||||
|
||||
EXPECT_EQ(1u,
|
||||
|
||||
@@ -126,6 +126,63 @@ INSTANTIATE_TEST_SUITE_P(StyleParser, StyleParserTest, ::testing::ValuesIn([] {
|
||||
return names;
|
||||
}()));
|
||||
|
||||
TEST(StyleParser, SpriteAsString) {
|
||||
style::Parser parser;
|
||||
parser.parse(R"({
|
||||
"version": 8,
|
||||
"sprite": "https://example.com/default/markers"
|
||||
})");
|
||||
auto result = &parser.sprites;
|
||||
ASSERT_EQ(1, result->size());
|
||||
ASSERT_EQ("https://example.com/default/markers", result->at(0).spriteURL);
|
||||
ASSERT_EQ("default", result->at(0).id);
|
||||
}
|
||||
|
||||
TEST(StyleParser, SpriteAsArrayEmpty) {
|
||||
style::Parser parser;
|
||||
parser.parse(R"({
|
||||
"version": 8,
|
||||
"sprite": []
|
||||
})");
|
||||
auto result = &parser.sprites;
|
||||
ASSERT_EQ(0, result->size());
|
||||
}
|
||||
|
||||
TEST(StyleParser, SpriteAsArraySingle) {
|
||||
style::Parser parser;
|
||||
parser.parse(R"({
|
||||
"version": 8,
|
||||
"sprite": [{
|
||||
"id": "default",
|
||||
"url": "https://example.com/default/markers"
|
||||
}]
|
||||
})");
|
||||
auto result = &parser.sprites;
|
||||
ASSERT_EQ(1, result->size());
|
||||
ASSERT_EQ("https://example.com/default/markers", result->at(0).spriteURL);
|
||||
ASSERT_EQ("default", result->at(0).id);
|
||||
}
|
||||
|
||||
TEST(StyleParser, SpriteAsArrayMultiple) {
|
||||
style::Parser parser;
|
||||
parser.parse(R"({
|
||||
"version": 8,
|
||||
"sprite": [{
|
||||
"id": "default",
|
||||
"url": "https://example.com/default/markers"
|
||||
},{
|
||||
"id": "hiking",
|
||||
"url": "https://example.com/hiking/markers"
|
||||
}]
|
||||
})");
|
||||
auto result = &parser.sprites;
|
||||
ASSERT_EQ(2, result->size());
|
||||
ASSERT_EQ("https://example.com/default/markers", result->at(0).spriteURL);
|
||||
ASSERT_EQ("default", result->at(0).id);
|
||||
ASSERT_EQ("https://example.com/hiking/markers", result->at(1).spriteURL);
|
||||
ASSERT_EQ("hiking", result->at(1).id);
|
||||
}
|
||||
|
||||
TEST(StyleParser, FontStacks) {
|
||||
style::Parser parser;
|
||||
parser.parse(util::read_file("test/fixtures/style_parser/font_stacks.json"));
|
||||
|
||||
Reference in New Issue
Block a user