summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
authordanswick <dan.swick@gmail.com>2019-09-18 11:39:43 -0700
committerdanswick <dan.swick@gmail.com>2019-09-18 11:39:43 -0700
commit46914ecff8b3f2a1945b33358a879c2aac074f17 (patch)
tree697cf276a43ae4c18c0ad7029c00e7d771448822 /platform
parent47ea84ad1a5fed3431d026c5765c17c507d4623e (diff)
parent8805defe57aa0d8886c7828d39b1b9b1f17f21b8 (diff)
downloadqtlocation-mapboxgl-upstream/android-docs-automation.tar.gz
Merge branch 'master' into android-docs-automationupstream/android-docs-automation
Diffstat (limited to 'platform')
-rw-r--r--platform/android/CHANGELOG.md1
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java2
-rw-r--r--platform/darwin/src/MGLRasterDEMSource.mm11
-rw-r--r--platform/darwin/src/MGLRasterTileSource.mm15
-rw-r--r--platform/darwin/src/MGLRasterTileSource_Private.h4
-rw-r--r--platform/darwin/test/MGLStyleTests.mm95
-rw-r--r--platform/glfw/glfw_view.cpp103
-rw-r--r--platform/glfw/glfw_view.hpp4
-rw-r--r--platform/ios/CHANGELOG.md1
-rw-r--r--platform/ios/Integration Tests/MGLStyleLayerIntegrationTests.m16
-rw-r--r--platform/node/CHANGELOG.md3
-rw-r--r--platform/node/src/node_feature.cpp6
-rw-r--r--platform/node/src/node_map.cpp221
-rw-r--r--platform/node/src/node_map.hpp4
-rw-r--r--platform/node/test/ignores.json15
-rw-r--r--platform/node/test/js/map.test.js3
-rw-r--r--platform/node/test/suite_implementation.js6
17 files changed, 417 insertions, 93 deletions
diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md
index 734647e4c8..76704a44cf 100644
--- a/platform/android/CHANGELOG.md
+++ b/platform/android/CHANGELOG.md
@@ -8,6 +8,7 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to
- Fixed constant repainting for the sources with invisible layers, caused by `RenderSource::hasFadingTiles()` returning `true` all the time. [#15600](https://github.com/mapbox/mapbox-gl-native/pull/15600)
- Fixed an issue that caused the state of CompassView not up to date when `UiSettings.setCompassEnabled()` is set to true. [#15606](https://github.com/mapbox/mapbox-gl-native/pull/15606)
- Fixed an issue that `maxzoom` in style `Sources` option was ignored when URL resource is provided. It may cause problems such as extra tiles downloading at higher zoom level than `maxzoom`, or problems that wrong setting of `overscaledZ` in `OverscaledTileID` that will be passed to `SymbolLayout`, leading wrong rendering appearance. [#15581](https://github.com/mapbox/mapbox-gl-native/pull/15581)
+ - Fixed an assertion hit caused by possibility of adding a layer to an incompatible source. [#15644](https://github.com/mapbox/mapbox-gl-native/pull/15644)
## 8.4.0-alpha.2 - September 11, 2019
[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.4.0-alpha.1...android-v8.4.0-alpha.2) since [Mapbox Maps SDK for Android v8.4.0-alpha.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.4.0-alpha.1):
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java
index 1e0069c25f..990bd32262 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java
@@ -235,7 +235,7 @@ public class MapSnapshotter {
*/
@NonNull
public Options withApiBaseUri(String apiBaseUri) {
- this.apiBaseUrl = apiBaseUrl;
+ this.apiBaseUrl = apiBaseUri;
return this;
}
diff --git a/platform/darwin/src/MGLRasterDEMSource.mm b/platform/darwin/src/MGLRasterDEMSource.mm
index 27614b9ef4..753499ff94 100644
--- a/platform/darwin/src/MGLRasterDEMSource.mm
+++ b/platform/darwin/src/MGLRasterDEMSource.mm
@@ -7,11 +7,10 @@
@implementation MGLRasterDEMSource
-- (std::unique_ptr<mbgl::style::RasterSource>)pendingSourceWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL tileSize:(CGFloat)tileSize {
- NSString *configurationURLString = configurationURL.mgl_URLByStandardizingScheme.absoluteString;
- return std::make_unique<mbgl::style::RasterDEMSource>(identifier.UTF8String,
- configurationURLString.UTF8String,
- uint16_t(round(tileSize)));
+- (std::unique_ptr<mbgl::style::RasterSource>)pendingSourceWithIdentifier:(NSString *)identifier urlOrTileset:(mbgl::variant<std::string, mbgl::Tileset>)urlOrTileset tileSize:(uint16_t)tileSize {
+ auto source = std::make_unique<mbgl::style::RasterDEMSource>(identifier.UTF8String,
+ urlOrTileset,
+ tileSize);
+ return source;
}
-
@end
diff --git a/platform/darwin/src/MGLRasterTileSource.mm b/platform/darwin/src/MGLRasterTileSource.mm
index e89367711e..b31cee296f 100644
--- a/platform/darwin/src/MGLRasterTileSource.mm
+++ b/platform/darwin/src/MGLRasterTileSource.mm
@@ -33,15 +33,16 @@ static const CGFloat MGLRasterTileSourceRetinaTileSize = 512;
}
- (instancetype)initWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL tileSize:(CGFloat)tileSize {
- auto source = [self pendingSourceWithIdentifier:identifier configurationURL:configurationURL tileSize:tileSize];
+ NSString *configurationURLString = configurationURL.mgl_URLByStandardizingScheme.absoluteString;
+ auto source = [self pendingSourceWithIdentifier:identifier urlOrTileset:configurationURLString.UTF8String tileSize:uint16_t(round(tileSize))];
return self = [super initWithPendingSource:std::move(source)];
}
-- (std::unique_ptr<mbgl::style::RasterSource>)pendingSourceWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL tileSize:(CGFloat)tileSize {
- NSString *configurationURLString = configurationURL.mgl_URLByStandardizingScheme.absoluteString;
- return std::make_unique<mbgl::style::RasterSource>(identifier.UTF8String,
- configurationURLString.UTF8String,
- uint16_t(round(tileSize)));
+- (std::unique_ptr<mbgl::style::RasterSource>)pendingSourceWithIdentifier:(NSString *)identifier urlOrTileset:(mbgl::variant<std::string, mbgl::Tileset>)urlOrTileset tileSize:(uint16_t)tileSize {
+ auto source = std::make_unique<mbgl::style::RasterSource>(identifier.UTF8String,
+ urlOrTileset,
+ tileSize);
+ return source;
}
- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NSArray<NSString *> *)tileURLTemplates options:(nullable NSDictionary<MGLTileSourceOption, id> *)options {
@@ -56,7 +57,7 @@ static const CGFloat MGLRasterTileSourceRetinaTileSize = 512;
tileSize = static_cast<uint16_t>(round(tileSizeNumber.doubleValue));
}
- auto source = std::make_unique<mbgl::style::RasterSource>(identifier.UTF8String, tileSet, tileSize);
+ auto source = [self pendingSourceWithIdentifier:identifier urlOrTileset:tileSet tileSize:tileSize];
return self = [super initWithPendingSource:std::move(source)];
}
diff --git a/platform/darwin/src/MGLRasterTileSource_Private.h b/platform/darwin/src/MGLRasterTileSource_Private.h
index 8502b811e2..55f342c7ff 100644
--- a/platform/darwin/src/MGLRasterTileSource_Private.h
+++ b/platform/darwin/src/MGLRasterTileSource_Private.h
@@ -1,8 +1,10 @@
#import "MGLRasterTileSource.h"
#include <memory>
+#include <mbgl/util/variant.hpp>
namespace mbgl {
+ class Tileset;
namespace style {
class RasterSource;
}
@@ -14,7 +16,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, readonly, nullable) mbgl::style::RasterSource *rawSource;
-- (std::unique_ptr<mbgl::style::RasterSource>)pendingSourceWithIdentifier:(NSString *)identifier configurationURL:(NSURL *)configurationURL tileSize:(CGFloat)tileSize;
+- (std::unique_ptr<mbgl::style::RasterSource>)pendingSourceWithIdentifier:(NSString *)identifier urlOrTileset:(mbgl::variant<std::string, mbgl::Tileset>)urlOrTileset tileSize:(uint16_t)tileSize;
@end
diff --git a/platform/darwin/test/MGLStyleTests.mm b/platform/darwin/test/MGLStyleTests.mm
index 7aaf70a80a..ec2605646c 100644
--- a/platform/darwin/test/MGLStyleTests.mm
+++ b/platform/darwin/test/MGLStyleTests.mm
@@ -229,23 +229,23 @@
- (void)testRemovingSourceInUse {
// Add a raster tile source
- MGLRasterTileSource *rasterTileSource = [[MGLRasterTileSource alloc] initWithIdentifier:@"some-identifier" tileURLTemplates:@[] options:nil];
- [self.style addSource:rasterTileSource];
+ MGLVectorTileSource *vectorTileSource = [[MGLVectorTileSource alloc] initWithIdentifier:@"some-identifier" tileURLTemplates:@[] options:nil];
+ [self.style addSource:vectorTileSource];
// Add a layer using it
- MGLFillStyleLayer *fillLayer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"fillLayer" source:rasterTileSource];
+ MGLFillStyleLayer *fillLayer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"fillLayer" source:vectorTileSource];
[self.style addLayer:fillLayer];
// Attempt to remove the raster tile source
NSError *error;
- BOOL result = [self.style removeSource:rasterTileSource error:&error];
+ BOOL result = [self.style removeSource:vectorTileSource error:&error];
XCTAssertFalse(result);
XCTAssertEqualObjects(error.domain, MGLErrorDomain);
XCTAssertEqual(error.code, MGLErrorCodeSourceIsInUseCannotRemove);
// Ensure it is still there
- XCTAssertTrue([[self.style sourceWithIdentifier:rasterTileSource.identifier] isMemberOfClass:[MGLRasterTileSource class]]);
+ XCTAssertTrue([[self.style sourceWithIdentifier:vectorTileSource.identifier] isMemberOfClass:[MGLVectorTileSource class]]);
}
- (void)testLayers {
@@ -311,54 +311,61 @@
}
- (void)testRemovingLayerBeforeAddingSameLayer {
- MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"shape-source-removing-before-adding" shape:nil options:nil];
-
- // Attempting to find a layer with identifier will trigger an exception if the source associated with the layer is not added
- [self.style addSource:source];
-
- MGLFillStyleLayer *fillLayer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"fill-layer" source:source];
- [self.style removeLayer:fillLayer];
- [self.style addLayer:fillLayer];
- XCTAssertNotNil([self.style layerWithIdentifier:fillLayer.identifier]);
-
- MGLRasterStyleLayer *rasterLayer = [[MGLRasterStyleLayer alloc] initWithIdentifier:@"raster-layer" source:source];
- [self.style removeLayer:rasterLayer];
- [self.style addLayer:rasterLayer];
- XCTAssertNotNil([self.style layerWithIdentifier:rasterLayer.identifier]);
-
- MGLSymbolStyleLayer *symbolLayer = [[MGLSymbolStyleLayer alloc] initWithIdentifier:@"symbol-layer" source:source];
- [self.style removeLayer:symbolLayer];
- [self.style addLayer:symbolLayer];
- XCTAssertNotNil([self.style layerWithIdentifier:symbolLayer.identifier]);
-
- MGLLineStyleLayer *lineLayer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"line-layer" source:source];
- [self.style removeLayer:lineLayer];
- [self.style addLayer:lineLayer];
- XCTAssertNotNil([self.style layerWithIdentifier:lineLayer.identifier]);
-
- MGLCircleStyleLayer *circleLayer = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"circle-layer" source:source];
- [self.style removeLayer:circleLayer];
- [self.style addLayer:circleLayer];
- XCTAssertNotNil([self.style layerWithIdentifier:circleLayer.identifier]);
-
- MGLBackgroundStyleLayer *backgroundLayer = [[MGLBackgroundStyleLayer alloc] initWithIdentifier:@"background-layer"];
- [self.style removeLayer:backgroundLayer];
- [self.style addLayer:backgroundLayer];
- XCTAssertNotNil([self.style layerWithIdentifier:backgroundLayer.identifier]);
+ {
+ MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"shape-source-removing-before-adding" shape:nil options:nil];
+
+ // Attempting to find a layer with identifier will trigger an exception if the source associated with the layer is not added
+ [self.style addSource:source];
+
+ MGLFillStyleLayer *fillLayer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"fill-layer" source:source];
+ [self.style removeLayer:fillLayer];
+ [self.style addLayer:fillLayer];
+ XCTAssertNotNil([self.style layerWithIdentifier:fillLayer.identifier]);
+
+ MGLSymbolStyleLayer *symbolLayer = [[MGLSymbolStyleLayer alloc] initWithIdentifier:@"symbol-layer" source:source];
+ [self.style removeLayer:symbolLayer];
+ [self.style addLayer:symbolLayer];
+ XCTAssertNotNil([self.style layerWithIdentifier:symbolLayer.identifier]);
+
+ MGLLineStyleLayer *lineLayer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"line-layer" source:source];
+ [self.style removeLayer:lineLayer];
+ [self.style addLayer:lineLayer];
+ XCTAssertNotNil([self.style layerWithIdentifier:lineLayer.identifier]);
+
+ MGLCircleStyleLayer *circleLayer = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"circle-layer" source:source];
+ [self.style removeLayer:circleLayer];
+ [self.style addLayer:circleLayer];
+ XCTAssertNotNil([self.style layerWithIdentifier:circleLayer.identifier]);
+
+ MGLBackgroundStyleLayer *backgroundLayer = [[MGLBackgroundStyleLayer alloc] initWithIdentifier:@"background-layer"];
+ [self.style removeLayer:backgroundLayer];
+ [self.style addLayer:backgroundLayer];
+ XCTAssertNotNil([self.style layerWithIdentifier:backgroundLayer.identifier]);
+ }
+
+ {
+ MGLRasterTileSource *rasterSource = [[MGLRasterTileSource alloc] initWithIdentifier:@"raster-tile-source" tileURLTemplates:@[] options:nil];
+ [self.style addSource:rasterSource];
+
+ MGLRasterStyleLayer *rasterLayer = [[MGLRasterStyleLayer alloc] initWithIdentifier:@"raster-layer" source:rasterSource];
+ [self.style removeLayer:rasterLayer];
+ [self.style addLayer:rasterLayer];
+ XCTAssertNotNil([self.style layerWithIdentifier:rasterLayer.identifier]);
+ }
}
- (void)testAddingLayerOfTypeABeforeRemovingLayerOfTypeBWithSameIdentifier {
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"shape-source-identifier" shape:nil options:nil];
[self.style addSource:source];
-
+
// Add a fill layer
MGLFillStyleLayer *fillLayer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"some-identifier" source:source];
[self.style addLayer:fillLayer];
-
+
// Attempt to remove a line layer with the same identifier as the fill layer
MGLLineStyleLayer *lineLayer = [[MGLLineStyleLayer alloc] initWithIdentifier:fillLayer.identifier source:source];
[self.style removeLayer:lineLayer];
-
+
XCTAssertTrue([[self.style layerWithIdentifier:fillLayer.identifier] isMemberOfClass:[MGLFillStyleLayer class]]);
}
@@ -382,10 +389,10 @@
MGLImage *image = [[NSBundle bundleForClass:[self class]] imageForResource:imageName];
#endif
XCTAssertNotNil(image);
-
+
[self.style setImage:image forName:imageName];
MGLImage *styleImage = [self.style imageForName:imageName];
-
+
XCTAssertNotNil(styleImage);
XCTAssertEqual(image.size.width, styleImage.size.width);
XCTAssertEqual(image.size.height, styleImage.size.height);
diff --git a/platform/glfw/glfw_view.cpp b/platform/glfw/glfw_view.cpp
index 43c4de9759..c39b2c904a 100644
--- a/platform/glfw/glfw_view.cpp
+++ b/platform/glfw/glfw_view.cpp
@@ -4,22 +4,24 @@
#include "ny_route.hpp"
#include <mbgl/annotation/annotation.hpp>
-#include <mbgl/style/style.hpp>
-#include <mbgl/style/sources/custom_geometry_source.hpp>
+#include <mbgl/gfx/backend.hpp>
+#include <mbgl/gfx/backend_scope.hpp>
+#include <mbgl/map/camera.hpp>
+#include <mbgl/renderer/renderer.hpp>
+#include <mbgl/style/expression/dsl.hpp>
#include <mbgl/style/image.hpp>
-#include <mbgl/style/transition_options.hpp>
#include <mbgl/style/layers/fill_extrusion_layer.hpp>
+#include <mbgl/style/layers/fill_layer.hpp>
#include <mbgl/style/layers/line_layer.hpp>
-#include <mbgl/style/expression/dsl.hpp>
+#include <mbgl/style/sources/custom_geometry_source.hpp>
+#include <mbgl/style/sources/geojson_source.hpp>
+#include <mbgl/style/style.hpp>
+#include <mbgl/style/transition_options.hpp>
+#include <mbgl/util/chrono.hpp>
+#include <mbgl/util/geo.hpp>
#include <mbgl/util/logging.hpp>
#include <mbgl/util/platform.hpp>
#include <mbgl/util/string.hpp>
-#include <mbgl/util/chrono.hpp>
-#include <mbgl/util/geo.hpp>
-#include <mbgl/renderer/renderer.hpp>
-#include <mbgl/gfx/backend.hpp>
-#include <mbgl/gfx/backend_scope.hpp>
-#include <mbgl/map/camera.hpp>
#include <mapbox/cheap_ruler.hpp>
#include <mapbox/geometry.hpp>
@@ -323,6 +325,52 @@ void GLFWView::onKey(GLFWwindow *window, int key, int /*scancode*/, int action,
case GLFW_KEY_T:
view->toggleCustomSource();
break;
+ case GLFW_KEY_F: {
+ using namespace mbgl;
+ using namespace mbgl::style;
+ using namespace mbgl::style::expression::dsl;
+
+ auto &style = view->map->getStyle();
+ if (!style.getSource("states")) {
+ std::string url = "https://docs.mapbox.com/mapbox-gl-js/assets/us_states.geojson";
+ auto source = std::make_unique<GeoJSONSource>("states");
+ source->setURL(url);
+ style.addSource(std::move(source));
+
+ mbgl::CameraOptions cameraOptions;
+ cameraOptions.center = mbgl::LatLng{42.619626, -103.523181};
+ cameraOptions.zoom = 3;
+ cameraOptions.pitch = 0;
+ cameraOptions.bearing = 0;
+ view->map->jumpTo(cameraOptions);
+ }
+
+ auto layer = style.getLayer("state-fills");
+ if (!layer) {
+ auto fillLayer = std::make_unique<FillLayer>("state-fills", "states");
+ fillLayer->setFillColor(mbgl::Color{0.0, 0.0, 1.0, 0.5});
+ fillLayer->setFillOpacity(PropertyExpression<float>(
+ createExpression(R"(["case", ["boolean", ["feature-state", "hover"], false], 1, 0.5])")));
+ style.addLayer(std::move(fillLayer));
+ } else {
+ layer->setVisibility(layer->getVisibility() == mbgl::style::VisibilityType::Visible
+ ? mbgl::style::VisibilityType::None
+ : mbgl::style::VisibilityType::Visible);
+ }
+
+ layer = style.getLayer("state-borders");
+ if (!layer) {
+ auto borderLayer = std::make_unique<LineLayer>("state-borders", "states");
+ borderLayer->setLineColor(mbgl::Color{0.0, 0.0, 1.0, 1.0});
+ borderLayer->setLineWidth(PropertyExpression<float>(
+ createExpression(R"(["case", ["boolean", ["feature-state", "hover"], false], 2, 1])")));
+ style.addLayer(std::move(borderLayer));
+ } else {
+ layer->setVisibility(layer->getVisibility() == mbgl::style::VisibilityType::Visible
+ ? mbgl::style::VisibilityType::None
+ : mbgl::style::VisibilityType::Visible);
+ }
+ } break;
}
}
@@ -558,6 +606,41 @@ void GLFWView::onMouseMove(GLFWwindow *window, double x, double y) {
}
view->lastX = x;
view->lastY = y;
+
+ auto &style = view->map->getStyle();
+ if (style.getLayer("state-fills")) {
+ auto screenCoordinate = mbgl::ScreenCoordinate{view->lastX, view->lastY};
+ const mbgl::RenderedQueryOptions queryOptions({{{"state-fills"}}, {}});
+ auto result = view->rendererFrontend->getRenderer()->queryRenderedFeatures(screenCoordinate, queryOptions);
+ using namespace mbgl;
+ FeatureState newState;
+
+ if (result.size() > 0) {
+ FeatureIdentifier id = result[0].id;
+ optional<std::string> idStr = featureIDtoString(id);
+
+ if (idStr) {
+ if (view->featureID && (*view->featureID != *idStr)) {
+ newState["hover"] = false;
+ view->rendererFrontend->getRenderer()->setFeatureState("states", {}, *view->featureID, newState);
+ view->featureID = nullopt;
+ }
+
+ if (!view->featureID) {
+ newState["hover"] = true;
+ view->featureID = featureIDtoString(id);
+ view->rendererFrontend->getRenderer()->setFeatureState("states", {}, *view->featureID, newState);
+ }
+ }
+ } else {
+ if (view->featureID) {
+ newState["hover"] = false;
+ view->rendererFrontend->getRenderer()->setFeatureState("states", {}, *view->featureID, newState);
+ view->featureID = nullopt;
+ }
+ }
+ view->invalidate();
+ }
}
void GLFWView::onWindowFocus(GLFWwindow *window, int focused) {
diff --git a/platform/glfw/glfw_view.hpp b/platform/glfw/glfw_view.hpp
index 54b89ba2d9..dbe6ceb046 100644
--- a/platform/glfw/glfw_view.hpp
+++ b/platform/glfw/glfw_view.hpp
@@ -1,9 +1,10 @@
#pragma once
#include <mbgl/map/map.hpp>
+#include <mbgl/util/geometry.hpp>
+#include <mbgl/util/optional.hpp>
#include <mbgl/util/run_loop.hpp>
#include <mbgl/util/timer.hpp>
-#include <mbgl/util/geometry.hpp>
struct GLFWwindow;
class GLFWBackend;
@@ -134,4 +135,5 @@ private:
GLFWwindow *window = nullptr;
bool dirty = false;
+ mbgl::optional<std::string> featureID;
};
diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md
index f2394d1b84..089cc18606 100644
--- a/platform/ios/CHANGELOG.md
+++ b/platform/ios/CHANGELOG.md
@@ -7,6 +7,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
### Styles and rendering
* Added an `-[MGLMapSnapshotter startWithOverlayHandler:completionHandler:]` method to provide the snapshot's current `CGContext` in order to perform custom drawing on `MGLMapSnapShot` objects. ([#15530](https://github.com/mapbox/mapbox-gl-native/pull/15530))
* Fixed an issue that `maxzoom` in style `Sources` option was ignored when URL resource is provided. It may cause problems such as extra tiles downloading at higher zoom level than `maxzoom`, or problems that wrong setting of `overscaledZ` in `OverscaledTileID` that will be passed to `SymbolLayout`, leading wrong rendering appearance. ([#15581](https://github.com/mapbox/mapbox-gl-native/pull/15581))
+* Fixed an assertion hit caused by possibility of adding a layer to an incompatible source. ([#15644](https://github.com/mapbox/mapbox-gl-native/pull/15644))
### Performance improvements
diff --git a/platform/ios/Integration Tests/MGLStyleLayerIntegrationTests.m b/platform/ios/Integration Tests/MGLStyleLayerIntegrationTests.m
index c018c457b9..f5f2f957d3 100644
--- a/platform/ios/Integration Tests/MGLStyleLayerIntegrationTests.m
+++ b/platform/ios/Integration Tests/MGLStyleLayerIntegrationTests.m
@@ -82,31 +82,31 @@
// Testing generated layers
MGLLineStyleLayer *lineLayer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"lineLayerID" source:source];
- MGLRasterStyleLayer *rasterLayer = [[MGLRasterStyleLayer alloc] initWithIdentifier:@"rasterLayerID" source:source];
+ MGLCircleStyleLayer *circleLayer = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"circleLayerID" source:source];
[self.mapView.style addSource:source];
[self.mapView.style addLayer:lineLayer];
- [self.mapView.style addLayer:rasterLayer];
+ [self.mapView.style addLayer:circleLayer];
XCTAssertNoThrow(lineLayer.isVisible);
- XCTAssertNoThrow(rasterLayer.isVisible);
+ XCTAssertNoThrow(circleLayer.isVisible);
XCTAssert(![source.description containsString:@"<unknown>"]);
XCTAssert(![lineLayer.description containsString:@"<unknown>"]);
- XCTAssert(![rasterLayer.description containsString:@"<unknown>"]);
+ XCTAssert(![circleLayer.description containsString:@"<unknown>"]);
self.styleLoadingExpectation = nil;
[self.mapView setStyleURL:[[NSBundle bundleForClass:[self class]] URLForResource:@"one-liner" withExtension:@"json"]];
[self waitForMapViewToFinishLoadingStyleWithTimeout:10];
-
+
XCTAssert([source.description containsString:@"<unknown>"]);
XCTAssert([lineLayer.description containsString:@"<unknown>"]);
- XCTAssert([rasterLayer.description containsString:@"<unknown>"]);
+ XCTAssert([circleLayer.description containsString:@"<unknown>"]);
XCTAssertThrowsSpecificNamed(lineLayer.isVisible, NSException, MGLInvalidStyleLayerException, @"Layer should raise an exception if its core peer got invalidated");
- XCTAssertThrowsSpecificNamed(rasterLayer.isVisible, NSException, MGLInvalidStyleLayerException, @"Layer should raise an exception if its core peer got invalidated");
+ XCTAssertThrowsSpecificNamed(circleLayer.isVisible, NSException, MGLInvalidStyleLayerException, @"Layer should raise an exception if its core peer got invalidated");
XCTAssertThrowsSpecificNamed([self.mapView.style removeLayer:lineLayer], NSException, NSInvalidArgumentException, @"Style should raise an exception when attempting to remove an invalid layer (e.g. if its core peer got invalidated)");
- XCTAssertThrowsSpecificNamed([self.mapView.style removeLayer:rasterLayer], NSException, NSInvalidArgumentException, @"Style should raise an exception when attempting to remove an invalid layer (e.g. if its core peer got invalidated)");
+ XCTAssertThrowsSpecificNamed([self.mapView.style removeLayer:circleLayer], NSException, NSInvalidArgumentException, @"Style should raise an exception when attempting to remove an invalid layer (e.g. if its core peer got invalidated)");
}
@end
diff --git a/platform/node/CHANGELOG.md b/platform/node/CHANGELOG.md
index 486dd44e10..84fbff741c 100644
--- a/platform/node/CHANGELOG.md
+++ b/platform/node/CHANGELOG.md
@@ -1,3 +1,6 @@
+# master
+* Add support for feature state APIs. ([#15480](https://github.com/mapbox/mapbox-gl-native/pull/15480))
+
# 4.3.0
* Introduce `text-writing-mode` layout property for symbol layer ([#14932](https://github.com/mapbox/mapbox-gl-native/pull/14932)). The `text-writing-mode` layout property allows control over symbol's preferred writing mode. The new property value is an array, whose values are enumeration values from a ( `horizontal` | `vertical` ) set.
* Fixed rendering and collision detection issues with using `text-variable-anchor` and `icon-text-fit` properties on the same layer ([#15367](https://github.com/mapbox/mapbox-gl-native/pull/15367)).
diff --git a/platform/node/src/node_feature.cpp b/platform/node/src/node_feature.cpp
index 2dfab686a7..646cc23338 100644
--- a/platform/node/src/node_feature.cpp
+++ b/platform/node/src/node_feature.cpp
@@ -167,6 +167,12 @@ v8::Local<v8::Object> toJS(const Feature& feature) {
Nan::Set(result, Nan::New("id").ToLocalChecked(), FeatureIdentifier::visit(feature.id, ToValue()));
}
+ Nan::Set(result, Nan::New("source").ToLocalChecked(), toJS(feature.source));
+ if (!feature.sourceLayer.empty()) {
+ Nan::Set(result, Nan::New("sourceLayer").ToLocalChecked(), toJS(feature.sourceLayer));
+ }
+ Nan::Set(result, Nan::New("state").ToLocalChecked(), toJS(feature.state));
+
return scope.Escape(result);
}
diff --git a/platform/node/src/node_map.cpp b/platform/node/src/node_map.cpp
index 641816dc00..7450f461f8 100644
--- a/platform/node/src/node_map.cpp
+++ b/platform/node/src/node_map.cpp
@@ -117,6 +117,9 @@ ParseError)JS").ToLocalChecked()).ToLocalChecked();
Nan::SetPrototypeMethod(tpl, "setAxonometric", SetAxonometric);
Nan::SetPrototypeMethod(tpl, "setXSkew", SetXSkew);
Nan::SetPrototypeMethod(tpl, "setYSkew", SetYSkew);
+ Nan::SetPrototypeMethod(tpl, "setFeatureState", SetFeatureState);
+ Nan::SetPrototypeMethod(tpl, "getFeatureState", GetFeatureState);
+ Nan::SetPrototypeMethod(tpl, "removeFeatureState", RemoveFeatureState);
Nan::SetPrototypeMethod(tpl, "dumpDebugLogs", DumpDebugLogs);
Nan::SetPrototypeMethod(tpl, "queryRenderedFeatures", QueryRenderedFeatures);
@@ -1099,6 +1102,224 @@ void NodeMap::SetYSkew(const Nan::FunctionCallbackInfo<v8::Value>& info) {
info.GetReturnValue().SetUndefined();
}
+void NodeMap::SetFeatureState(const Nan::FunctionCallbackInfo<v8::Value>& info) {
+ using namespace mbgl;
+ using namespace mbgl::style::conversion;
+
+ auto nodeMap = Nan::ObjectWrap::Unwrap<NodeMap>(info.Holder());
+ if (!nodeMap->map) return Nan::ThrowError(releasedMessage());
+
+ if (info.Length() < 2) {
+ return Nan::ThrowTypeError("Two arguments required");
+ }
+
+ if (!info[0]->IsObject() || !info[1]->IsObject()) {
+ return Nan::ThrowTypeError("Both arguments must be objects");
+ }
+
+ std::string sourceID, featureID;
+ mbgl::optional<std::string> sourceLayerID;
+ auto feature = Nan::To<v8::Object>(info[0]).ToLocalChecked();
+ if (Nan::Has(feature, Nan::New("source").ToLocalChecked()).FromJust()) {
+ auto sourceOption = Nan::Get(feature, Nan::New("source").ToLocalChecked()).ToLocalChecked();
+ if (!sourceOption->IsString()) {
+ return Nan::ThrowTypeError("Requires feature.source property to be a string");
+ }
+ sourceID = *Nan::Utf8String(sourceOption);
+ } else {
+ return Nan::ThrowTypeError("SetFeatureState: Requires feature.source property");
+ }
+
+ if (Nan::Has(feature, Nan::New("sourceLayer").ToLocalChecked()).FromJust()) {
+ auto sourceLayerOption = Nan::Get(feature, Nan::New("sourceLayer").ToLocalChecked()).ToLocalChecked();
+ if (!sourceLayerOption->IsString()) {
+ return Nan::ThrowTypeError("SetFeatureState: Requires feature.sourceLayer property to be a string");
+ }
+ sourceLayerID = {*Nan::Utf8String(sourceLayerOption)};
+ }
+
+ if (Nan::Has(feature, Nan::New("id").ToLocalChecked()).FromJust()) {
+ auto idOption = Nan::Get(feature, Nan::New("id").ToLocalChecked()).ToLocalChecked();
+ if (!idOption->IsString() && !(idOption->IsNumber() || idOption->IsString())) {
+ return Nan::ThrowTypeError("Requires feature.id property to be a string or a number");
+ }
+ featureID = *Nan::Utf8String(idOption);
+ } else {
+ return Nan::ThrowTypeError("SetFeatureState: Requires feature.id property");
+ }
+
+ Convertible state(info[1]);
+
+ if (!isObject(state)) {
+ return Nan::ThrowTypeError("Feature state must be an object");
+ }
+
+ std::string sourceLayer = sourceLayerID.value_or(std::string());
+ std::string stateKey;
+ Value stateValue;
+ bool valueParsed = false;
+ FeatureState newState;
+
+ const std::function<optional<Error>(const std::string&, const Convertible&)> convertFn =
+ [&](const std::string& k, const Convertible& v) -> optional<Error> {
+ optional<Value> value = toValue(v);
+ if (value) {
+ stateValue = std::move(*value);
+ valueParsed = true;
+ } else if (isArray(v)) {
+ std::vector<Value> array;
+ std::size_t length = arrayLength(v);
+ array.reserve(length);
+ for (size_t i = 0; i < length; ++i) {
+ optional<Value> arrayVal = toValue(arrayMember(v, i));
+ if (arrayVal) {
+ array.emplace_back(*arrayVal);
+ }
+ }
+ std::unordered_map<std::string, Value> result;
+ result[k] = std::move(array);
+ stateValue = std::move(result);
+ valueParsed = true;
+ return {};
+
+ } else if (isObject(v)) {
+ eachMember(v, convertFn);
+ }
+ if (!valueParsed) {
+ Nan::ThrowTypeError("Could not get feature state value");
+ return nullopt;
+ }
+ stateKey = k;
+ newState[stateKey] = stateValue;
+ return nullopt;
+ };
+
+ eachMember(state, convertFn);
+
+ try {
+ nodeMap->frontend->getRenderer()->setFeatureState(sourceID, sourceLayerID, featureID, newState);
+ } catch (const std::exception& ex) {
+ return Nan::ThrowError(ex.what());
+ }
+
+ info.GetReturnValue().SetUndefined();
+}
+
+void NodeMap::GetFeatureState(const Nan::FunctionCallbackInfo<v8::Value>& info) {
+ auto nodeMap = Nan::ObjectWrap::Unwrap<NodeMap>(info.Holder());
+ if (!nodeMap->map) return Nan::ThrowError(releasedMessage());
+
+ if (info.Length() < 1) {
+ return Nan::ThrowTypeError("One argument required");
+ }
+
+ if (!info[0]->IsObject() || !info[1]->IsObject()) {
+ return Nan::ThrowTypeError("Argument must be object");
+ }
+
+ std::string sourceID, featureID;
+ mbgl::optional<std::string> sourceLayerID;
+ auto feature = Nan::To<v8::Object>(info[0]).ToLocalChecked();
+ if (Nan::Has(feature, Nan::New("source").ToLocalChecked()).FromJust()) {
+ auto sourceOption = Nan::Get(feature, Nan::New("source").ToLocalChecked()).ToLocalChecked();
+ if (!sourceOption->IsString()) {
+ return Nan::ThrowTypeError("Requires feature.source property to be a string");
+ }
+ sourceID = *Nan::Utf8String(sourceOption);
+ } else {
+ return Nan::ThrowTypeError("GetFeatureState: Requires feature.source property");
+ }
+
+ if (Nan::Has(feature, Nan::New("sourceLayer").ToLocalChecked()).FromJust()) {
+ auto sourceLayerOption = Nan::Get(feature, Nan::New("sourceLayer").ToLocalChecked()).ToLocalChecked();
+ if (!sourceLayerOption->IsString()) {
+ return Nan::ThrowTypeError("GetFeatureState: Requires feature.sourceLayer property to be a string");
+ }
+ sourceLayerID = {*Nan::Utf8String(sourceLayerOption)};
+ }
+
+ if (Nan::Has(feature, Nan::New("id").ToLocalChecked()).FromJust()) {
+ auto idOption = Nan::Get(feature, Nan::New("id").ToLocalChecked()).ToLocalChecked();
+ if (!idOption->IsString() && !(idOption->IsNumber() || idOption->IsString())) {
+ return Nan::ThrowTypeError("Requires feature.id property to be a string or a number");
+ }
+ featureID = *Nan::Utf8String(idOption);
+ } else {
+ return Nan::ThrowTypeError("GetFeatureState: Requires feature.id property");
+ }
+
+ mbgl::FeatureState state;
+ try {
+ nodeMap->frontend->getRenderer()->getFeatureState(state, sourceID, sourceLayerID, featureID);
+ } catch (const std::exception& ex) {
+ return Nan::ThrowError(ex.what());
+ }
+
+ info.GetReturnValue().SetUndefined();
+}
+
+void NodeMap::RemoveFeatureState(const Nan::FunctionCallbackInfo<v8::Value>& info) {
+ auto nodeMap = Nan::ObjectWrap::Unwrap<NodeMap>(info.Holder());
+ if (!nodeMap->map) return Nan::ThrowError(releasedMessage());
+
+ if (info.Length() < 1) {
+ return Nan::ThrowTypeError("At least one argument required");
+ }
+
+ if (!info[0]->IsObject()) {
+ return Nan::ThrowTypeError("Argument 1 must be object");
+ }
+
+ if (info.Length() == 2 && !info[1]->IsString()) {
+ return Nan::ThrowTypeError("argument 2 must be string");
+ }
+
+ std::string sourceID;
+ mbgl::optional<std::string> sourceLayerID, featureID, stateKey;
+ auto feature = Nan::To<v8::Object>(info[0]).ToLocalChecked();
+ if (Nan::Has(feature, Nan::New("source").ToLocalChecked()).FromJust()) {
+ auto sourceOption = Nan::Get(feature, Nan::New("source").ToLocalChecked()).ToLocalChecked();
+ if (!sourceOption->IsString()) {
+ return Nan::ThrowTypeError("Requires feature.source property to be a string");
+ }
+ sourceID = *Nan::Utf8String(sourceOption);
+ } else {
+ return Nan::ThrowTypeError("RemoveFeatureState: Requires feature.source property");
+ }
+
+ if (Nan::Has(feature, Nan::New("sourceLayer").ToLocalChecked()).FromJust()) {
+ auto sourceLayerOption = Nan::Get(feature, Nan::New("sourceLayer").ToLocalChecked()).ToLocalChecked();
+ if (!sourceLayerOption->IsString()) {
+ return Nan::ThrowTypeError("RemoveFeatureState: Requires feature.sourceLayer property to be a string");
+ }
+ sourceLayerID = {*Nan::Utf8String(sourceLayerOption)};
+ }
+
+ if (Nan::Has(feature, Nan::New("id").ToLocalChecked()).FromJust()) {
+ auto idOption = Nan::Get(feature, Nan::New("id").ToLocalChecked()).ToLocalChecked();
+ if (!idOption->IsString() && !(idOption->IsNumber() || idOption->IsString())) {
+ return Nan::ThrowTypeError("Requires feature.id property to be a string or a number");
+ }
+ featureID = {*Nan::Utf8String(idOption)};
+ }
+
+ if (info.Length() == 2) {
+ auto keyParam = Nan::To<v8::String>(info[1]).ToLocalChecked();
+ if (!keyParam->IsString()) {
+ return Nan::ThrowTypeError("RemoveFeatureState: Requires feature key property to be a string");
+ }
+ stateKey = {*Nan::Utf8String(keyParam)};
+ }
+
+ try {
+ nodeMap->frontend->getRenderer()->removeFeatureState(sourceID, sourceLayerID, featureID, stateKey);
+ } catch (const std::exception& ex) {
+ return Nan::ThrowError(ex.what());
+ }
+
+ info.GetReturnValue().SetUndefined();
+}
+
void NodeMap::DumpDebugLogs(const Nan::FunctionCallbackInfo<v8::Value>& info) {
auto nodeMap = Nan::ObjectWrap::Unwrap<NodeMap>(info.Holder());
if (!nodeMap->map) return Nan::ThrowError(releasedMessage());
diff --git a/platform/node/src/node_map.hpp b/platform/node/src/node_map.hpp
index 486754c1c3..381e10381b 100644
--- a/platform/node/src/node_map.hpp
+++ b/platform/node/src/node_map.hpp
@@ -64,6 +64,10 @@ public:
static void DumpDebugLogs(const Nan::FunctionCallbackInfo<v8::Value>&);
static void QueryRenderedFeatures(const Nan::FunctionCallbackInfo<v8::Value>&);
+ static void SetFeatureState(const Nan::FunctionCallbackInfo<v8::Value>&);
+ static void GetFeatureState(const Nan::FunctionCallbackInfo<v8::Value>&);
+ static void RemoveFeatureState(const Nan::FunctionCallbackInfo<v8::Value>&);
+
static v8::Local<v8::Value> ParseError(const char* msg);
void startRender(RenderOptions options);
diff --git a/platform/node/test/ignores.json b/platform/node/test/ignores.json
index d32fb6b0c4..f053b2add1 100644
--- a/platform/node/test/ignores.json
+++ b/platform/node/test/ignores.json
@@ -20,15 +20,8 @@
"query-tests/geometry/multipolygon": "needs investigation",
"query-tests/geometry/polygon": "needs investigation",
"query-tests/world-wrapping/box": "skip - needs issue",
- "query-tests/circle-radius/feature-state": "skip - port https://github.com/mapbox/mapbox-gl-js/pull/6263 - needs issue",
- "query-tests/circle-stroke-width/feature-state": "skip - port https://github.com/mapbox/mapbox-gl-js/pull/6263 - needs issue",
"query-tests/fill-extrusion-translate/multiple-layers": "https://github.com/mapbox/mapbox-gl-native/issues/12701",
"query-tests/fill-translate/multiple-layers": "https://github.com/mapbox/mapbox-gl-native/issues/12701",
- "query-tests/line-gap-width/feature-state": "skip - port https://github.com/mapbox/mapbox-gl-js/pull/6263 - needs issue",
- "query-tests/line-offset/feature-state": "skip - port https://github.com/mapbox/mapbox-gl-js/pull/6263 - needs issue",
- "query-tests/line-offset/pattern-feature-state": "skip - port https://github.com/mapbox/mapbox-gl-js/pull/6263 - needs issue",
- "query-tests/line-width/feature-state": "skip - port https://github.com/mapbox/mapbox-gl-js/pull/6263 - needs issue",
- "query-tests/feature-state/default": "skip - port https://github.com/mapbox/mapbox-gl-js/pull/6263 - needs issue",
"query-tests/regressions/mapbox-gl-js#6555": "skip - no querySourceFeatures in mbgl-node; needs issue",
"render-tests/background-color/transition": "https://github.com/mapbox/mapbox-gl-native/issues/10619",
"render-tests/canvas/default": "skip - js specific",
@@ -52,7 +45,6 @@
"render-tests/fill-extrusion-pattern/opacity": "https://github.com/mapbox/mapbox-gl-js/issues/3327",
"render-tests/fill-extrusion-pattern/feature-expression": "https://github.com/mapbox/mapbox-gl-js/issues/3327",
"render-tests/fill-extrusion-pattern/tile-buffer": "https://github.com/mapbox/mapbox-gl-js/issues/3327",
- "render-tests/fill-pattern/update-feature-state": "skip - port https://github.com/mapbox/mapbox-gl-js/pull/6263 - needs issue",
"render-tests/geojson/inline-linestring-fill": "current behavior is arbitrary",
"render-tests/mixed-zoom/z10-z11": "https://github.com/mapbox/mapbox-gl-native/issues/10397",
"render-tests/raster-masking/overlapping-zoom": "https://github.com/mapbox/mapbox-gl-native/issues/10195",
@@ -73,19 +65,12 @@
"render-tests/symbol-cross-fade/chinese": "https://github.com/mapbox/mapbox-gl-native/issues/10619",
"render-tests/video/default": "skip - https://github.com/mapbox/mapbox-gl-native/issues/601",
"render-tests/background-color/colorSpace-hcl": "needs issue",
- "render-tests/feature-state/composite-expression": "https://github.com/mapbox/mapbox-gl-native/issues/12613",
- "render-tests/feature-state/data-expression": "https://github.com/mapbox/mapbox-gl-native/issues/12613",
- "render-tests/feature-state/vector-source": "https://github.com/mapbox/mapbox-gl-native/issues/12613",
"render-tests/text-variable-anchor/remember-last-placement": "skip - fails on gl-native, as symbol index is not functional at static map mode - needs issue",
- "render-tests/remove-feature-state/composite-expression": "https://github.com/mapbox/mapbox-gl-native/issues/12413",
- "render-tests/remove-feature-state/data-expression": "https://github.com/mapbox/mapbox-gl-native/issues/12413",
- "render-tests/remove-feature-state/vector-source": "https://github.com/mapbox/mapbox-gl-native/issues/12413",
"render-tests/regressions/mapbox-gl-js#8026": "skip - js specific",
"render-tests/fill-extrusion-geometry/linestring": "https://github.com/mapbox/mapbox-gl-native/pull/14240",
"render-tests/circle-sort-key/literal": "https://github.com/mapbox/mapbox-gl-native/issues/15008",
"render-tests/fill-sort-key/literal": "https://github.com/mapbox/mapbox-gl-native/issues/15008",
"render-tests/line-sort-key/literal": "https://github.com/mapbox/mapbox-gl-native/issues/15008",
- "query-tests/remove-feature-state/default": "https://github.com/mapbox/mapbox-gl-native/issues/12413",
"query-tests/fill-extrusion/base-in": "https://github.com/mapbox/mapbox-gl-native/issues/13139",
"query-tests/fill-extrusion/box-in": "https://github.com/mapbox/mapbox-gl-native/issues/13139",
"query-tests/fill-extrusion/side-in": "https://github.com/mapbox/mapbox-gl-native/issues/13139",
diff --git a/platform/node/test/js/map.test.js b/platform/node/test/js/map.test.js
index b21c1519e3..d085e32f4c 100644
--- a/platform/node/test/js/map.test.js
+++ b/platform/node/test/js/map.test.js
@@ -126,6 +126,9 @@ test('Map', function(t) {
'setAxonometric',
'setXSkew',
'setYSkew',
+ 'setFeatureState',
+ 'getFeatureState',
+ 'removeFeatureState',
'dumpDebugLogs',
'queryRenderedFeatures'
]);
diff --git a/platform/node/test/suite_implementation.js b/platform/node/test/suite_implementation.js
index f868af8ece..386bd41092 100644
--- a/platform/node/test/suite_implementation.js
+++ b/platform/node/test/suite_implementation.js
@@ -122,6 +122,12 @@ export default function (style, options, callback) {
map.load(operation[1]);
applyOperations(operations.slice(1), callback);
+ } else if (operation[0] ==='setFeatureState' || operation[0] ==='getFeatureState' || operation[0] ==='removeFeatureState') {
+ map.render(options, function () {
+ map[operation[0]].apply(map, operation.slice(1));
+ applyOperations(operations.slice(1), callback);
+ });
+
} else {
// Ensure that the next `map.render(options)` does not overwrite this change.
if (operation[0] === 'setCenter') {