summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrad Leege <bleege@gmail.com>2015-10-30 09:05:04 -0500
committerBrad Leege <bleege@gmail.com>2015-10-30 09:05:04 -0500
commit25c8eeecf9245cbabdc592c959a56a7c50451315 (patch)
tree0e8e8bdfc28c0504acf5adb83b5e2db2cbbafb57
parent90b1469a77b0161cc263138368a8b20726468b6c (diff)
parent6f7c53900d998baba5cabf91b3b333ccba7ef099 (diff)
downloadqtlocation-mapboxgl-25c8eeecf9245cbabdc592c959a56a7c50451315.tar.gz
Merge branch 'master' of github.com:mapbox/mapbox-gl-native
-rw-r--r--android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java8
-rw-r--r--android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/UserLocationView.java61
-rw-r--r--android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml12
-rw-r--r--android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/attribution_button_normal.png (renamed from android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/ic_info_blue_normal.png)bin2194 -> 2194 bytes
-rw-r--r--android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/attribution_button_pressed.png (renamed from android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/ic_info_blue_pressed.png)bin2133 -> 2133 bytes
-rwxr-xr-xandroid/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/my_location.png (renamed from android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/user_location.png)bin2783 -> 2783 bytes
-rwxr-xr-xandroid/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/my_location_bearing.png (renamed from android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/user_location_bearing.png)bin5939 -> 5939 bytes
-rwxr-xr-xandroid/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/my_location_stale.png (renamed from android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/user_location_stale.png)bin2593 -> 2593 bytes
-rw-r--r--android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/attribution_button_normal.png (renamed from android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/ic_info_blue_normal.png)bin1354 -> 1354 bytes
-rw-r--r--android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/attribution_button_pressed.png (renamed from android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/ic_info_blue_pressed.png)bin1391 -> 1391 bytes
-rwxr-xr-xandroid/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/my_location.png (renamed from android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/user_location.png)bin2089 -> 2089 bytes
-rwxr-xr-xandroid/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/my_location_bearing.png (renamed from android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/user_location_bearing.png)bin3599 -> 3599 bytes
-rwxr-xr-xandroid/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/my_location_stale.png (renamed from android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/user_location_stale.png)bin1942 -> 1942 bytes
-rw-r--r--android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/attribution_button_normal.png (renamed from android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/ic_info_blue_normal.png)bin2710 -> 2710 bytes
-rw-r--r--android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/attribution_button_pressed.png (renamed from android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/ic_info_blue_pressed.png)bin2738 -> 2738 bytes
-rwxr-xr-xandroid/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/my_location.png (renamed from android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/user_location.png)bin3520 -> 3520 bytes
-rwxr-xr-xandroid/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/my_location_bearing.png (renamed from android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/user_location_bearing.png)bin8155 -> 8155 bytes
-rwxr-xr-xandroid/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/my_location_stale.png (renamed from android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/user_location_stale.png)bin3287 -> 3287 bytes
-rw-r--r--android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/attribution_button_normal.png (renamed from android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/ic_info_blue_normal.png)bin4256 -> 4256 bytes
-rw-r--r--android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/attribution_button_pressed.png (renamed from android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/ic_info_blue_pressed.png)bin4240 -> 4240 bytes
-rwxr-xr-xandroid/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/my_location.png (renamed from android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/user_location.png)bin5057 -> 5057 bytes
-rwxr-xr-xandroid/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/my_location_bearing.png (renamed from android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/user_location_bearing.png)bin13246 -> 13246 bytes
-rwxr-xr-xandroid/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/my_location_stale.png (renamed from android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/user_location_stale.png)bin4676 -> 4676 bytes
-rw-r--r--android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/attribution_button_normal.png (renamed from android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/ic_info_blue_normal.png)bin730 -> 730 bytes
-rw-r--r--android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/attribution_button_pressed.png (renamed from android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/ic_info_blue_pressed.png)bin836 -> 836 bytes
-rwxr-xr-xandroid/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/my_location.png (renamed from android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/user_location.png)bin5236 -> 5236 bytes
-rwxr-xr-xandroid/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/my_location_bearing.png (renamed from android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/user_location_bearing.png)bin11688 -> 11688 bytes
-rwxr-xr-xandroid/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/my_location_stale.png (renamed from android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/user_location_stale.png)bin5053 -> 5053 bytes
-rw-r--r--android/MapboxGLAndroidSDK/src/main/res/drawable/attribution_button_selector.xml5
-rw-r--r--android/MapboxGLAndroidSDK/src/main/res/drawable/ic_info_selector.xml5
-rw-r--r--android/MapboxGLAndroidSDK/src/main/res/layout/mapview_internal.xml2
-rw-r--r--android/MapboxGLAndroidSDK/src/main/res/values/colors.xml1
-rw-r--r--platform/node/src/node_map.cpp75
-rw-r--r--src/mbgl/layer/background_layer.cpp9
-rw-r--r--src/mbgl/layer/background_layer.hpp5
-rw-r--r--src/mbgl/layer/circle_layer.cpp12
-rw-r--r--src/mbgl/layer/circle_layer.hpp5
-rw-r--r--src/mbgl/layer/fill_layer.cpp17
-rw-r--r--src/mbgl/layer/fill_layer.hpp5
-rw-r--r--src/mbgl/layer/line_layer.cpp30
-rw-r--r--src/mbgl/layer/line_layer.hpp5
-rw-r--r--src/mbgl/layer/raster_layer.cpp19
-rw-r--r--src/mbgl/layer/raster_layer.hpp5
-rw-r--r--src/mbgl/layer/symbol_layer.cpp71
-rw-r--r--src/mbgl/layer/symbol_layer.hpp5
-rw-r--r--src/mbgl/style/paint_properties_map.cpp12
-rw-r--r--src/mbgl/style/paint_properties_map.hpp8
-rw-r--r--src/mbgl/style/piecewisefunction_properties.hpp4
-rw-r--r--src/mbgl/style/property_parsing.cpp434
-rw-r--r--src/mbgl/style/property_parsing.hpp57
-rw-r--r--src/mbgl/style/style_layer.hpp11
-rw-r--r--src/mbgl/style/style_parser.cpp821
-rw-r--r--src/mbgl/style/style_parser.hpp78
-rw-r--r--test/fixtures/style_parser/circle-color.info.json2
-rw-r--r--test/fixtures/style_parser/line-translate.info.json2
-rw-r--r--test/storage/http_error.cpp2
56 files changed, 920 insertions, 868 deletions
diff --git a/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java b/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java
index 2b6a3071ec..13482c1ca2 100644
--- a/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java
+++ b/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/MapView.java
@@ -2306,7 +2306,13 @@ public final class MapView extends FrameLayout {
// Single finger double tap
// Zoom in
- zoom(true, e.getX(), e.getY());
+ if (mUserLocationView.getMyLocationTrackingMode() == MyLocationTracking.TRACKING_NONE) {
+ // Zoom in on gesture
+ zoom(true, e.getX(), e.getY());
+ } else {
+ // Zoom in on center map
+ zoom(true, getWidth() / 2, getHeight() / 2);
+ }
return true;
}
diff --git a/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/UserLocationView.java b/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/UserLocationView.java
index 349765bdd3..db5b320ba6 100644
--- a/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/UserLocationView.java
+++ b/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/views/UserLocationView.java
@@ -37,14 +37,10 @@ import com.mapzen.android.lost.api.LocationRequest;
import com.mapzen.android.lost.api.LocationServices;
import com.mapzen.android.lost.api.LostApiClient;
-import java.util.ArrayDeque;
-
final class UserLocationView extends View {
private MapView mMapView;
- private static final int BLUE_COLOR = 0x39ACCBFF;
-
private float mDensity;
private boolean mShowMarker;
@@ -137,6 +133,8 @@ final class UserLocationView extends View {
// Setup the custom paint
Resources resources = context.getResources();
+ int accuracyColor = resources.getColor(R.color.my_location_ring);
+
mDensity = resources.getDisplayMetrics().density;
mMarkerCoordinate = new LatLng(0.0, 0.0);
mMarkerScreenPoint = new PointF();
@@ -145,20 +143,20 @@ final class UserLocationView extends View {
mAccuracyPaintFill = new Paint();
mAccuracyPaintFill.setAntiAlias(true);
mAccuracyPaintFill.setStyle(Paint.Style.FILL);
- mAccuracyPaintFill.setColor(BLUE_COLOR);
+ mAccuracyPaintFill.setColor(accuracyColor);
mAccuracyPaintFill.setAlpha((int) (255 * 0.25f));
mAccuracyPaintStroke = new Paint();
mAccuracyPaintStroke.setAntiAlias(true);
mAccuracyPaintStroke.setStyle(Paint.Style.STROKE);
mAccuracyPaintStroke.setStrokeWidth(0.5f * mDensity);
- mAccuracyPaintStroke.setColor(BLUE_COLOR);
+ mAccuracyPaintStroke.setColor(accuracyColor);
mAccuracyPaintStroke.setAlpha((int) (255 * 0.5f));
mAccuracyPath = new Path();
mAccuracyBounds = new RectF();
- mUserLocationDrawable = ContextCompat.getDrawable(getContext(), R.drawable.user_location);
+ mUserLocationDrawable = ContextCompat.getDrawable(getContext(), R.drawable.my_location);
mUserLocationDrawableBounds = new Rect(
-mUserLocationDrawable.getIntrinsicWidth() / 2,
-mUserLocationDrawable.getIntrinsicHeight() / 2,
@@ -171,7 +169,7 @@ final class UserLocationView extends View {
mUserLocationDrawable.getIntrinsicHeight() / 2);
mUserLocationDrawable.setBounds(mUserLocationDrawableBounds);
- mUserLocationBearingDrawable = ContextCompat.getDrawable(getContext(), R.drawable.user_location_bearing);
+ mUserLocationBearingDrawable = ContextCompat.getDrawable(getContext(), R.drawable.my_location_bearing);
mUserLocationBearingDrawableBounds = new Rect(
-mUserLocationBearingDrawable.getIntrinsicWidth() / 2,
-mUserLocationBearingDrawable.getIntrinsicHeight() / 2,
@@ -184,7 +182,7 @@ final class UserLocationView extends View {
mUserLocationBearingDrawable.getIntrinsicHeight() / 2);
mUserLocationBearingDrawable.setBounds(mUserLocationBearingDrawableBounds);
- mUserLocationStaleDrawable = ContextCompat.getDrawable(getContext(), R.drawable.user_location_stale);
+ mUserLocationStaleDrawable = ContextCompat.getDrawable(getContext(), R.drawable.my_location_stale);
mUserLocationStaleDrawableBounds = new Rect(
-mUserLocationStaleDrawable.getIntrinsicWidth() / 2,
-mUserLocationStaleDrawable.getIntrinsicHeight() / 2,
@@ -382,8 +380,7 @@ final class UserLocationView extends View {
private GeomagneticField mGeomagneticField;
// Controls the sensor update rate in milliseconds
- private static final int UPDATE_RATE_MS = 500;
- private AngleLowPassFilter mLowPassFilter;
+ private static final int UPDATE_RATE_MS = 300;
// Compass data
private float mCompassBearing;
@@ -392,12 +389,11 @@ final class UserLocationView extends View {
public MyBearingListener(Context context) {
mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
mSensorRotationVector = mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
- mLowPassFilter = new AngleLowPassFilter();
}
public void onStart(Context context) {
mRotationDevice = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
- mSensorManager.registerListener(this, mSensorRotationVector, UPDATE_RATE_MS * 1000);
+ mSensorManager.registerListener(this, mSensorRotationVector, UPDATE_RATE_MS * 2500);
}
public void onStop() {
@@ -414,6 +410,11 @@ final class UserLocationView extends View {
return;
}
+ long currentTime = SystemClock.elapsedRealtime();
+ if (currentTime < mCompassUpdateNextTimestamp) {
+ return;
+ }
+
switch (event.sensor.getType()) {
case Sensor.TYPE_ROTATION_VECTOR:
SensorManager.getRotationMatrixFromVector(mRotationMatrix, event.values);
@@ -432,19 +433,13 @@ final class UserLocationView extends View {
break;
}
- mLowPassFilter.add(mOrientation[0]);
- long currentTime = System.currentTimeMillis();
- if (currentTime < mCompassUpdateNextTimestamp) {
- return;
- }
-
mCompassUpdateNextTimestamp = currentTime + UPDATE_RATE_MS;
mGeomagneticField = new GeomagneticField(
(float) mUserLocation.getLatitude(),
(float) mUserLocation.getLongitude(),
(float) mUserLocation.getAltitude(),
currentTime);
- mCompassBearing = (float) Math.toDegrees(mLowPassFilter.average()) + mGeomagneticField.getDeclination();
+ mCompassBearing = (float) Math.toDegrees(mOrientation[0] + mGeomagneticField.getDeclination());
setCompass(mCompassBearing);
}
@@ -452,32 +447,6 @@ final class UserLocationView extends View {
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO add accuracy to the equiation
}
-
- private class AngleLowPassFilter {
-
- private final int LENGTH = 5;
-
- private float sumSin, sumCos;
-
- private ArrayDeque<Float> queue = new ArrayDeque<>();
-
- public void add(float radians) {
- sumSin += (float) Math.sin(radians);
- sumCos += (float) Math.cos(radians);
- queue.add(radians);
-
- if (queue.size() > LENGTH) {
- float old = queue.poll();
- sumSin -= Math.sin(old);
- sumCos -= Math.cos(old);
- }
- }
-
- public float average() {
- int size = queue.size();
- return (float) Math.atan2(sumSin / size, sumCos / size);
- }
- }
}
diff --git a/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml b/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml
index 09dee3752a..66149ffcb6 100644
--- a/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml
+++ b/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml
@@ -40,4 +40,16 @@
<public name="attribution_margin_right" type="attr" />
<public name="attribution_margin_bottom" type="attr" />
<public name="attribution_visibility" type="attr" />
+
+ <public name="attribution_logo" type="drawable" />
+ <public name="compass" type="drawable" />
+ <public name="default_marker" type="drawable" />
+ <public name="attribution_button_pressed_selector" type="drawable" />
+ <public name="attribution_button_pressed_normal" type="drawable" />
+ <public name="attribution_button_pressed_pressed" type="drawable" />
+ <public name="my_location" type="drawable" />
+ <public name="my_location_bearing" type="drawable" />
+ <public name="my_location_stale" type="drawable" />
+ <public name="my_location_ring" type="color" />
+ <public name="mapbox_blue" type="color" />
</resources>
diff --git a/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/ic_info_blue_normal.png b/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/attribution_button_normal.png
index de44e3ddc0..de44e3ddc0 100644
--- a/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/ic_info_blue_normal.png
+++ b/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/attribution_button_normal.png
Binary files differ
diff --git a/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/ic_info_blue_pressed.png b/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/attribution_button_pressed.png
index fa26786242..fa26786242 100644
--- a/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/ic_info_blue_pressed.png
+++ b/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/attribution_button_pressed.png
Binary files differ
diff --git a/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/user_location.png b/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/my_location.png
index 1ae8d541af..1ae8d541af 100755
--- a/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/user_location.png
+++ b/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/my_location.png
Binary files differ
diff --git a/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/user_location_bearing.png b/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/my_location_bearing.png
index 8ecaffa2e8..8ecaffa2e8 100755
--- a/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/user_location_bearing.png
+++ b/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/my_location_bearing.png
Binary files differ
diff --git a/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/user_location_stale.png b/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/my_location_stale.png
index 0d599c01fa..0d599c01fa 100755
--- a/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/user_location_stale.png
+++ b/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/my_location_stale.png
Binary files differ
diff --git a/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/ic_info_blue_normal.png b/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/attribution_button_normal.png
index dd50478ac1..dd50478ac1 100644
--- a/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/ic_info_blue_normal.png
+++ b/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/attribution_button_normal.png
Binary files differ
diff --git a/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/ic_info_blue_pressed.png b/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/attribution_button_pressed.png
index d377f3cb8c..d377f3cb8c 100644
--- a/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/ic_info_blue_pressed.png
+++ b/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/attribution_button_pressed.png
Binary files differ
diff --git a/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/user_location.png b/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/my_location.png
index 542cd25e22..542cd25e22 100755
--- a/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/user_location.png
+++ b/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/my_location.png
Binary files differ
diff --git a/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/user_location_bearing.png b/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/my_location_bearing.png
index 429f03f648..429f03f648 100755
--- a/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/user_location_bearing.png
+++ b/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/my_location_bearing.png
Binary files differ
diff --git a/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/user_location_stale.png b/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/my_location_stale.png
index 6613c41153..6613c41153 100755
--- a/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/user_location_stale.png
+++ b/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/my_location_stale.png
Binary files differ
diff --git a/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/ic_info_blue_normal.png b/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/attribution_button_normal.png
index df7d7a8875..df7d7a8875 100644
--- a/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/ic_info_blue_normal.png
+++ b/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/attribution_button_normal.png
Binary files differ
diff --git a/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/ic_info_blue_pressed.png b/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/attribution_button_pressed.png
index f5b1833641..f5b1833641 100644
--- a/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/ic_info_blue_pressed.png
+++ b/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/attribution_button_pressed.png
Binary files differ
diff --git a/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/user_location.png b/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/my_location.png
index ca1f1fe630..ca1f1fe630 100755
--- a/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/user_location.png
+++ b/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/my_location.png
Binary files differ
diff --git a/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/user_location_bearing.png b/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/my_location_bearing.png
index 1b88f9f489..1b88f9f489 100755
--- a/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/user_location_bearing.png
+++ b/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/my_location_bearing.png
Binary files differ
diff --git a/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/user_location_stale.png b/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/my_location_stale.png
index 7af3789ff0..7af3789ff0 100755
--- a/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/user_location_stale.png
+++ b/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/my_location_stale.png
Binary files differ
diff --git a/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/ic_info_blue_normal.png b/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/attribution_button_normal.png
index 0a04d4eaad..0a04d4eaad 100644
--- a/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/ic_info_blue_normal.png
+++ b/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/attribution_button_normal.png
Binary files differ
diff --git a/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/ic_info_blue_pressed.png b/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/attribution_button_pressed.png
index faaef0625d..faaef0625d 100644
--- a/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/ic_info_blue_pressed.png
+++ b/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/attribution_button_pressed.png
Binary files differ
diff --git a/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/user_location.png b/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/my_location.png
index 6f175df168..6f175df168 100755
--- a/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/user_location.png
+++ b/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/my_location.png
Binary files differ
diff --git a/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/user_location_bearing.png b/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/my_location_bearing.png
index f4bb454a06..f4bb454a06 100755
--- a/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/user_location_bearing.png
+++ b/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/my_location_bearing.png
Binary files differ
diff --git a/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/user_location_stale.png b/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/my_location_stale.png
index f1d2f2eca0..f1d2f2eca0 100755
--- a/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/user_location_stale.png
+++ b/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/my_location_stale.png
Binary files differ
diff --git a/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/ic_info_blue_normal.png b/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/attribution_button_normal.png
index bcee96deaa..bcee96deaa 100644
--- a/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/ic_info_blue_normal.png
+++ b/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/attribution_button_normal.png
Binary files differ
diff --git a/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/ic_info_blue_pressed.png b/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/attribution_button_pressed.png
index 781263f760..781263f760 100644
--- a/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/ic_info_blue_pressed.png
+++ b/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/attribution_button_pressed.png
Binary files differ
diff --git a/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/user_location.png b/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/my_location.png
index d43541ac3c..d43541ac3c 100755
--- a/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/user_location.png
+++ b/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/my_location.png
Binary files differ
diff --git a/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/user_location_bearing.png b/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/my_location_bearing.png
index a8cccbb3e2..a8cccbb3e2 100755
--- a/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/user_location_bearing.png
+++ b/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/my_location_bearing.png
Binary files differ
diff --git a/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/user_location_stale.png b/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/my_location_stale.png
index 33e952391f..33e952391f 100755
--- a/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/user_location_stale.png
+++ b/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/my_location_stale.png
Binary files differ
diff --git a/android/MapboxGLAndroidSDK/src/main/res/drawable/attribution_button_selector.xml b/android/MapboxGLAndroidSDK/src/main/res/drawable/attribution_button_selector.xml
new file mode 100644
index 0000000000..b5fedb0fd0
--- /dev/null
+++ b/android/MapboxGLAndroidSDK/src/main/res/drawable/attribution_button_selector.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/attribution_button_pressed" android:state_pressed="true" />
+ <item android:drawable="@drawable/attribution_button_normal" />
+</selector> \ No newline at end of file
diff --git a/android/MapboxGLAndroidSDK/src/main/res/drawable/ic_info_selector.xml b/android/MapboxGLAndroidSDK/src/main/res/drawable/ic_info_selector.xml
deleted file mode 100644
index 9f550f66d5..0000000000
--- a/android/MapboxGLAndroidSDK/src/main/res/drawable/ic_info_selector.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:drawable="@drawable/ic_info_blue_pressed" android:state_pressed="true" />
- <item android:drawable="@drawable/ic_info_blue_normal" />
-</selector> \ No newline at end of file
diff --git a/android/MapboxGLAndroidSDK/src/main/res/layout/mapview_internal.xml b/android/MapboxGLAndroidSDK/src/main/res/layout/mapview_internal.xml
index c4eaecc079..92cd2315f4 100644
--- a/android/MapboxGLAndroidSDK/src/main/res/layout/mapview_internal.xml
+++ b/android/MapboxGLAndroidSDK/src/main/res/layout/mapview_internal.xml
@@ -26,7 +26,7 @@
android:clickable="true"
android:contentDescription="@string/attributionsIconContentDescription"
android:padding="7dp"
- android:src="@drawable/ic_info_selector" />
+ android:src="@drawable/attribution_button_selector" />
<com.mapbox.mapboxsdk.views.UserLocationView
android:id="@+id/userLocationView"
diff --git a/android/MapboxGLAndroidSDK/src/main/res/values/colors.xml b/android/MapboxGLAndroidSDK/src/main/res/values/colors.xml
index bb1c326a89..55cf3fb1b6 100644
--- a/android/MapboxGLAndroidSDK/src/main/res/values/colors.xml
+++ b/android/MapboxGLAndroidSDK/src/main/res/values/colors.xml
@@ -3,4 +3,5 @@
<color name="white">#FFFFFF</color>
<color name="black">#000000</color>
<color name="mapbox_blue">#1E8CAB</color>
+ <color name="my_location_ring">@color/mapbox_blue</color>
</resources>
diff --git a/platform/node/src/node_map.cpp b/platform/node/src/node_map.cpp
index 76e14e3b94..e36f9bc222 100644
--- a/platform/node/src/node_map.cpp
+++ b/platform/node/src/node_map.cpp
@@ -56,6 +56,45 @@ NAN_MODULE_INIT(NodeMap::Init) {
sharedDisplay();
}
+/**
+ * A request object, given to the `request` handler of a map, is an
+ * encapsulation of a URL and type of a resource that the map asks you to load.
+ *
+ * The `kind` property is one of
+ *
+ * "Unknown": 0,
+ * "Style": 1,
+ * "Source": 2,
+ * "Tile": 3,
+ * "Glyphs": 4,
+ * "SpriteImage": 5,
+ * "SpriteJSON": 6
+ *
+ * @typedef
+ * @name Request
+ * @property {string} url
+ * @property {number} kind
+ */
+
+/**
+ * Mapbox GL object: this object loads stylesheets and renders them into
+ * images.
+ *
+ * @class
+ * @name Map
+ * @param {Object} options
+ * @param {Function} options.request a method used to request resources
+ * over the internet
+ * @param {Function} [options.cancel]
+ * @param {number} options.ratio pixel ratio
+ * @example
+ * var map = new mbgl.Map({ request: function() {} });
+ * map.load(require('./test/fixtures/style.json'));
+ * map.render({}, function(err, image) {
+ * if (err) throw err;
+ * fs.writeFileSync('image.png', image);
+ * });
+ */
NAN_METHOD(NodeMap::New) {
if (!info.IsConstructCall()) {
return Nan::ThrowTypeError("Use the new operator to create new Map objects");
@@ -103,6 +142,21 @@ const std::string StringifyStyle(v8::Local<v8::Value> styleHandle) {
return *Nan::Utf8String(Nan::MakeCallback(JSON, "stringify", 1, &styleHandle));
}
+/**
+ * Load a stylesheet
+ *
+ * @function
+ * @name load
+ * @param {string|Object} stylesheet either an object or a JSON representation
+ * @returns {undefined} loads stylesheet into map
+ * @throws {Error} if stylesheet is missing or invalid
+ * @example
+ * // providing an object
+ * map.load(require('./test/fixtures/style.json'));
+ *
+ * // providing a string
+ * map.load(fs.readFileSync('./test/fixtures/style.json', 'utf8'));
+ */
NAN_METHOD(NodeMap::Load) {
auto nodeMap = Nan::ObjectWrap::Unwrap<NodeMap>(info.Holder());
@@ -176,6 +230,22 @@ std::unique_ptr<NodeMap::RenderOptions> NodeMap::ParseOptions(v8::Local<v8::Obje
return options;
}
+/**
+ * Render an image from the currently-loaded style
+ *
+ * @name render
+ * @param {Object} options
+ * @param {number} [options.zoom=0]
+ * @param {number} [options.width=512]
+ * @param {number} [options.height=512]
+ * @param {Array<number>} [options.center=[0,0]] latitude, longitude center
+ * of the map
+ * @param {number} [options.bearing=0] rotation
+ * @param {Array<string>} [options.classes=[]] GL Style Classes
+ * @param {Function} callback
+ * @returns {undefined} calls callback
+ * @throws {Error} if stylesheet is not loaded or if map is already rendering
+ */
NAN_METHOD(NodeMap::Render) {
auto nodeMap = Nan::ObjectWrap::Unwrap<NodeMap>(info.Holder());
@@ -302,6 +372,11 @@ void NodeMap::renderFinished() {
}
}
+/**
+ * Clean up any resources used by a map instance.options
+ * @name release
+ * @returns {undefined}
+ */
NAN_METHOD(NodeMap::Release) {
auto nodeMap = Nan::ObjectWrap::Unwrap<NodeMap>(info.Holder());
diff --git a/src/mbgl/layer/background_layer.cpp b/src/mbgl/layer/background_layer.cpp
index 31e524bc81..70c6488ce1 100644
--- a/src/mbgl/layer/background_layer.cpp
+++ b/src/mbgl/layer/background_layer.cpp
@@ -1,7 +1,16 @@
#include <mbgl/layer/background_layer.hpp>
+#include <mbgl/style/property_parsing.hpp>
namespace mbgl {
+void BackgroundLayer::parsePaints(const JSVal& layer) {
+ paints.parseEach(layer, [&] (ClassProperties& paint, const JSVal& value) {
+ parseProperty<Function<float>>("background-opacity", PropertyKey::BackgroundOpacity, paint, value);
+ parseProperty<Function<Color>>("background-color", PropertyKey::BackgroundColor, paint, value);
+ parseProperty<PiecewiseConstantFunction<Faded<std::string>>>("background-pattern", PropertyKey::BackgroundImage, paint, value, "background-pattern-transition");
+ });
+}
+
void BackgroundLayer::recalculate(const StyleCalculationParameters& parameters) {
paints.removeExpiredTransitions(parameters.now);
diff --git a/src/mbgl/layer/background_layer.hpp b/src/mbgl/layer/background_layer.hpp
index 8fe689ee66..86dfd24a4b 100644
--- a/src/mbgl/layer/background_layer.hpp
+++ b/src/mbgl/layer/background_layer.hpp
@@ -3,11 +3,16 @@
#include <mbgl/style/style_layer.hpp>
#include <mbgl/style/style_properties.hpp>
+#include <mbgl/style/paint_properties_map.hpp>
+#include <mbgl/style/class_properties.hpp>
namespace mbgl {
class BackgroundLayer : public StyleLayer {
public:
+ void parseLayout(const JSVal&) override {};
+ void parsePaints(const JSVal&) override;
+
void recalculate(const StyleCalculationParameters&) override;
BackgroundPaintProperties properties;
diff --git a/src/mbgl/layer/circle_layer.cpp b/src/mbgl/layer/circle_layer.cpp
index 0f16b02d3c..e3fa4b4dee 100644
--- a/src/mbgl/layer/circle_layer.cpp
+++ b/src/mbgl/layer/circle_layer.cpp
@@ -1,7 +1,19 @@
#include <mbgl/layer/circle_layer.hpp>
+#include <mbgl/style/property_parsing.hpp>
namespace mbgl {
+void CircleLayer::parsePaints(const JSVal& layer) {
+ paints.parseEach(layer, [&] (ClassProperties& paint, const JSVal& value) {
+ parseProperty<Function<float>>("circle-radius", PropertyKey::CircleRadius, paint, value);
+ parseProperty<Function<Color>>("circle-color", PropertyKey::CircleColor, paint, value);
+ parseProperty<Function<float>>("circle-opacity", PropertyKey::CircleOpacity, paint, value);
+ parseProperty<Function<std::array<float,2>>>("circle-translate", PropertyKey::CircleTranslate, paint, value);
+ parseProperty<Function<TranslateAnchorType>>("circle-translate-anchor", PropertyKey::CircleTranslateAnchor, paint, value);
+ parseProperty<Function<float>>("circle-blur", PropertyKey::CircleBlur, paint, value);
+ });
+}
+
void CircleLayer::recalculate(const StyleCalculationParameters& parameters) {
paints.removeExpiredTransitions(parameters.now);
diff --git a/src/mbgl/layer/circle_layer.hpp b/src/mbgl/layer/circle_layer.hpp
index ae1f68198d..957d6b9cae 100644
--- a/src/mbgl/layer/circle_layer.hpp
+++ b/src/mbgl/layer/circle_layer.hpp
@@ -3,11 +3,16 @@
#include <mbgl/style/style_layer.hpp>
#include <mbgl/style/style_properties.hpp>
+#include <mbgl/style/paint_properties_map.hpp>
+#include <mbgl/style/class_properties.hpp>
namespace mbgl {
class CircleLayer : public StyleLayer {
public:
+ void parseLayout(const JSVal&) override {};
+ void parsePaints(const JSVal&) override;
+
void recalculate(const StyleCalculationParameters&) override;
CirclePaintProperties properties;
diff --git a/src/mbgl/layer/fill_layer.cpp b/src/mbgl/layer/fill_layer.cpp
index ba3001efa6..53bf0ac89c 100644
--- a/src/mbgl/layer/fill_layer.cpp
+++ b/src/mbgl/layer/fill_layer.cpp
@@ -1,7 +1,24 @@
#include <mbgl/layer/fill_layer.hpp>
+#include <mbgl/style/property_parsing.hpp>
namespace mbgl {
+void FillLayer::parsePaints(const JSVal& layer) {
+ paints.parseEach(layer, [&] (ClassProperties& paint, const JSVal& value) {
+ parseProperty<Function<bool>>("fill-antialias", PropertyKey::FillAntialias, paint, value);
+ parseProperty<Function<float>>("fill-opacity", PropertyKey::FillOpacity, paint, value);
+ parseProperty<PropertyTransition>("fill-opacity-transition", PropertyKey::FillOpacity, paint, value);
+ parseProperty<Function<Color>>("fill-color", PropertyKey::FillColor, paint, value);
+ parseProperty<PropertyTransition>("fill-color-transition", PropertyKey::FillColor, paint, value);
+ parseProperty<Function<Color>>("fill-outline-color", PropertyKey::FillOutlineColor, paint, value);
+ parseProperty<PropertyTransition>("fill-outline-color-transition", PropertyKey::FillOutlineColor, paint, value);
+ parseProperty<Function<std::array<float, 2>>>("fill-translate", PropertyKey::FillTranslate, paint, value);
+ parseProperty<PropertyTransition>("fill-translate-transition", PropertyKey::FillTranslate, paint, value);
+ parseProperty<Function<TranslateAnchorType>>("fill-translate-anchor", PropertyKey::FillTranslateAnchor, paint, value);
+ parseProperty<PiecewiseConstantFunction<Faded<std::string>>>("fill-pattern", PropertyKey::FillImage, paint, value, "fill-pattern-transition");
+ });
+}
+
void FillLayer::recalculate(const StyleCalculationParameters& parameters) {
paints.removeExpiredTransitions(parameters.now);
diff --git a/src/mbgl/layer/fill_layer.hpp b/src/mbgl/layer/fill_layer.hpp
index 59ccaf36c6..7a5d468bb3 100644
--- a/src/mbgl/layer/fill_layer.hpp
+++ b/src/mbgl/layer/fill_layer.hpp
@@ -3,11 +3,16 @@
#include <mbgl/style/style_layer.hpp>
#include <mbgl/style/style_properties.hpp>
+#include <mbgl/style/paint_properties_map.hpp>
+#include <mbgl/style/class_properties.hpp>
namespace mbgl {
class FillLayer : public StyleLayer {
public:
+ void parseLayout(const JSVal&) override {};
+ void parsePaints(const JSVal&) override;
+
void recalculate(const StyleCalculationParameters&) override;
FillPaintProperties properties;
diff --git a/src/mbgl/layer/line_layer.cpp b/src/mbgl/layer/line_layer.cpp
index 4556741029..fe660638a8 100644
--- a/src/mbgl/layer/line_layer.cpp
+++ b/src/mbgl/layer/line_layer.cpp
@@ -1,7 +1,37 @@
#include <mbgl/layer/line_layer.hpp>
+#include <mbgl/style/style_bucket.hpp>
+#include <mbgl/style/property_parsing.hpp>
+#include <mbgl/map/tile_id.hpp>
namespace mbgl {
+void LineLayer::parseLayout(const JSVal& value) {
+ parseProperty<Function<CapType>>("line-cap", PropertyKey::LineCap, bucket->layout, value);
+ parseProperty<Function<JoinType>>("line-join", PropertyKey::LineJoin, bucket->layout, value);
+ parseProperty<Function<float>>("line-miter-limit", PropertyKey::LineMiterLimit, bucket->layout, value);
+ parseProperty<Function<float>>("line-round-limit", PropertyKey::LineRoundLimit, bucket->layout, value);
+}
+
+void LineLayer::parsePaints(const JSVal& layer) {
+ paints.parseEach(layer, [&] (ClassProperties& paint, const JSVal& value) {
+ parseProperty<Function<float>>("line-opacity", PropertyKey::LineOpacity, paint, value);
+ parseProperty<PropertyTransition>("line-opacity-transition", PropertyKey::LineOpacity, paint, value);
+ parseProperty<Function<Color>>("line-color", PropertyKey::LineColor, paint, value);
+ parseProperty<PropertyTransition>("line-color-transition", PropertyKey::LineColor, paint, value);
+ parseProperty<Function<std::array<float,2>>>("line-translate", PropertyKey::LineTranslate, paint, value);
+ parseProperty<PropertyTransition>("line-translate-transition", PropertyKey::LineTranslate, paint, value);
+ parseProperty<Function<TranslateAnchorType>>("line-translate-anchor", PropertyKey::LineTranslateAnchor, paint, value);
+ parseProperty<Function<float>>("line-width", PropertyKey::LineWidth, paint, value);
+ parseProperty<PropertyTransition>("line-width-transition", PropertyKey::LineWidth, paint, value);
+ parseProperty<Function<float>>("line-gap-width", PropertyKey::LineGapWidth, paint, value);
+ parseProperty<PropertyTransition>("line-gap-width-transition", PropertyKey::LineGapWidth, paint, value);
+ parseProperty<Function<float>>("line-blur", PropertyKey::LineBlur, paint, value);
+ parseProperty<PropertyTransition>("line-blur-transition", PropertyKey::LineBlur, paint, value);
+ parseProperty<PiecewiseConstantFunction<Faded<std::vector<float>>>>("line-dasharray", PropertyKey::LineDashArray, paint, value, "line-dasharray-transition");
+ parseProperty<PiecewiseConstantFunction<Faded<std::string>>>("line-pattern", PropertyKey::LineImage, paint, value, "line-pattern-transition");
+ });
+}
+
void LineLayer::recalculate(const StyleCalculationParameters& parameters) {
paints.removeExpiredTransitions(parameters.now);
diff --git a/src/mbgl/layer/line_layer.hpp b/src/mbgl/layer/line_layer.hpp
index d9cf73521b..5f8c0f2b3a 100644
--- a/src/mbgl/layer/line_layer.hpp
+++ b/src/mbgl/layer/line_layer.hpp
@@ -3,11 +3,16 @@
#include <mbgl/style/style_layer.hpp>
#include <mbgl/style/style_properties.hpp>
+#include <mbgl/style/paint_properties_map.hpp>
+#include <mbgl/style/class_properties.hpp>
namespace mbgl {
class LineLayer : public StyleLayer {
public:
+ void parseLayout(const JSVal&) override;
+ void parsePaints(const JSVal&) override;
+
void recalculate(const StyleCalculationParameters&) override;
LinePaintProperties properties;
diff --git a/src/mbgl/layer/raster_layer.cpp b/src/mbgl/layer/raster_layer.cpp
index b217f9d356..3f210233ac 100644
--- a/src/mbgl/layer/raster_layer.cpp
+++ b/src/mbgl/layer/raster_layer.cpp
@@ -1,7 +1,26 @@
#include <mbgl/layer/raster_layer.hpp>
+#include <mbgl/style/property_parsing.hpp>
namespace mbgl {
+void RasterLayer::parsePaints(const JSVal& layer) {
+ paints.parseEach(layer, [&] (ClassProperties& paint, const JSVal& value) {
+ parseProperty<Function<float>>("raster-opacity", PropertyKey::RasterOpacity, paint, value);
+ parseProperty<PropertyTransition>("raster-opacity-transition", PropertyKey::RasterOpacity, paint, value);
+ parseProperty<Function<float>>("raster-hue-rotate", PropertyKey::RasterHueRotate, paint, value);
+ parseProperty<PropertyTransition>("raster-hue-rotate-transition", PropertyKey::RasterHueRotate, paint, value);
+ parseProperty<Function<float>>("raster-brightness-min", PropertyKey::RasterBrightnessLow, paint, value);
+ parseProperty<Function<float>>("raster-brightness-max", PropertyKey::RasterBrightnessHigh, paint, value);
+ parseProperty<PropertyTransition>("raster-brightness-transition", PropertyKey::RasterBrightness, paint, value);
+ parseProperty<Function<float>>("raster-saturation", PropertyKey::RasterSaturation, paint, value);
+ parseProperty<PropertyTransition>("raster-saturation-transition", PropertyKey::RasterSaturation, paint, value);
+ parseProperty<Function<float>>("raster-contrast", PropertyKey::RasterContrast, paint, value);
+ parseProperty<PropertyTransition>("raster-contrast-transition", PropertyKey::RasterContrast, paint, value);
+ parseProperty<Function<float>>("raster-fade-duration", PropertyKey::RasterFade, paint, value);
+ parseProperty<PropertyTransition>("raster-fade-duration-transition", PropertyKey::RasterFade, paint, value);
+ });
+}
+
void RasterLayer::recalculate(const StyleCalculationParameters& parameters) {
paints.removeExpiredTransitions(parameters.now);
diff --git a/src/mbgl/layer/raster_layer.hpp b/src/mbgl/layer/raster_layer.hpp
index ba34dc60c0..6a0de8a38c 100644
--- a/src/mbgl/layer/raster_layer.hpp
+++ b/src/mbgl/layer/raster_layer.hpp
@@ -3,11 +3,16 @@
#include <mbgl/style/style_layer.hpp>
#include <mbgl/style/style_properties.hpp>
+#include <mbgl/style/paint_properties_map.hpp>
+#include <mbgl/style/class_properties.hpp>
namespace mbgl {
class RasterLayer : public StyleLayer {
public:
+ void parseLayout(const JSVal&) override {};
+ void parsePaints(const JSVal&) override;
+
void recalculate(const StyleCalculationParameters&) override;
RasterPaintProperties properties;
diff --git a/src/mbgl/layer/symbol_layer.cpp b/src/mbgl/layer/symbol_layer.cpp
index 940c518430..983b1f3700 100644
--- a/src/mbgl/layer/symbol_layer.cpp
+++ b/src/mbgl/layer/symbol_layer.cpp
@@ -1,9 +1,80 @@
#include <mbgl/layer/symbol_layer.hpp>
#include <mbgl/style/style_bucket.hpp>
#include <mbgl/style/property_evaluator.hpp>
+#include <mbgl/style/property_parsing.hpp>
namespace mbgl {
+void SymbolLayer::parseLayout(const JSVal& value) {
+ parseProperty<Function<PlacementType>>("symbol-placement", PropertyKey::SymbolPlacement, bucket->layout, value);
+ parseProperty<Function<float>>("symbol-spacing", PropertyKey::SymbolSpacing, bucket->layout, value);
+ parseProperty<Function<bool>>("symbol-avoid-edges", PropertyKey::SymbolAvoidEdges, bucket->layout, value);
+ parseProperty<Function<bool>>("icon-allow-overlap", PropertyKey::IconAllowOverlap, bucket->layout, value);
+ parseProperty<Function<bool>>("icon-ignore-placement", PropertyKey::IconIgnorePlacement, bucket->layout, value);
+ parseProperty<Function<bool>>("icon-optional", PropertyKey::IconOptional, bucket->layout, value);
+ parseProperty<Function<RotationAlignmentType>>("icon-rotation-alignment", PropertyKey::IconRotationAlignment, bucket->layout, value);
+ parseProperty<Function<float>>("icon-size", PropertyKey::IconSize, bucket->layout, value);
+ parseProperty<Function<std::string>>("icon-image", PropertyKey::IconImage, bucket->layout, value);
+ parseProperty<Function<float>>("icon-rotate", PropertyKey::IconRotate, bucket->layout, value);
+ parseProperty<Function<float>>("icon-padding", PropertyKey::IconPadding, bucket->layout, value);
+ parseProperty<Function<bool>>("icon-keep-upright", PropertyKey::IconKeepUpright, bucket->layout, value);
+ parseProperty<Function<std::array<float, 2>>>("icon-offset", PropertyKey::IconOffset, bucket->layout, value);
+ parseProperty<Function<RotationAlignmentType>>("text-rotation-alignment", PropertyKey::TextRotationAlignment, bucket->layout, value);
+ parseProperty<Function<std::string>>("text-field", PropertyKey::TextField, bucket->layout, value);
+ parseProperty<Function<std::string>>("text-font", PropertyKey::TextFont, bucket->layout, value);
+ parseProperty<Function<float>>("text-size", PropertyKey::TextSize, bucket->layout, value);
+ parseProperty<Function<float>>("text-max-width", PropertyKey::TextMaxWidth, bucket->layout, value);
+ parseProperty<Function<float>>("text-line-height", PropertyKey::TextLineHeight, bucket->layout, value);
+ parseProperty<Function<float>>("text-letter-spacing", PropertyKey::TextLetterSpacing, bucket->layout, value);
+ parseProperty<Function<TextJustifyType>>("text-justify", PropertyKey::TextJustify, bucket->layout, value);
+ parseProperty<Function<TextAnchorType>>("text-anchor", PropertyKey::TextAnchor, bucket->layout, value);
+ parseProperty<Function<float>>("text-max-angle", PropertyKey::TextMaxAngle, bucket->layout, value);
+ parseProperty<Function<float>>("text-rotate", PropertyKey::TextRotate, bucket->layout, value);
+ parseProperty<Function<float>>("text-padding", PropertyKey::TextPadding, bucket->layout, value);
+ parseProperty<Function<bool>>("text-keep-upright", PropertyKey::TextKeepUpright, bucket->layout, value);
+ parseProperty<Function<TextTransformType>>("text-transform", PropertyKey::TextTransform, bucket->layout, value);
+ parseProperty<Function<std::array<float, 2>>>("text-offset", PropertyKey::TextOffset, bucket->layout, value);
+ parseProperty<Function<bool>>("text-allow-overlap", PropertyKey::TextAllowOverlap, bucket->layout, value);
+ parseProperty<Function<bool>>("text-ignore-placement", PropertyKey::TextIgnorePlacement, bucket->layout, value);
+ parseProperty<Function<bool>>("text-optional", PropertyKey::TextOptional, bucket->layout, value);
+}
+
+void SymbolLayer::parsePaints(const JSVal& layer) {
+ paints.parseEach(layer, [&] (ClassProperties& paint, const JSVal& value) {
+ parseProperty<Function<float>>("icon-opacity", PropertyKey::IconOpacity, paint, value);
+ parseProperty<PropertyTransition>("icon-opacity-transition", PropertyKey::IconOpacity, paint, value);
+ parseProperty<Function<float>>("icon-size", PropertyKey::IconSize, paint, value);
+ parseProperty<PropertyTransition>("icon-size-transition", PropertyKey::IconSize, paint, value);
+ parseProperty<Function<Color>>("icon-color", PropertyKey::IconColor, paint, value);
+ parseProperty<PropertyTransition>("icon-color-transition", PropertyKey::IconColor, paint, value);
+ parseProperty<Function<Color>>("icon-halo-color", PropertyKey::IconHaloColor, paint, value);
+ parseProperty<PropertyTransition>("icon-halo-color-transition", PropertyKey::IconHaloColor, paint, value);
+ parseProperty<Function<float>>("icon-halo-width", PropertyKey::IconHaloWidth, paint, value);
+ parseProperty<PropertyTransition>("icon-halo-width-transition", PropertyKey::IconHaloWidth, paint, value);
+ parseProperty<Function<float>>("icon-halo-blur", PropertyKey::IconHaloBlur, paint, value);
+ parseProperty<PropertyTransition>("icon-halo-blur-transition", PropertyKey::IconHaloBlur, paint, value);
+ parseProperty<Function<std::array<float, 2>>>("icon-translate", PropertyKey::IconTranslate, paint, value);
+ parseProperty<PropertyTransition>("icon-translate-transition", PropertyKey::IconTranslate, paint, value);
+ parseProperty<Function<TranslateAnchorType>>("icon-translate-anchor", PropertyKey::IconTranslateAnchor, paint, value);
+
+ parseProperty<Function<float>>("text-opacity", PropertyKey::TextOpacity, paint, value);
+ parseProperty<PropertyTransition>("text-opacity-transition", PropertyKey::TextOpacity, paint, value);
+ parseProperty<Function<float>>("text-size", PropertyKey::TextSize, paint, value);
+ parseProperty<PropertyTransition>("text-size-transition", PropertyKey::TextSize, paint, value);
+ parseProperty<Function<Color>>("text-color", PropertyKey::TextColor, paint, value);
+ parseProperty<PropertyTransition>("text-color-transition", PropertyKey::TextColor, paint, value);
+ parseProperty<Function<Color>>("text-halo-color", PropertyKey::TextHaloColor, paint, value);
+ parseProperty<PropertyTransition>("text-halo-color-transition", PropertyKey::TextHaloColor, paint, value);
+ parseProperty<Function<float>>("text-halo-width", PropertyKey::TextHaloWidth, paint, value);
+ parseProperty<PropertyTransition>("text-halo-width-transition", PropertyKey::TextHaloWidth, paint, value);
+ parseProperty<Function<float>>("text-halo-blur", PropertyKey::TextHaloBlur, paint, value);
+ parseProperty<PropertyTransition>("text-halo-blur-transition", PropertyKey::TextHaloBlur, paint, value);
+ parseProperty<Function<std::array<float, 2>>>("text-translate", PropertyKey::TextTranslate, paint, value);
+ parseProperty<PropertyTransition>("text-translate-transition", PropertyKey::TextTranslate, paint, value);
+ parseProperty<Function<TranslateAnchorType>>("text-translate-anchor", PropertyKey::TextTranslateAnchor, paint, value);
+ });
+}
+
void SymbolLayer::recalculate(const StyleCalculationParameters& parameters) {
paints.removeExpiredTransitions(parameters.now);
diff --git a/src/mbgl/layer/symbol_layer.hpp b/src/mbgl/layer/symbol_layer.hpp
index 52aed14a14..ce92c19594 100644
--- a/src/mbgl/layer/symbol_layer.hpp
+++ b/src/mbgl/layer/symbol_layer.hpp
@@ -3,11 +3,16 @@
#include <mbgl/style/style_layer.hpp>
#include <mbgl/style/style_properties.hpp>
+#include <mbgl/style/paint_properties_map.hpp>
+#include <mbgl/style/class_properties.hpp>
namespace mbgl {
class SymbolLayer : public StyleLayer {
public:
+ void parseLayout(const JSVal&) override;
+ void parsePaints(const JSVal&) override;
+
void recalculate(const StyleCalculationParameters&) override;
SymbolPaintProperties properties;
diff --git a/src/mbgl/style/paint_properties_map.cpp b/src/mbgl/style/paint_properties_map.cpp
index 18f6867457..44513908c1 100644
--- a/src/mbgl/style/paint_properties_map.cpp
+++ b/src/mbgl/style/paint_properties_map.cpp
@@ -5,6 +5,18 @@
namespace mbgl {
+void PaintPropertiesMap::parseEach(const JSVal& layer, std::function<void (ClassProperties &, const JSVal &)> parsePaint) {
+ rapidjson::Value::ConstMemberIterator itr = layer.MemberBegin();
+ for (; itr != layer.MemberEnd(); ++itr) {
+ const std::string name { itr->name.GetString(), itr->name.GetStringLength() };
+ if (name == "paint") {
+ parsePaint(paints[ClassID::Default], itr->value);
+ } else if (name.compare(0, 6, "paint.") == 0 && name.length() > 6) {
+ parsePaint(paints[ClassDictionary::Get().lookup(name.substr(6))], itr->value);
+ }
+ }
+}
+
void PaintPropertiesMap::cascade(const std::vector<std::string>& classes,
const TimePoint& now,
const PropertyTransition& defaultTransition) {
diff --git a/src/mbgl/style/paint_properties_map.hpp b/src/mbgl/style/paint_properties_map.hpp
index 14ed33fe4d..26fd8301ba 100644
--- a/src/mbgl/style/paint_properties_map.hpp
+++ b/src/mbgl/style/paint_properties_map.hpp
@@ -8,14 +8,19 @@
#include <mbgl/util/interpolate.hpp>
+#include <rapidjson/document.h>
+
#include <map>
#include <set>
+#include <functional>
namespace mbgl {
class ClassProperties;
class PropertyTransition;
+using JSVal = rapidjson::Value;
+
class PaintPropertiesMap {
public:
void cascade(const std::vector<std::string>& classNames,
@@ -25,6 +30,9 @@ public:
bool hasTransitions() const;
void removeExpiredTransitions(const TimePoint& now);
+ // Call the function for each "paint" or "paint.*" object in the layer.
+ void parseEach(const JSVal& layer, std::function<void (ClassProperties&, const JSVal&)>);
+
template <typename T>
void calculate(PropertyKey key, T& target, const StyleCalculationParameters& parameters) {
auto it = appliedStyle.find(key);
diff --git a/src/mbgl/style/piecewisefunction_properties.hpp b/src/mbgl/style/piecewisefunction_properties.hpp
index d3a9543952..491442958d 100644
--- a/src/mbgl/style/piecewisefunction_properties.hpp
+++ b/src/mbgl/style/piecewisefunction_properties.hpp
@@ -18,9 +18,9 @@ struct PiecewiseConstantFunction {
duration(duration_) {
}
- PiecewiseConstantFunction(T& value, mapbox::util::optional<Duration> duration_)
+ PiecewiseConstantFunction(const T& value)
: values({{ 0, value }}),
- duration(duration_) {
+ duration() {
}
T evaluate(const StyleCalculationParameters&) const;
diff --git a/src/mbgl/style/property_parsing.cpp b/src/mbgl/style/property_parsing.cpp
new file mode 100644
index 0000000000..ba69ed8685
--- /dev/null
+++ b/src/mbgl/style/property_parsing.cpp
@@ -0,0 +1,434 @@
+#include <mbgl/style/property_parsing.hpp>
+
+#include <mbgl/platform/log.hpp>
+
+#include <csscolorparser/csscolorparser.hpp>
+
+namespace mbgl {
+namespace detail {
+
+optional<std::vector<float>> parseFloatArray(const JSVal& value) {
+ if (!value.IsArray()) {
+ Log::Warning(Event::ParseStyle, "dasharray value must be an array of numbers");
+ return {};
+ }
+
+ std::vector<float> result;
+
+ for (rapidjson::SizeType i = 0; i < value.Size(); ++i) {
+ const JSVal& part = value[i];
+
+ if (!part.IsNumber()) {
+ Log::Warning(Event::ParseStyle, "dasharray value must be an array of numbers");
+ return {};
+ }
+
+ result.push_back(part.GetDouble());
+ }
+
+ return result;
+}
+
+
+template <>
+optional<bool> parseProperty(const char* name, const JSVal& value) {
+ if (!value.IsBool()) {
+ Log::Warning(Event::ParseStyle, "value of '%s' must be a boolean", name);
+ return {};
+ }
+
+ return value.GetBool();
+}
+
+template <>
+optional<float> parseProperty(const char* name, const JSVal& value) {
+ if (!value.IsNumber()) {
+ Log::Warning(Event::ParseStyle, "value of '%s' must be a number, or a number function", name);
+ return {};
+ }
+
+ return value.GetDouble();
+}
+
+template <>
+optional<std::string> parseProperty(const char* name, const JSVal& value) {
+ if (std::string { "text-font" } == name) {
+ if (!value.IsArray()) {
+ Log::Warning(Event::ParseStyle, "value of '%s' must be an array of strings", name);
+ return {};
+ }
+
+ std::string result = "";
+ for (rapidjson::SizeType i = 0; i < value.Size(); ++i) {
+ const JSVal& stop = value[i];
+ if (stop.IsString()) {
+ result += stop.GetString();
+ if (i < value.Size()-1) {
+ result += ",";
+ }
+ } else {
+ Log::Warning(Event::ParseStyle, "text-font members must be strings");
+ return {};
+ }
+ }
+ return result;
+ }
+
+ if (!value.IsString()) {
+ Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name);
+ return {};
+ }
+
+ return std::string { value.GetString(), value.GetStringLength() };
+}
+
+template <>
+optional<Color> parseProperty(const char* name, const JSVal& value) {
+ if (!value.IsString()) {
+ Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name);
+ return {};
+ }
+
+ CSSColorParser::Color css_color = CSSColorParser::parse({ value.GetString(), value.GetStringLength() });
+
+ // Premultiply the color.
+ const float factor = css_color.a / 255;
+
+ return Color{{(float)css_color.r * factor,
+ (float)css_color.g * factor,
+ (float)css_color.b * factor,
+ css_color.a}};
+}
+
+template <>
+optional<TranslateAnchorType> parseProperty(const char* name, const JSVal& value) {
+ if (!value.IsString()) {
+ Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name);
+ return {};
+ }
+
+ return { TranslateAnchorTypeClass({ value.GetString(), value.GetStringLength() }) };
+}
+
+template <>
+optional<RotateAnchorType> parseProperty<RotateAnchorType>(const char* name, const JSVal& value) {
+ if (!value.IsString()) {
+ Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name);
+ return {};
+ }
+
+ return { RotateAnchorTypeClass({ value.GetString(), value.GetStringLength() }) };
+}
+
+template <>
+optional<CapType> parseProperty<CapType>(const char* name, const JSVal& value) {
+ if (!value.IsString()) {
+ Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name);
+ return {};
+ }
+
+ return { CapTypeClass({ value.GetString(), value.GetStringLength() }) };
+}
+
+template <>
+optional<JoinType> parseProperty<JoinType>(const char* name, const JSVal& value) {
+ if (!value.IsString()) {
+ Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name);
+ return {};
+ }
+
+ return { JoinTypeClass({ value.GetString(), value.GetStringLength() }) };
+}
+
+template <>
+optional<PlacementType> parseProperty<PlacementType>(const char* name, const JSVal& value) {
+ if (!value.IsString()) {
+ Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name);
+ return {};
+ }
+
+ return { PlacementTypeClass({ value.GetString(), value.GetStringLength() }) };
+}
+
+template <>
+optional<TextAnchorType> parseProperty<TextAnchorType>(const char* name, const JSVal& value) {
+ if (!value.IsString()) {
+ Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name);
+ return {};
+ }
+
+ return { TextAnchorTypeClass({ value.GetString(), value.GetStringLength() }) };
+}
+
+template <>
+optional<TextJustifyType> parseProperty<TextJustifyType>(const char* name, const JSVal& value) {
+ if (!value.IsString()) {
+ Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name);
+ return {};
+ }
+
+ return { TextJustifyTypeClass({ value.GetString(), value.GetStringLength() }) };
+}
+
+template <>
+optional<TextTransformType> parseProperty<TextTransformType>(const char* name, const JSVal& value) {
+ if (!value.IsString()) {
+ Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name);
+ return {};
+ }
+
+ return { TextTransformTypeClass({ value.GetString(), value.GetStringLength() }) };
+}
+
+template <>
+optional<RotationAlignmentType> parseProperty<RotationAlignmentType>(const char* name, const JSVal& value) {
+ if (!value.IsString()) {
+ Log::Warning(Event::ParseStyle, "value of '%s' must be a string", name);
+ return {};
+ }
+
+ return { RotationAlignmentTypeClass({ value.GetString(), value.GetStringLength() }) };
+}
+
+template <>
+optional<std::array<float, 2>> parseProperty(const char* name, const JSVal& value) {
+ if (value.IsArray() && value.Size() == 2 &&
+ value[rapidjson::SizeType(0)].IsNumber() &&
+ value[rapidjson::SizeType(1)].IsNumber()) {
+
+ float first = value[rapidjson::SizeType(0)].GetDouble();
+ float second = value[rapidjson::SizeType(1)].GetDouble();
+ return { {{ first, second }} };
+ } else {
+ Log::Warning(Event::ParseStyle, "value of '%s' must be an array of two numbers", name);
+ return {};
+ }
+}
+
+template <>
+optional<PropertyTransition> parseProperty(const char *, const JSVal& value) {
+ PropertyTransition transition;
+ if (value.IsObject()) {
+ bool parsed = false;
+ if (value.HasMember("duration") && value["duration"].IsNumber()) {
+ transition.duration = std::chrono::milliseconds(value["duration"].GetUint());
+ parsed = true;
+ }
+ if (value.HasMember("delay") && value["delay"].IsNumber()) {
+ transition.delay = std::chrono::milliseconds(value["delay"].GetUint());
+ parsed = true;
+ }
+ if (!parsed) {
+ return {};
+ }
+ }
+ return transition;
+}
+
+// --- Function ---
+
+template <typename T>
+optional<std::vector<std::pair<float, T>>> parseStops(const char* name, const JSVal& value) {
+ if (!value.IsArray()) {
+ Log::Warning(Event::ParseStyle, "stops function must specify a stops array");
+ return {};
+ }
+
+ std::vector<std::pair<float, T>> stops;
+
+ for (rapidjson::SizeType i = 0; i < value.Size(); ++i) {
+ const JSVal& stop = value[i];
+
+ if (!stop.IsArray()) {
+ Log::Warning(Event::ParseStyle, "function argument must be a numeric value");
+ return {};
+ }
+
+ if (stop.Size() != 2) {
+ Log::Warning(Event::ParseStyle, "stop must have zoom level and value specification");
+ return {};
+ }
+
+ const JSVal& z = stop[rapidjson::SizeType(0)];
+ if (!z.IsNumber()) {
+ Log::Warning(Event::ParseStyle, "zoom level in stop must be a number");
+ return {};
+ }
+
+ optional<T> v = parseProperty<T>(name, stop[rapidjson::SizeType(1)]);
+ if (!v) {
+ return {};
+ }
+
+ stops.emplace_back(z.GetDouble(), *v);
+ }
+
+ return stops;
+}
+
+template <typename T>
+optional<Function<T>> parseFunction(const char* name, const JSVal& value) {
+ if (!value.IsObject()) {
+ auto constant = parseProperty<T>(name, value);
+ if (!constant) {
+ return {};
+ }
+ return { ConstantFunction<T>(*constant) };
+ }
+
+ if (!value.HasMember("stops")) {
+ Log::Warning(Event::ParseStyle, "function must specify a function type");
+ return {};
+ }
+
+ float base = 1.0f;
+
+ if (value.HasMember("base")) {
+ const JSVal& value_base = value["base"];
+
+ if (!value_base.IsNumber()) {
+ Log::Warning(Event::ParseStyle, "base must be numeric");
+ return {};
+ }
+
+ base = value_base.GetDouble();
+ }
+
+ auto stops = parseStops<T>(name, value["stops"]);
+
+ if (!stops) {
+ return {};
+ }
+
+ return { StopsFunction<T>(*stops, base) };
+}
+
+template <> optional<Function<std::array<float, 2>>> parseProperty(const char* name, const JSVal& value) {
+ return parseFunction<std::array<float, 2>>(name, value);
+}
+
+template <> optional<Function<std::string>> parseProperty(const char* name, const JSVal& value) {
+ return parseFunction<std::string>(name, value);
+}
+
+template <> optional<Function<TranslateAnchorType>> parseProperty(const char* name, const JSVal& value) {
+ return parseFunction<TranslateAnchorType>(name, value);
+}
+
+template <> optional<Function<RotateAnchorType>> parseProperty(const char* name, const JSVal& value) {
+ return parseFunction<RotateAnchorType>(name, value);
+}
+
+template <> optional<Function<CapType>> parseProperty(const char* name, const JSVal& value) {
+ return parseFunction<CapType>(name, value);
+}
+
+template <> optional<Function<JoinType>> parseProperty(const char* name, const JSVal& value) {
+ return parseFunction<JoinType>(name, value);
+}
+
+template <> optional<Function<PlacementType>> parseProperty(const char* name, const JSVal& value) {
+ return parseFunction<PlacementType>(name, value);
+}
+
+template <> optional<Function<TextAnchorType>> parseProperty(const char* name, const JSVal& value) {
+ return parseFunction<TextAnchorType>(name, value);
+}
+
+template <> optional<Function<TextJustifyType>> parseProperty(const char* name, const JSVal& value) {
+ return parseFunction<TextJustifyType>(name, value);
+}
+
+template <> optional<Function<TextTransformType>> parseProperty(const char* name, const JSVal& value) {
+ return parseFunction<TextTransformType>(name, value);
+}
+
+template <> optional<Function<RotationAlignmentType>> parseProperty(const char* name, const JSVal& value) {
+ return parseFunction<RotationAlignmentType>(name, value);
+}
+
+template <> optional<Function<bool>> parseProperty(const char* name, const JSVal& value) {
+ return parseFunction<bool>(name, value);
+}
+
+template<> optional<Function<float>> parseProperty(const char* name, const JSVal& value) {
+ return parseFunction<float>(name, value);
+}
+
+template<> optional<Function<Color>> parseProperty(const char* name, const JSVal& value) {
+ return parseFunction<Color>(name, value);
+}
+
+template <typename T>
+optional<PiecewiseConstantFunction<T>> parsePiecewiseConstantFunction(const JSVal& value, const JSVal& transition) {
+ mapbox::util::optional<Duration> duration;
+ if (transition.HasMember("duration")) {
+ duration = std::chrono::milliseconds(transition["duration"].GetUint());
+ }
+
+ if (!value.HasMember("stops")) {
+ Log::Warning(Event::ParseStyle, "function must specify a function type");
+ return {};
+ }
+
+ auto stops = parseStops<T>("", value["stops"]);
+
+ if (!stops) {
+ return {};
+ }
+
+ return PiecewiseConstantFunction<T>(*stops, duration);
+}
+
+template <>
+optional<Faded<std::vector<float>>> parseProperty(const char*, const JSVal& value) {
+ auto floatarray = parseFloatArray(value);
+ if (!floatarray) {
+ return {};
+ }
+
+ Faded<std::vector<float>> parsed;
+ parsed.to = *floatarray;
+ return parsed;
+}
+
+template <>
+optional<Faded<std::string>> parseProperty(const char* name, const JSVal& value) {
+ if (!value.IsString()) {
+ Log::Warning(Event::ParseStyle, "value of '%s' must be a string, or a string function", name);
+ return {};
+ }
+
+ Faded<std::string> parsed;
+ parsed.to = { value.GetString(), value.GetStringLength() };
+ return parsed;
+}
+
+template <>
+optional<PiecewiseConstantFunction<Faded<std::vector<float>>>> parseProperty(const char* name, const JSVal& value, const JSVal& transition) {
+ if (value.IsObject()) {
+ return parsePiecewiseConstantFunction<Faded<std::vector<float>>>(value, transition);
+ }
+
+ auto constant = parseProperty<Faded<std::vector<float>>>(name, value);
+ if (!constant) {
+ return {};
+ }
+ return PiecewiseConstantFunction<Faded<std::vector<float>>>(*constant);
+}
+
+template <>
+optional<PiecewiseConstantFunction<Faded<std::string>>> parseProperty(const char* name, const JSVal& value, const JSVal& transition) {
+ if (value.IsObject()) {
+ return parsePiecewiseConstantFunction<Faded<std::string>>(value, transition);
+ }
+
+ auto constant = parseProperty<Faded<std::string>>(name, value);
+ if (!constant) {
+ return {};
+ }
+ return PiecewiseConstantFunction<Faded<std::string>>(*constant);
+}
+
+}
+}
diff --git a/src/mbgl/style/property_parsing.hpp b/src/mbgl/style/property_parsing.hpp
new file mode 100644
index 0000000000..478e192898
--- /dev/null
+++ b/src/mbgl/style/property_parsing.hpp
@@ -0,0 +1,57 @@
+#ifndef MBGL_PROPERTY_PARSING
+#define MBGL_PROPERTY_PARSING
+
+#include <mbgl/style/class_properties.hpp>
+
+#include <mapbox/optional.hpp>
+#include <rapidjson/document.h>
+
+namespace mbgl {
+
+using JSVal = rapidjson::Value;
+
+template <typename T>
+using optional = mapbox::util::optional<T>;
+
+namespace detail {
+
+template <typename T>
+optional<T> parseProperty(const char* name, const JSVal&);
+
+template <typename T>
+optional<T> parseProperty(const char* name, const JSVal&, const JSVal& transition);
+
+}
+
+template <typename T>
+void parseProperty(const char* name, PropertyKey key, ClassProperties& properties, const JSVal& value) {
+ if (!value.HasMember(name))
+ return;
+
+ const optional<T> res = detail::parseProperty<T>(name, value[name]);
+
+ if (res) {
+ properties.set(key, *res);
+ }
+}
+
+template <typename T>
+void parseProperty(const char* name, PropertyKey key, ClassProperties& properties, const JSVal& value, const char* transitionName) {
+ if (!value.HasMember(name))
+ return;
+
+ const JSVal& noTransition = JSVal { rapidjson::kObjectType };
+
+ const optional<T> res = detail::parseProperty<T>(name, value[name],
+ value.HasMember(transitionName)
+ ? value[transitionName]
+ : noTransition);
+
+ if (res) {
+ properties.set(key, *res);
+ }
+}
+
+}
+
+#endif
diff --git a/src/mbgl/style/style_layer.hpp b/src/mbgl/style/style_layer.hpp
index 43d595bb38..a27e8a89cf 100644
--- a/src/mbgl/style/style_layer.hpp
+++ b/src/mbgl/style/style_layer.hpp
@@ -1,8 +1,7 @@
#ifndef MBGL_STYLE_STYLE_LAYER
#define MBGL_STYLE_STYLE_LAYER
-#include <mbgl/style/class_dictionary.hpp>
-#include <mbgl/style/class_properties.hpp>
+#include <mbgl/style/types.hpp>
#include <mbgl/style/paint_properties_map.hpp>
#include <mbgl/renderer/render_pass.hpp>
@@ -11,9 +10,10 @@
#include <mbgl/util/chrono.hpp>
#include <mbgl/util/ptr.hpp>
+#include <rapidjson/document.h>
+
#include <vector>
#include <string>
-#include <map>
namespace mbgl {
@@ -21,12 +21,17 @@ class StyleBucket;
class StyleCalculationParameters;
class PropertyTransition;
+using JSVal = rapidjson::Value;
+
class StyleLayer : public util::noncopyable {
public:
static std::unique_ptr<StyleLayer> create(StyleLayerType);
virtual ~StyleLayer() = default;
+ virtual void parseLayout(const JSVal& value) = 0;
+ virtual void parsePaints(const JSVal& value) = 0;
+
// Partially evaluate paint properties based on a set of classes.
void cascade(const std::vector<std::string>& classNames,
const TimePoint& now,
diff --git a/src/mbgl/style/style_parser.cpp b/src/mbgl/style/style_parser.cpp
index 3aecfa51eb..c7b6827474 100644
--- a/src/mbgl/style/style_parser.cpp
+++ b/src/mbgl/style/style_parser.cpp
@@ -1,26 +1,13 @@
#include <mbgl/style/style_parser.hpp>
-#include <mbgl/map/source.hpp>
#include <mbgl/style/style_layer.hpp>
-#include <mbgl/util/constants.hpp>
-#include <mbgl/util/vec.hpp>
-#include <mbgl/util/uv_detail.hpp>
-#include <mbgl/platform/log.hpp>
-#include <csscolorparser/csscolorparser.hpp>
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wshadow"
-#pragma GCC diagnostic ignored "-Wunknown-pragmas"
-#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
-#include <boost/algorithm/string.hpp>
-#pragma GCC diagnostic pop
+#include <mbgl/platform/log.hpp>
#include <algorithm>
namespace mbgl {
-using JSVal = const rapidjson::Value&;
-
-void StyleParser::parse(JSVal document) {
+void StyleParser::parse(const JSVal& document) {
if (document.HasMember("version")) {
version = document["version"].GetInt();
if (version != 8) {
@@ -45,583 +32,70 @@ void StyleParser::parse(JSVal document) {
}
}
-#pragma mark - Parse Render Properties
-
-template<> StyleParser::Status StyleParser::parseRenderProperty(JSVal value, bool &target, const char *name) {
- if (value.HasMember(name)) {
- JSVal property = value[name];
- if (property.IsBool()) {
- target = property.GetBool();
- return StyleParserSuccess;
- } else {
- Log::Warning(Event::ParseStyle, "'%s' must be a boolean", name);
- }
- }
- return StyleParserFailure;
-}
-
-
-template<> StyleParser::Status StyleParser::parseRenderProperty(JSVal value, std::string &target, const char *name) {
- if (value.HasMember(name)) {
- JSVal property = value[name];
- if (property.IsString()) {
- target = { property.GetString(), property.GetStringLength() };
- return StyleParserSuccess;
- } else {
- Log::Warning(Event::ParseStyle, "'%s' must be a string", name);
- }
- }
- return StyleParserFailure;
-}
-
-template<> StyleParser::Status StyleParser::parseRenderProperty(JSVal value, float &target, const char *name) {
- if (value.HasMember(name)) {
- JSVal property = value[name];
- if (property.IsNumber()) {
- target = property.GetDouble();
- return StyleParserSuccess;
- } else {
- Log::Warning(Event::ParseStyle, "'%s' must be a number", name);
- }
- }
- return StyleParserFailure;
-}
-
-template<> StyleParser::Status StyleParser::parseRenderProperty(JSVal value, uint16_t &target, const char *name) {
- if (value.HasMember(name)) {
- JSVal property = value[name];
- if (property.IsUint()) {
- unsigned int int_value = property.GetUint();
- if (int_value > std::numeric_limits<uint16_t>::max()) {
- Log::Warning(Event::ParseStyle, "values for %s that are larger than %d are not supported", name, std::numeric_limits<uint16_t>::max());
- return StyleParserFailure;
- }
-
- target = int_value;
- return StyleParserSuccess;
- } else {
- Log::Warning(Event::ParseStyle, "%s must be an unsigned integer", name);
- }
- }
- return StyleParserFailure;
-}
-
-template<> StyleParser::Status StyleParser::parseRenderProperty(JSVal value, int32_t &target, const char *name) {
- if (value.HasMember(name)) {
- JSVal property = value[name];
- if (property.IsInt()) {
- target = property.GetInt();
- return StyleParserSuccess;
- } else {
- Log::Warning(Event::ParseStyle, "%s must be an integer", name);
- }
- }
- return StyleParserFailure;
-}
-
-template<> StyleParser::Status StyleParser::parseRenderProperty(JSVal value, vec2<float> &target, const char *name) {
- if (value.HasMember(name)) {
- JSVal property = value[name];
- if (property.IsArray()) {
- if (property.Size() >= 2) {
- target.x = property[(rapidjson::SizeType)0].GetDouble();
- target.y = property[(rapidjson::SizeType)1].GetDouble();
- return StyleParserSuccess;
- } else {
- Log::Warning(Event::ParseStyle, "%s must have at least two members", name);
- }
- } else {
- Log::Warning(Event::ParseStyle, "%s must be an array of numbers", name);
- }
- }
- return StyleParserFailure;
-}
-
-template<typename Parser, typename T>
-StyleParser::Status StyleParser::parseRenderProperty(JSVal value, T &target, const char *name) {
- if (value.HasMember(name)) {
- JSVal property = value[name];
- if (property.IsString()) {
- target = Parser({ property.GetString(), property.GetStringLength() });
- return StyleParserSuccess;
- } else {
- Log::Warning(Event::ParseStyle, "%s must have one of the enum values", name);
- }
- }
- return StyleParserFailure;
-}
-
-
-#pragma mark - Parse Sources
-
-void StyleParser::parseSources(JSVal value) {
- if (value.IsObject()) {
- rapidjson::Value::ConstMemberIterator itr = value.MemberBegin();
- for (; itr != value.MemberEnd(); ++itr) {
- std::string name { itr->name.GetString(), itr->name.GetStringLength() };
- std::unique_ptr<Source> source = std::make_unique<Source>();
- parseRenderProperty<SourceTypeClass>(itr->value, source->info.type, "type");
- parseRenderProperty(itr->value, source->info.url, "url");
- parseRenderProperty(itr->value, source->info.tile_size, "tileSize");
- source->info.source_id = name;
- source->info.parseTileJSONProperties(itr->value);
- sourcesMap.emplace(name, source.get());
- sources.emplace_back(std::move(source));
- }
- } else {
+void StyleParser::parseSources(const JSVal& value) {
+ if (!value.IsObject()) {
Log::Warning(Event::ParseStyle, "sources must be an object");
+ return;
}
-}
-
-#pragma mark - Parse Style Properties
-
-Color parseColor(JSVal value) {
- if (!value.IsString()) {
- Log::Warning(Event::ParseStyle, "color value must be a string");
- return Color{{ 0, 0, 0, 0 }};
- }
-
- CSSColorParser::Color css_color = CSSColorParser::parse({ value.GetString(), value.GetStringLength() });
- // Premultiply the color.
- const float factor = css_color.a / 255;
+ rapidjson::Value::ConstMemberIterator itr = value.MemberBegin();
+ for (; itr != value.MemberEnd(); ++itr) {
+ const JSVal& nameVal = itr->name;
+ const JSVal& sourceVal = itr->value;
- return Color{{(float)css_color.r * factor,
- (float)css_color.g * factor,
- (float)css_color.b * factor,
- css_color.a}};
-}
+ std::unique_ptr<Source> source = std::make_unique<Source>();
-StyleParser::Result<std::vector<float>> StyleParser::parseFloatArray(JSVal value) {
- if (!value.IsArray()) {
- Log::Warning(Event::ParseStyle, "dasharray value must be an array of numbers");
- return Result<std::vector<float>> { StyleParserFailure, std::vector<float>() };
- }
+ source->info.source_id = { nameVal.GetString(), nameVal.GetStringLength() };
- std::vector<float> vec;
- for (rapidjson::SizeType i = 0; i < value.Size(); ++i) {
- JSVal part = value[i];
- if (!part.IsNumber()) {
- Log::Warning(Event::ParseStyle, "dasharray value must be an array of numbers");
- return Result<std::vector<float>> { StyleParserFailure, std::vector<float>() };
+ if (!sourceVal.HasMember("type")) {
+ Log::Warning(Event::ParseStyle, "source must have a type");
+ continue;
}
- vec.push_back(part.GetDouble());
- }
- return Result<std::vector<float>> { StyleParserSuccess, vec };
-}
-
-template <>
-StyleParser::Result<std::array<float, 2>> StyleParser::parseProperty(JSVal value, const char*) {
- if (value.IsArray() && value.Size() == 2 &&
- value[rapidjson::SizeType(0)].IsNumber() &&
- value[rapidjson::SizeType(1)].IsNumber()) {
- float first = value[rapidjson::SizeType(0)].GetDouble();
- float second = value[rapidjson::SizeType(1)].GetDouble();
- return Result<std::array<float, 2>> { StyleParserSuccess, {{ first, second }} };
- } else {
- Log::Warning(Event::ParseStyle, "value must be array of two numbers");
- return Result<std::array<float, 2>> { StyleParserFailure, {{ 0.0f, 0.0f }} };
- }
-}
-
-template <>
-StyleParser::Result<float> StyleParser::parseProperty(JSVal value, const char* property_name) {
- if (value.IsNumber()) {
- return Result<float> { StyleParserSuccess, value.GetDouble() };
- } else {
- Log::Warning(Event::ParseStyle, "value of '%s' must be a number, or a number function", property_name);
- return Result<float> { StyleParserFailure, 0.0f };
- }
-}
-
-template <>
-StyleParser::Result<Color> StyleParser::parseProperty(JSVal value, const char*) {
- return Result<Color> { StyleParserSuccess, parseColor(value) };
-}
-
-template <>
-StyleParser::Result<Faded<std::vector<float>>> StyleParser::parseProperty(JSVal value, const char*) {
- Faded<std::vector<float>> parsed;
- parsed.to = std::get<1>(parseFloatArray(value));
- return Result<Faded<std::vector<float>>> { StyleParserSuccess, parsed };
-}
-
-template <>
-StyleParser::Result<Faded<std::string>> StyleParser::parseProperty(JSVal value, const char *property_name) {
- Faded<std::string> parsed;
- if (value.IsString()) {
- parsed.to = { value.GetString(), value.GetStringLength() };
- return Result<Faded<std::string>> { StyleParserSuccess, parsed };
- } else {
- Log::Warning(Event::ParseStyle, "value of '%s' must be a string, or a string function", property_name);
- return Result<Faded<std::string>> { StyleParserFailure, parsed };
- }
-}
-
-template <typename T>
-StyleParser::Result<std::vector<std::pair<float, T>>> StyleParser::parseStops(JSVal value_stops, const char *property_name) {
-
- if (!value_stops.IsArray()) {
- Log::Warning(Event::ParseStyle, "stops function must specify a stops array");
- return Result<std::vector<std::pair<float, T>>> { StyleParserFailure, {}};
- }
-
- std::vector<std::pair<float, T>> stops;
-
- for (rapidjson::SizeType i = 0; i < value_stops.Size(); ++i) {
- JSVal stop = value_stops[i];
- if (stop.IsArray()) {
- if (stop.Size() != 2) {
- Log::Warning(Event::ParseStyle, "stop must have zoom level and value specification");
- return Result<std::vector<std::pair<float, T>>> { StyleParserFailure, {}};
- }
-
- JSVal z = stop[rapidjson::SizeType(0)];
- if (!z.IsNumber()) {
- Log::Warning(Event::ParseStyle, "zoom level in stop must be a number");
- return Result<std::vector<std::pair<float, T>>> { StyleParserFailure, {}};
- }
-
- stops.emplace_back(z.GetDouble(), std::get<1>(parseProperty<T>(stop[rapidjson::SizeType(1)], property_name)));
- } else {
- Log::Warning(Event::ParseStyle, "function argument must be a numeric value");
- return Result<std::vector<std::pair<float, T>>> { StyleParserFailure, {}};
+ const JSVal& typeVal = sourceVal["type"];
+ if (!typeVal.IsString()) {
+ Log::Warning(Event::ParseStyle, "source type must have one of the enum values");
+ continue;
}
- }
- return Result<std::vector<std::pair<float, T>>>(StyleParserSuccess, stops);
-}
-template <typename T>
-StyleParser::Result<Function<T>> StyleParser::parseFunction(JSVal value, const char *property_name) {
- if (!value.IsObject()) {
- return parseProperty<T>(value, property_name);
- }
+ source->info.type = SourceTypeClass({ typeVal.GetString(), typeVal.GetStringLength() });
- if (!value.HasMember("stops")) {
- Log::Warning(Event::ParseStyle, "function must specify a function type");
- return Result<Function<T>> { StyleParserFailure, ConstantFunction<T>(T()) };
- }
+ if (sourceVal.HasMember("url")) {
+ const JSVal& urlVal = sourceVal["url"];
- float base = 1.0f;
+ if (!urlVal.IsString()) {
+ Log::Warning(Event::ParseStyle, "source url must be a string");
+ continue;
+ }
- if (value.HasMember("base")) {
- JSVal value_base = value["base"];
- if (value_base.IsNumber()) {
- base = value_base.GetDouble();
- } else {
- Log::Warning(Event::ParseStyle, "base must be numeric");
+ source->info.url = { urlVal.GetString(), urlVal.GetStringLength() };
}
- }
-
- auto stops = parseStops<T>(value["stops"], property_name);
-
- if (!std::get<0>(stops)) {
- return Result<Function<T>> { StyleParserFailure, ConstantFunction<T>(T()) };
- }
-
- return Result<Function<T>> { StyleParserSuccess, StopsFunction<T>(std::get<1>(stops), base) };
-}
-
-template <typename T>
-StyleParser::Result<PiecewiseConstantFunction<T>> StyleParser::parsePiecewiseConstantFunction(JSVal value, JSVal transition) {
- mapbox::util::optional<Duration> duration;
- if (transition.HasMember("duration")) {
- duration = std::chrono::milliseconds(transition["duration"].GetUint());
- }
-
- if (!value.HasMember("stops")) {
- Log::Warning(Event::ParseStyle, "function must specify a function type");
- return Result<PiecewiseConstantFunction<T>> { StyleParserFailure, { {}, duration } };
- }
-
- auto stops = parseStops<T>(value["stops"], "");
-
- if (!std::get<0>(stops)) {
- return Result<PiecewiseConstantFunction<T>> { StyleParserFailure, { {}, duration } };
- }
-
- return Result<PiecewiseConstantFunction<T>> { StyleParserSuccess, { std::get<1>(stops), duration } };
-}
-
-template <typename T>
-StyleParser::Status StyleParser::setProperty(JSVal value, const char *property_name, PropertyKey key, ClassProperties &klass) {
- auto res = parseProperty<T>(value, property_name);
- if (std::get<0>(res)) {
- klass.set(key, std::get<1>(res));
- }
- return std::get<0>(res);
-}
-
-template <typename T>
-StyleParser::Status StyleParser::setProperty(JSVal value, const char *property_name, PropertyKey key, ClassProperties &klass, JSVal transition) {
- auto res = parseProperty<T>(value, property_name, transition);
- if (std::get<0>(res)) {
- klass.set(key, std::get<1>(res));
- }
- return std::get<0>(res);
-}
-
-template<typename T>
-void StyleParser::parseVisibility(StyleBucket &bucket, JSVal value) {
- if (!value.HasMember("visibility")) {
- return;
- } else if (!value["visibility"].IsString()) {
- Log::Warning(Event::ParseStyle, "value of 'visibility' must be a string");
- bucket.visibility = VisibilityType::Visible;
- return;
- }
- bucket.visibility = VisibilityTypeClass({ value["visibility"].GetString(), value["visibility"].GetStringLength() });
-}
-template<typename T>
-StyleParser::Status StyleParser::parseOptionalProperty(const char *property_name, PropertyKey key, ClassProperties &klass, JSVal value) {
- if (!value.HasMember(property_name)) {
- return StyleParserFailure;
- } else {
- return setProperty<T>(value[property_name], property_name, key, klass);
- }
-}
+ if (sourceVal.HasMember("tileSize")) {
+ const JSVal& tileSizeVal = sourceVal["tileSize"];
-template<typename T>
-StyleParser::Status StyleParser::parseOptionalProperty(const char *property_name, PropertyKey key, ClassProperties &klass, JSVal value, const char *transition_name) {
- if (!value.HasMember(property_name)) {
- return StyleParserFailure;
- } else {
- if (value.HasMember(transition_name)) {
- return setProperty<T>(value[property_name], property_name, key, klass, value[transition_name]);
- } else {
- JSVal val = JSVal { rapidjson::kObjectType };
- return setProperty<T>(value[property_name], property_name, key, klass, val);
- }
- }
-}
-
-template<> StyleParser::Result<std::string> StyleParser::parseProperty(JSVal value, const char *property_name) {
- if (std::string { "text-font" } == property_name) {
- if (!value.IsArray()) {
- Log::Warning(Event::ParseStyle, "value of '%s' must be an array of strings", property_name);
- return Result<std::string> { StyleParserFailure, std::string() };
- } else {
- std::string result = "";
- for (rapidjson::SizeType i = 0; i < value.Size(); ++i) {
- JSVal stop = value[i];
- if (stop.IsString()) {
- result += stop.GetString();
- if (i < value.Size()-1) {
- result += ",";
- }
- } else {
- Log::Warning(Event::ParseStyle, "text-font members must be strings");
- return Result<std::string> { StyleParserFailure, {} };
- }
+ if (!tileSizeVal.IsUint()) {
+ Log::Warning(Event::ParseStyle, "source tileSize must be an unsigned integer");
+ continue;
}
- return Result<std::string> { StyleParserSuccess, result };
- }
- } else if (!value.IsString()) {
- Log::Warning(Event::ParseStyle, "value of '%s' must be a string", property_name);
- return Result<std::string> { StyleParserFailure, std::string() };
- } else {
- return Result<std::string> { StyleParserSuccess, { value.GetString(), value.GetStringLength() } };
- }
-}
-
-template<> StyleParser::Result<bool> StyleParser::parseProperty(JSVal value, const char *property_name) {
- if (!value.IsBool()) {
- Log::Warning(Event::ParseStyle, "value of '%s' must be a boolean", property_name);
- return Result<bool> { StyleParserFailure, StyleParserSuccess };
- }
-
- return Result<bool> { StyleParserSuccess, value.GetBool() };
-}
-
-template<> StyleParser::Result<TranslateAnchorType> StyleParser::parseProperty(JSVal value, const char *property_name) {
- if (!value.IsString()) {
- Log::Warning(Event::ParseStyle, "value of '%s' must be a string", property_name);
- return Result<TranslateAnchorType> { StyleParserFailure, TranslateAnchorType::Map };
- }
-
- return Result<TranslateAnchorType> { StyleParserSuccess, TranslateAnchorTypeClass({ value.GetString(), value.GetStringLength() }) };
-}
-
-template<> StyleParser::Result<RotateAnchorType> StyleParser::parseProperty<RotateAnchorType>(JSVal value, const char *property_name) {
- if (!value.IsString()) {
- Log::Warning(Event::ParseStyle, "value of '%s' must be a string", property_name);
- return Result<RotateAnchorType> { StyleParserFailure, RotateAnchorType::Map };
- }
-
- return Result<RotateAnchorType> { StyleParserSuccess, RotateAnchorTypeClass({ value.GetString(), value.GetStringLength() }) };
-}
-
-template<> StyleParser::Result<CapType> StyleParser::parseProperty<CapType>(JSVal value, const char *property_name) {
- if (!value.IsString()) {
- Log::Warning(Event::ParseStyle, "value of '%s' must be a string", property_name);
- return Result<CapType> { StyleParserFailure, CapType::Butt };
- }
-
- return Result<CapType> { StyleParserSuccess, CapTypeClass({ value.GetString(), value.GetStringLength() }) };
-}
-
-template<> StyleParser::Result<JoinType> StyleParser::parseProperty<JoinType>(JSVal value, const char *property_name) {
- if (!value.IsString()) {
- Log::Warning(Event::ParseStyle, "value of '%s' must be a string", property_name);
- return Result<JoinType> { StyleParserFailure, JoinType::Miter };
- }
-
- return Result<JoinType> { StyleParserSuccess, JoinTypeClass({ value.GetString(), value.GetStringLength() }) };
-}
-
-template<> StyleParser::Result<PlacementType> StyleParser::parseProperty<PlacementType>(JSVal value, const char *property_name) {
- if (!value.IsString()) {
- Log::Warning(Event::ParseStyle, "value of '%s' must be a string", property_name);
- return Result<PlacementType> { StyleParserFailure, PlacementType::Point };
- }
-
- return Result<PlacementType> { StyleParserSuccess, PlacementTypeClass({ value.GetString(), value.GetStringLength() }) };
-}
-
-template<> StyleParser::Result<TextAnchorType> StyleParser::parseProperty<TextAnchorType>(JSVal value, const char *property_name) {
- if (!value.IsString()) {
- Log::Warning(Event::ParseStyle, "value of '%s' must be a string", property_name);
- return Result<TextAnchorType> { StyleParserFailure, TextAnchorType::Center };
- }
-
- return Result<TextAnchorType> { StyleParserSuccess, TextAnchorTypeClass({ value.GetString(), value.GetStringLength() }) };
-}
-
-template<> StyleParser::Result<TextJustifyType> StyleParser::parseProperty<TextJustifyType>(JSVal value, const char *property_name) {
- if (!value.IsString()) {
- Log::Warning(Event::ParseStyle, "value of '%s' must be a string", property_name);
- return Result<TextJustifyType> { StyleParserFailure, TextJustifyType::Center };
- }
- return Result<TextJustifyType> { StyleParserSuccess, TextJustifyTypeClass({ value.GetString(), value.GetStringLength() }) };
-}
-
-template<> StyleParser::Result<TextTransformType> StyleParser::parseProperty<TextTransformType>(JSVal value, const char *property_name) {
- if (!value.IsString()) {
- Log::Warning(Event::ParseStyle, "value of '%s' must be a string", property_name);
- return Result<TextTransformType> { StyleParserFailure, TextTransformType::None };
- }
-
- return Result<TextTransformType> { StyleParserSuccess, TextTransformTypeClass({ value.GetString(), value.GetStringLength() }) };
-}
-
-template<> StyleParser::Result<RotationAlignmentType> StyleParser::parseProperty<RotationAlignmentType>(JSVal value, const char *property_name) {
- if (!value.IsString()) {
- Log::Warning(Event::ParseStyle, "value of '%s' must be a string", property_name);
- return Result<RotationAlignmentType> { StyleParserFailure, RotationAlignmentType::Map };
- }
-
- return Result<RotationAlignmentType> { StyleParserSuccess, RotationAlignmentTypeClass({ value.GetString(), value.GetStringLength() }) };
-}
+ unsigned int intValue = tileSizeVal.GetUint();
+ if (intValue > std::numeric_limits<uint16_t>::max()) {
+ Log::Warning(Event::ParseStyle, "values for tileSize that are larger than %d are not supported", std::numeric_limits<uint16_t>::max());
+ continue;
+ }
-template<> StyleParser::Result<PropertyTransition> StyleParser::parseProperty(JSVal value, const char */*property_name*/) {
- PropertyTransition transition;
- if (value.IsObject()) {
- bool parsed = false;
- if (value.HasMember("duration") && value["duration"].IsNumber()) {
- transition.duration = std::chrono::milliseconds(value["duration"].GetUint());
- parsed = true;
- }
- if (value.HasMember("delay") && value["delay"].IsNumber()) {
- transition.delay = std::chrono::milliseconds(value["delay"].GetUint());
- parsed = true;
- }
- if (!parsed) {
- return Result<PropertyTransition> { StyleParserFailure, std::move(transition) };
+ source->info.tile_size = intValue;
}
- }
- return Result<PropertyTransition> { StyleParserSuccess, std::move(transition) };
-}
-template<> StyleParser::Result<Function<std::array<float, 2>>> StyleParser::parseProperty(JSVal value, const char *property_name) {
- return parseFunction<std::array<float, 2>>(value, property_name);
-}
+ source->info.parseTileJSONProperties(sourceVal);
-template<> StyleParser::Result<Function<std::string>> StyleParser::parseProperty(JSVal value, const char *property_name) {
- return parseFunction<std::string>(value, property_name);
-}
-
-template<> StyleParser::Result<Function<TranslateAnchorType>> StyleParser::parseProperty(JSVal value, const char *property_name) {
- return parseFunction<TranslateAnchorType>(value, property_name);
-}
-
-template<> StyleParser::Result<Function<RotateAnchorType>> StyleParser::parseProperty(JSVal value, const char *property_name) {
- return parseFunction<RotateAnchorType>(value, property_name);
-}
-
-template<> StyleParser::Result<Function<CapType>> StyleParser::parseProperty(JSVal value, const char *property_name) {
- return parseFunction<CapType>(value, property_name);
-}
-
-template<> StyleParser::Result<Function<JoinType>> StyleParser::parseProperty(JSVal value, const char *property_name) {
- return parseFunction<JoinType>(value, property_name);
-}
-
-template<> StyleParser::Result<Function<PlacementType>> StyleParser::parseProperty(JSVal value, const char *property_name) {
- return parseFunction<PlacementType>(value, property_name);
-}
-
-template<> StyleParser::Result<Function<TextAnchorType>> StyleParser::parseProperty(JSVal value, const char *property_name) {
- return parseFunction<TextAnchorType>(value, property_name);
-}
-
-template<> StyleParser::Result<Function<TextJustifyType>> StyleParser::parseProperty(JSVal value, const char *property_name) {
- return parseFunction<TextJustifyType>(value, property_name);
-}
-
-template<> StyleParser::Result<Function<TextTransformType>> StyleParser::parseProperty(JSVal value, const char *property_name) {
- return parseFunction<TextTransformType>(value, property_name);
-}
-
-template<> StyleParser::Result<Function<RotationAlignmentType>> StyleParser::parseProperty(JSVal value, const char *property_name) {
- return parseFunction<RotationAlignmentType>(value, property_name);
-}
-
-
-template<> StyleParser::Result<Function<bool>> StyleParser::parseProperty(JSVal value, const char *property_name) {
- return parseFunction<bool>(value, property_name);
-}
-
-template<> StyleParser::Result<Function<float>> StyleParser::parseProperty(JSVal value, const char *property_name) {
- return parseFunction<float>(value, property_name);
-}
-
-template<> StyleParser::Result<Function<Color>> StyleParser::parseProperty(JSVal value, const char *property_name) {
- return parseFunction<Color>(value, property_name);
-}
-
-template<> StyleParser::Result<PiecewiseConstantFunction<Faded<std::vector<float>>>> StyleParser::parseProperty(JSVal value, const char *property_name, JSVal transition) {
- if (value.IsObject()) {
- return parsePiecewiseConstantFunction<Faded<std::vector<float>>>(value, transition);
- } else if (value.IsArray()) {
- Faded<std::vector<float>> parsed;
- Result<std::vector<float>> floatarray = parseFloatArray(value);
- parsed.to = std::get<1>(floatarray);
- return Result<PiecewiseConstantFunction<Faded<std::vector<float>>>> { std::get<0>(floatarray), { parsed, {} } };
- } else {
- Log::Warning(Event::ParseStyle, "value of '%s' must be an array of numbers, or a number array function", property_name);
- return Result<PiecewiseConstantFunction<Faded<std::vector<float>>>> { StyleParserFailure, { {}, {} } };
+ sourcesMap.emplace(source->info.source_id, source.get());
+ sources.emplace_back(std::move(source));
}
}
-template<> StyleParser::Result<PiecewiseConstantFunction<Faded<std::string>>> StyleParser::parseProperty(JSVal value, const char *property_name, JSVal transition) {
- if (value.IsObject()) {
- return parsePiecewiseConstantFunction<Faded<std::string>>(value, transition);
- } else if (value.IsString()) {
- Faded<std::string> parsed;
- parsed.to = { value.GetString(), value.GetStringLength() };
- return Result<PiecewiseConstantFunction<Faded<std::string>>> { StyleParserSuccess, { parsed, {} } };
- } else {
- Log::Warning(Event::ParseStyle, "value of '%s' must be string or a string function", property_name);
- return Result<PiecewiseConstantFunction<Faded<std::string>>> { StyleParserFailure, { {}, {} } };
- }
-}
-
-#pragma mark - Parse Layers
-
-void StyleParser::parseLayers(JSVal value) {
+void StyleParser::parseLayers(const JSVal& value) {
std::vector<std::string> ids;
if (!value.IsArray()) {
@@ -630,7 +104,7 @@ void StyleParser::parseLayers(JSVal value) {
}
for (rapidjson::SizeType i = 0; i < value.Size(); ++i) {
- JSVal layerValue = value[i];
+ const JSVal& layerValue = value[i];
if (!layerValue.IsObject()) {
Log::Warning(Event::ParseStyle, "layer must be an object");
@@ -642,7 +116,7 @@ void StyleParser::parseLayers(JSVal value) {
continue;
}
- JSVal id = layerValue["id"];
+ const JSVal& id = layerValue["id"];
if (!id.IsString()) {
Log::Warning(Event::ParseStyle, "layer id must be a string");
continue;
@@ -654,7 +128,7 @@ void StyleParser::parseLayers(JSVal value) {
continue;
}
- layersMap.emplace(layerID, std::pair<JSVal, util::ptr<StyleLayer>> { layerValue, nullptr });
+ layersMap.emplace(layerID, std::pair<const JSVal&, util::ptr<StyleLayer>> { layerValue, nullptr });
ids.push_back(layerID);
}
@@ -671,7 +145,7 @@ void StyleParser::parseLayers(JSVal value) {
}
}
-void StyleParser::parseLayer(const std::string& id, JSVal value, util::ptr<StyleLayer>& layer) {
+void StyleParser::parseLayer(const std::string& id, const JSVal& value, util::ptr<StyleLayer>& layer) {
if (layer) {
// Skip parsing this again. We already have a valid layer definition.
return;
@@ -685,7 +159,7 @@ void StyleParser::parseLayer(const std::string& id, JSVal value, util::ptr<Style
if (value.HasMember("ref")) {
// This layer is referencing another layer. Recursively parse that layer.
- JSVal refVal = value["ref"];
+ const JSVal& refVal = value["ref"];
if (!refVal.IsString()) {
Log::Warning(Event::ParseStyle, "layer ref of '%s' must be a string", id.c_str());
return;
@@ -722,7 +196,7 @@ void StyleParser::parseLayer(const std::string& id, JSVal value, util::ptr<Style
return;
}
- JSVal typeVal = value["type"];
+ const JSVal& typeVal = value["type"];
if (!typeVal.IsString()) {
Log::Warning(Event::ParseStyle, "layer '%s' has an invalid type", id.c_str());
return;
@@ -739,19 +213,18 @@ void StyleParser::parseLayer(const std::string& id, JSVal value, util::ptr<Style
layer->id = id;
layer->type = typeClass;
-
- util::ptr<StyleBucket> bucket = std::make_shared<StyleBucket>(layer->type);
+ layer->bucket = std::make_shared<StyleBucket>(layer->type);
// We name the buckets according to the layer that defined it.
- bucket->name = layer->id;
+ layer->bucket->name = layer->id;
if (value.HasMember("source")) {
- JSVal value_source = value["source"];
+ const JSVal& value_source = value["source"];
if (value_source.IsString()) {
- bucket->source = { value_source.GetString(), value_source.GetStringLength() };
- auto source_it = sourcesMap.find(bucket->source);
+ layer->bucket->source = { value_source.GetString(), value_source.GetStringLength() };
+ auto source_it = sourcesMap.find(layer->bucket->source);
if (source_it == sourcesMap.end()) {
- Log::Warning(Event::ParseStyle, "can't find source '%s' required for layer '%s'", bucket->source.c_str(), layer->id.c_str());
+ Log::Warning(Event::ParseStyle, "can't find source '%s' required for layer '%s'", layer->bucket->source.c_str(), layer->id.c_str());
}
} else {
Log::Warning(Event::ParseStyle, "source of layer '%s' must be a string", layer->id.c_str());
@@ -759,208 +232,66 @@ void StyleParser::parseLayer(const std::string& id, JSVal value, util::ptr<Style
}
if (value.HasMember("source-layer")) {
- JSVal value_source_layer = value["source-layer"];
+ const JSVal& value_source_layer = value["source-layer"];
if (value_source_layer.IsString()) {
- bucket->source_layer = { value_source_layer.GetString(), value_source_layer.GetStringLength() };
+ layer->bucket->source_layer = { value_source_layer.GetString(), value_source_layer.GetStringLength() };
} else {
Log::Warning(Event::ParseStyle, "source-layer of layer '%s' must be a string", layer->id.c_str());
}
}
if (value.HasMember("filter")) {
- bucket->filter = parseFilterExpression(value["filter"]);
- }
-
- if (value.HasMember("layout")) {
- parseLayout(value["layout"], bucket);
+ layer->bucket->filter = parseFilterExpression(value["filter"]);
}
if (value.HasMember("minzoom")) {
- JSVal min_zoom = value["minzoom"];
+ const JSVal& min_zoom = value["minzoom"];
if (min_zoom.IsNumber()) {
- bucket->min_zoom = min_zoom.GetDouble();
+ layer->bucket->min_zoom = min_zoom.GetDouble();
} else {
Log::Warning(Event::ParseStyle, "minzoom of layer %s must be numeric", layer->id.c_str());
}
}
if (value.HasMember("maxzoom")) {
- JSVal max_zoom = value["maxzoom"];
+ const JSVal& max_zoom = value["maxzoom"];
if (max_zoom.IsNumber()) {
- bucket->max_zoom = max_zoom.GetDouble();
+ layer->bucket->max_zoom = max_zoom.GetDouble();
} else {
Log::Warning(Event::ParseStyle, "maxzoom of layer %s must be numeric", layer->id.c_str());
}
}
- layer->bucket = bucket;
- }
-
- std::map<ClassID, ClassProperties> paints;
- parsePaints(value, paints);
- layer->paints.paints = std::move(paints);
-}
-
-#pragma mark - Parse Styles
-
-void StyleParser::parsePaints(JSVal value, std::map<ClassID, ClassProperties> &paints) {
- rapidjson::Value::ConstMemberIterator itr = value.MemberBegin();
- for (; itr != value.MemberEnd(); ++itr) {
- const std::string name { itr->name.GetString(), itr->name.GetStringLength() };
-
- if (name == "paint") {
- parsePaint(itr->value, paints[ClassID::Default]);
- } else if (name.compare(0, 6, "paint.") == 0 && name.length() > 6) {
- const ClassID class_id = ClassDictionary::Get().lookup(name.substr(6));
- parsePaint(itr->value, paints[class_id]);
+ if (value.HasMember("layout")) {
+ parseVisibility(*layer->bucket, value["layout"]);
+ layer->parseLayout(value["layout"]);
}
}
-}
-void StyleParser::parsePaint(JSVal value, ClassProperties &klass) {
- using Key = PropertyKey;
-
- parseOptionalProperty<Function<bool>>("fill-antialias", Key::FillAntialias, klass, value);
- parseOptionalProperty<Function<float>>("fill-opacity", Key::FillOpacity, klass, value);
- parseOptionalProperty<PropertyTransition>("fill-opacity-transition", Key::FillOpacity, klass, value);
- parseOptionalProperty<Function<Color>>("fill-color", Key::FillColor, klass, value);
- parseOptionalProperty<PropertyTransition>("fill-color-transition", Key::FillColor, klass, value);
- parseOptionalProperty<Function<Color>>("fill-outline-color", Key::FillOutlineColor, klass, value);
- parseOptionalProperty<PropertyTransition>("fill-outline-color-transition", Key::FillOutlineColor, klass, value);
- parseOptionalProperty<Function<std::array<float, 2>>>("fill-translate", Key::FillTranslate, klass, value);
- parseOptionalProperty<PropertyTransition>("fill-translate-transition", Key::FillTranslate, klass, value);
- parseOptionalProperty<Function<TranslateAnchorType>>("fill-translate-anchor", Key::FillTranslateAnchor, klass, value);
- parseOptionalProperty<PiecewiseConstantFunction<Faded<std::string>>>("fill-pattern", Key::FillImage, klass, value, "fill-pattern-transition");
-
- parseOptionalProperty<Function<float>>("line-opacity", Key::LineOpacity, klass, value);
- parseOptionalProperty<PropertyTransition>("line-opacity-transition", Key::LineOpacity, klass, value);
- parseOptionalProperty<Function<Color>>("line-color", Key::LineColor, klass, value);
- parseOptionalProperty<PropertyTransition>("line-color-transition", Key::LineColor, klass, value);
- parseOptionalProperty<Function<std::array<float,2>>>("line-translate", Key::LineTranslate, klass, value);
- parseOptionalProperty<PropertyTransition>("line-translate-transition", Key::LineTranslate, klass, value);
- parseOptionalProperty<Function<TranslateAnchorType>>("line-translate-anchor", Key::LineTranslateAnchor, klass, value);
- parseOptionalProperty<Function<float>>("line-width", Key::LineWidth, klass, value);
- parseOptionalProperty<PropertyTransition>("line-width-transition", Key::LineWidth, klass, value);
- parseOptionalProperty<Function<float>>("line-gap-width", Key::LineGapWidth, klass, value);
- parseOptionalProperty<PropertyTransition>("line-gap-width-transition", Key::LineGapWidth, klass, value);
- parseOptionalProperty<Function<float>>("line-blur", Key::LineBlur, klass, value);
- parseOptionalProperty<PropertyTransition>("line-blur-transition", Key::LineBlur, klass, value);
- parseOptionalProperty<PiecewiseConstantFunction<Faded<std::vector<float>>>>("line-dasharray", Key::LineDashArray, klass, value, "line-dasharray-transition");
- parseOptionalProperty<PiecewiseConstantFunction<Faded<std::string>>>("line-pattern", Key::LineImage, klass, value, "line-pattern-transition");
-
- parseOptionalProperty<Function<float>>("circle-radius", Key::CircleRadius, klass, value);
- parseOptionalProperty<Function<Color>>("circle-color", Key::CircleColor, klass, value);
- parseOptionalProperty<Function<float>>("circle-opacity", Key::CircleOpacity, klass, value);
- parseOptionalProperty<Function<std::array<float,2>>>("circle-translate", Key::CircleTranslate, klass, value);
- parseOptionalProperty<Function<TranslateAnchorType>>("circle-translate-anchor", Key::CircleTranslateAnchor, klass, value);
- parseOptionalProperty<Function<float>>("circle-blur", Key::CircleBlur, klass, value);
-
- parseOptionalProperty<Function<float>>("icon-opacity", Key::IconOpacity, klass, value);
- parseOptionalProperty<PropertyTransition>("icon-opacity-transition", Key::IconOpacity, klass, value);
- parseOptionalProperty<Function<float>>("icon-size", Key::IconSize, klass, value);
- parseOptionalProperty<PropertyTransition>("icon-size-transition", Key::IconSize, klass, value);
- parseOptionalProperty<Function<Color>>("icon-color", Key::IconColor, klass, value);
- parseOptionalProperty<PropertyTransition>("icon-color-transition", Key::IconColor, klass, value);
- parseOptionalProperty<Function<Color>>("icon-halo-color", Key::IconHaloColor, klass, value);
- parseOptionalProperty<PropertyTransition>("icon-halo-color-transition", Key::IconHaloColor, klass, value);
- parseOptionalProperty<Function<float>>("icon-halo-width", Key::IconHaloWidth, klass, value);
- parseOptionalProperty<PropertyTransition>("icon-halo-width-transition", Key::IconHaloWidth, klass, value);
- parseOptionalProperty<Function<float>>("icon-halo-blur", Key::IconHaloBlur, klass, value);
- parseOptionalProperty<PropertyTransition>("icon-halo-blur-transition", Key::IconHaloBlur, klass, value);
- parseOptionalProperty<Function<std::array<float, 2>>>("icon-translate", Key::IconTranslate, klass, value);
- parseOptionalProperty<PropertyTransition>("icon-translate-transition", Key::IconTranslate, klass, value);
- parseOptionalProperty<Function<TranslateAnchorType>>("icon-translate-anchor", Key::IconTranslateAnchor, klass, value);
-
- parseOptionalProperty<Function<float>>("text-opacity", Key::TextOpacity, klass, value);
- parseOptionalProperty<PropertyTransition>("text-opacity-transition", Key::TextOpacity, klass, value);
- parseOptionalProperty<Function<float>>("text-size", Key::TextSize, klass, value);
- parseOptionalProperty<PropertyTransition>("text-size-transition", Key::TextSize, klass, value);
- parseOptionalProperty<Function<Color>>("text-color", Key::TextColor, klass, value);
- parseOptionalProperty<PropertyTransition>("text-color-transition", Key::TextColor, klass, value);
- parseOptionalProperty<Function<Color>>("text-halo-color", Key::TextHaloColor, klass, value);
- parseOptionalProperty<PropertyTransition>("text-halo-color-transition", Key::TextHaloColor, klass, value);
- parseOptionalProperty<Function<float>>("text-halo-width", Key::TextHaloWidth, klass, value);
- parseOptionalProperty<PropertyTransition>("text-halo-width-transition", Key::TextHaloWidth, klass, value);
- parseOptionalProperty<Function<float>>("text-halo-blur", Key::TextHaloBlur, klass, value);
- parseOptionalProperty<PropertyTransition>("text-halo-blur-transition", Key::TextHaloBlur, klass, value);
- parseOptionalProperty<Function<std::array<float, 2>>>("text-translate", Key::TextTranslate, klass, value);
- parseOptionalProperty<PropertyTransition>("text-translate-transition", Key::TextTranslate, klass, value);
- parseOptionalProperty<Function<TranslateAnchorType>>("text-translate-anchor", Key::TextTranslateAnchor, klass, value);
-
- parseOptionalProperty<Function<float>>("raster-opacity", Key::RasterOpacity, klass, value);
- parseOptionalProperty<PropertyTransition>("raster-opacity-transition", Key::RasterOpacity, klass, value);
- parseOptionalProperty<Function<float>>("raster-hue-rotate", Key::RasterHueRotate, klass, value);
- parseOptionalProperty<PropertyTransition>("raster-hue-rotate-transition", Key::RasterHueRotate, klass, value);
- parseOptionalProperty<Function<float>>("raster-brightness-min", Key::RasterBrightnessLow, klass, value);
- parseOptionalProperty<Function<float>>("raster-brightness-max", Key::RasterBrightnessHigh, klass, value);
- parseOptionalProperty<PropertyTransition>("raster-brightness-transition", Key::RasterBrightness, klass, value);
- parseOptionalProperty<Function<float>>("raster-saturation", Key::RasterSaturation, klass, value);
- parseOptionalProperty<PropertyTransition>("raster-saturation-transition", Key::RasterSaturation, klass, value);
- parseOptionalProperty<Function<float>>("raster-contrast", Key::RasterContrast, klass, value);
- parseOptionalProperty<PropertyTransition>("raster-contrast-transition", Key::RasterContrast, klass, value);
- parseOptionalProperty<Function<float>>("raster-fade-duration", Key::RasterFade, klass, value);
- parseOptionalProperty<PropertyTransition>("raster-fade-duration-transition", Key::RasterFade, klass, value);
-
- parseOptionalProperty<Function<float>>("background-opacity", Key::BackgroundOpacity, klass, value);
- parseOptionalProperty<Function<Color>>("background-color", Key::BackgroundColor, klass, value);
- parseOptionalProperty<PiecewiseConstantFunction<Faded<std::string>>>("background-pattern", Key::BackgroundImage, klass, value, "background-pattern-transition");
+ layer->parsePaints(value);
}
-void StyleParser::parseLayout(JSVal value, util::ptr<StyleBucket> &bucket) {
- using Key = PropertyKey;
-
- parseVisibility<VisibilityType>(*bucket, value);
-
- parseOptionalProperty<Function<CapType>>("line-cap", Key::LineCap, bucket->layout, value);
- parseOptionalProperty<Function<JoinType>>("line-join", Key::LineJoin, bucket->layout, value);
- parseOptionalProperty<Function<float>>("line-miter-limit", Key::LineMiterLimit, bucket->layout, value);
- parseOptionalProperty<Function<float>>("line-round-limit", Key::LineRoundLimit, bucket->layout, value);
-
- parseOptionalProperty<Function<PlacementType>>("symbol-placement", Key::SymbolPlacement, bucket->layout, value);
- parseOptionalProperty<Function<float>>("symbol-spacing", Key::SymbolSpacing, bucket->layout, value);
- parseOptionalProperty<Function<bool>>("symbol-avoid-edges", Key::SymbolAvoidEdges, bucket->layout, value);
- parseOptionalProperty<Function<bool>>("icon-allow-overlap", Key::IconAllowOverlap, bucket->layout, value);
- parseOptionalProperty<Function<bool>>("icon-ignore-placement", Key::IconIgnorePlacement, bucket->layout, value);
- parseOptionalProperty<Function<bool>>("icon-optional", Key::IconOptional, bucket->layout, value);
- parseOptionalProperty<Function<RotationAlignmentType>>("icon-rotation-alignment", Key::IconRotationAlignment, bucket->layout, value);
- parseOptionalProperty<Function<float>>("icon-size", Key::IconSize, bucket->layout, value);
- parseOptionalProperty<Function<std::string>>("icon-image", Key::IconImage, bucket->layout, value);
- parseOptionalProperty<Function<float>>("icon-rotate", Key::IconRotate, bucket->layout, value);
- parseOptionalProperty<Function<float>>("icon-padding", Key::IconPadding, bucket->layout, value);
- parseOptionalProperty<Function<bool>>("icon-keep-upright", Key::IconKeepUpright, bucket->layout, value);
- parseOptionalProperty<Function<std::array<float, 2>>>("icon-offset", Key::IconOffset, bucket->layout, value);
- parseOptionalProperty<Function<RotationAlignmentType>>("text-rotation-alignment", Key::TextRotationAlignment, bucket->layout, value);
- parseOptionalProperty<Function<std::string>>("text-field", Key::TextField, bucket->layout, value);
- parseOptionalProperty<Function<std::string>>("text-font", Key::TextFont, bucket->layout, value);
- parseOptionalProperty<Function<float>>("text-size", Key::TextSize, bucket->layout, value);
- parseOptionalProperty<Function<float>>("text-max-width", Key::TextMaxWidth, bucket->layout, value);
- parseOptionalProperty<Function<float>>("text-line-height", Key::TextLineHeight, bucket->layout, value);
- parseOptionalProperty<Function<float>>("text-letter-spacing", Key::TextLetterSpacing, bucket->layout, value);
- parseOptionalProperty<Function<TextJustifyType>>("text-justify", Key::TextJustify, bucket->layout, value);
- parseOptionalProperty<Function<TextAnchorType>>("text-anchor", Key::TextAnchor, bucket->layout, value);
- parseOptionalProperty<Function<float>>("text-max-angle", Key::TextMaxAngle, bucket->layout, value);
- parseOptionalProperty<Function<float>>("text-rotate", Key::TextRotate, bucket->layout, value);
- parseOptionalProperty<Function<float>>("text-padding", Key::TextPadding, bucket->layout, value);
- parseOptionalProperty<Function<bool>>("text-keep-upright", Key::TextKeepUpright, bucket->layout, value);
- parseOptionalProperty<Function<TextTransformType>>("text-transform", Key::TextTransform, bucket->layout, value);
- parseOptionalProperty<Function<std::array<float, 2>>>("text-offset", Key::TextOffset, bucket->layout, value);
- parseOptionalProperty<Function<bool>>("text-allow-overlap", Key::TextAllowOverlap, bucket->layout, value);
- parseOptionalProperty<Function<bool>>("text-ignore-placement", Key::TextIgnorePlacement, bucket->layout, value);
- parseOptionalProperty<Function<bool>>("text-optional", Key::TextOptional, bucket->layout, value);
-
-}
-
-void StyleParser::parseSprite(JSVal value) {
+void StyleParser::parseSprite(const JSVal& value) {
if (value.IsString()) {
sprite = { value.GetString(), value.GetStringLength() };
}
}
-void StyleParser::parseGlyphURL(JSVal value) {
+void StyleParser::parseGlyphURL(const JSVal& value) {
if (value.IsString()) {
glyph_url = { value.GetString(), value.GetStringLength() };
}
}
+void StyleParser::parseVisibility(StyleBucket& bucket, const JSVal& value) {
+ if (!value.HasMember("visibility")) {
+ return;
+ } else if (!value["visibility"].IsString()) {
+ Log::Warning(Event::ParseStyle, "value of 'visibility' must be a string");
+ bucket.visibility = VisibilityType::Visible;
+ return;
+ }
+ bucket.visibility = VisibilityTypeClass({ value["visibility"].GetString(), value["visibility"].GetStringLength() });
+}
}
diff --git a/src/mbgl/style/style_parser.hpp b/src/mbgl/style/style_parser.hpp
index 9efa8a85e3..583f8bc517 100644
--- a/src/mbgl/style/style_parser.hpp
+++ b/src/mbgl/style/style_parser.hpp
@@ -1,37 +1,28 @@
#ifndef MBGL_STYLE_STYLE_PARSER
#define MBGL_STYLE_STYLE_PARSER
-#include <rapidjson/document.h>
-#include <mbgl/style/style.hpp>
#include <mbgl/map/source.hpp>
-#include <mbgl/style/filter_expression.hpp>
-#include <mbgl/style/class_properties.hpp>
+#include <mbgl/util/ptr.hpp>
+
+#include <rapidjson/document.h>
#include <mbgl/style/style_bucket.hpp>
+#include <vector>
+#include <memory>
+#include <string>
#include <unordered_map>
#include <forward_list>
-#include <tuple>
namespace mbgl {
-enum class ClassID : uint32_t;
-
class StyleLayer;
class Source;
+using JSVal = rapidjson::Value;
+
class StyleParser {
public:
- using JSVal = const rapidjson::Value&;
-
- enum Status : bool {
- StyleParserFailure = 0,
- StyleParserSuccess
- };
-
- template<typename T>
- using Result = std::pair<Status, T>;
-
- void parse(JSVal document);
+ void parse(const JSVal&);
std::vector<std::unique_ptr<Source>>&& getSources() {
return std::move(sources);
@@ -50,57 +41,20 @@ public:
}
private:
- void parseSources(JSVal value);
- void parseLayers(JSVal value);
- void parseLayer(const std::string& id, JSVal value, util::ptr<StyleLayer>&);
- void parsePaints(JSVal value, std::map<ClassID, ClassProperties> &paints);
- void parsePaint(JSVal, ClassProperties &properties);
- void parseLayout(JSVal value, util::ptr<StyleBucket> &bucket);
- void parseSprite(JSVal value);
- void parseGlyphURL(JSVal value);
-
- // Parses optional properties into a render bucket.
- template<typename T>
- Status parseRenderProperty(JSVal value, T &target, const char *name);
- template <typename Parser, typename T>
- Status parseRenderProperty(JSVal value, T &target, const char *name);
-
- // Parses optional properties into style class properties.
- template <typename T>
- void parseVisibility(StyleBucket &bucket, JSVal value);
- template <typename T>
- Status parseOptionalProperty(const char *property_name, PropertyKey key, ClassProperties &klass, JSVal value);
- template <typename T>
- Status parseOptionalProperty(const char *property_name, PropertyKey key, ClassProperties &klass, JSVal value, const char *transition_name);
- template <typename T>
- Status setProperty(JSVal value, const char *property_name, PropertyKey key, ClassProperties &klass);
- template <typename T>
- Status setProperty(JSVal value, const char *property_name, PropertyKey key, ClassProperties &klass, JSVal transition);
-
- template <typename T>
- Result<T> parseProperty(JSVal value, const char *property_name);
- template <typename T>
- Result<T> parseProperty(JSVal value, const char *property_name, JSVal transition);
-
- template <typename T>
- Result<Function<T>> parseFunction(JSVal value, const char *);
- template <typename T>
- Result<PiecewiseConstantFunction<T>> parsePiecewiseConstantFunction(JSVal value, JSVal transition);
- template <typename T>
- Result<std::vector<std::pair<float, T>>> parseStops(JSVal value, const char *property_name);
-
- Result<std::vector<float>> parseFloatArray(JSVal value);
-
- FilterExpression parseFilter(JSVal);
+ void parseSources(const JSVal&);
+ void parseLayers(const JSVal&);
+ void parseLayer(const std::string& id, const JSVal&, util::ptr<StyleLayer>&);
+ void parseSprite(const JSVal&);
+ void parseGlyphURL(const JSVal&);
+ void parseVisibility(StyleBucket&, const JSVal& value);
-private:
std::uint8_t version;
std::vector<std::unique_ptr<Source>> sources;
std::vector<util::ptr<StyleLayer>> layers;
std::unordered_map<std::string, const Source*> sourcesMap;
- std::unordered_map<std::string, std::pair<JSVal, util::ptr<StyleLayer>>> layersMap;
+ std::unordered_map<std::string, std::pair<const JSVal&, util::ptr<StyleLayer>>> layersMap;
// Store a stack of layer IDs we're parsing right now. This is to prevent reference cycles.
std::forward_list<std::string> stack;
diff --git a/test/fixtures/style_parser/circle-color.info.json b/test/fixtures/style_parser/circle-color.info.json
index b1708c2f05..70375ce8f5 100644
--- a/test/fixtures/style_parser/circle-color.info.json
+++ b/test/fixtures/style_parser/circle-color.info.json
@@ -1,7 +1,7 @@
{
"default": {
"log": [
- [1, "WARNING", "ParseStyle", "color value must be a string"]
+ [1, "WARNING", "ParseStyle", "value of 'circle-color' must be a string"]
]
}
}
diff --git a/test/fixtures/style_parser/line-translate.info.json b/test/fixtures/style_parser/line-translate.info.json
index 3d9a908eb4..ff126bbf22 100644
--- a/test/fixtures/style_parser/line-translate.info.json
+++ b/test/fixtures/style_parser/line-translate.info.json
@@ -1,7 +1,7 @@
{
"default": {
"log": [
- [1, "WARNING", "ParseStyle", "value must be array of two numbers"]
+ [1, "WARNING", "ParseStyle", "value of 'line-translate' must be an array of two numbers"]
]
}
}
diff --git a/test/storage/http_error.cpp b/test/storage/http_error.cpp
index d0eefb408c..85bc70e546 100644
--- a/test/storage/http_error.cpp
+++ b/test/storage/http_error.cpp
@@ -53,7 +53,7 @@ TEST_F(Storage, HTTPError) {
fs.cancel(req2);
const auto duration = double(uv_hrtime() - start) / 1e9;
// 1.5 seconds == 4 retries, with a 500ms timeout (see above).
- EXPECT_LT(1.5, duration) << "Resource wasn't retried the correct number of times";
+ EXPECT_LT(1.4, duration) << "Resource wasn't retried the correct number of times";
EXPECT_GT(1.7, duration) << "Resource wasn't retried the correct number of times";
EXPECT_EQ(Response::Error, res.status);
EXPECT_EQ(false, res.stale);