Merge branch 'master' into pattern-functions

Conflicts:
	src/mbgl/renderer/painter.cpp
	src/mbgl/renderer/painter.hpp
	src/mbgl/renderer/painter_fill.cpp
	src/mbgl/renderer/painter_line.cpp
	src/mbgl/style/style_layer.cpp
	src/mbgl/style/style_layer.hpp
	src/mbgl/style/style_layer_group.cpp
	src/mbgl/style/style_layer_group.hpp
This commit is contained in:
Ansis Brammanis
2015-02-04 11:05:36 -08:00
228 changed files with 6729 additions and 4555 deletions

View File

@@ -2,9 +2,11 @@ Standard: Cpp11
IndentWidth: 4
AccessModifierOffset: -4
UseTab: Never
BinPackParameters: true
BinPackParameters: false
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AllowShortBlocksOnASingleLine: false
AllowShortFunctionsOnASingleLine: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
AlwaysBreakTemplateDeclarations: true
NamespaceIndentation: None
@@ -12,5 +14,5 @@ PointerBindsToType: false
SpacesInParentheses: false
BreakBeforeBraces: Attach
ColumnLimit: 100
Cpp11BracedListStyle: true
Cpp11BracedListStyle: false
SpacesBeforeTrailingComments: 1

9
.gitignore vendored
View File

@@ -3,11 +3,14 @@
*.o
*.actual.png
*.diff.png
*.pyc
/mason_packages
/config.gypi
/config-ios.gypi
/config-android.gypi
/config/*.gypi
/build
/macosx/build
/linux/build
/test/build
/test/node_modules
/include/mbgl/shader/shaders.hpp
/src/shader/shaders_gl.cpp
/src/shader/shaders_gles2.cpp

4
.gitmodules vendored
View File

@@ -13,3 +13,7 @@
[submodule "styles"]
path = styles
url = https://github.com/mapbox/mapbox-gl-styles.git
[submodule "app/ios"]
path = app/ios
url = https://github.com/mapbox/mapbox-gl-cocoa.git

2
.mason

Submodule .mason updated: 3833ddbd71...03869fd11e

View File

@@ -53,13 +53,13 @@ before_install:
- if [[ ${TRAVIS_OS_NAME} == "linux" ]]; then sudo service postgresql stop; fi
- source ./scripts/local_mason.sh
- source ./scripts/travis_helper.sh
- source ./scripts/install_node.sh
- source ./scripts/flags.sh
- ./scripts/travis_before_install.sh
- if [[ ${TRAVIS_OS_NAME} == "linux" && ${MASON_PLATFORM} != "android" ]]; then export LD_LIBRARY_PATH=`mason prefix mesa 10.4.3`/lib; fi
- if [[ ${TRAVIS_OS_NAME} == "linux" && ${MASON_PLATFORM} != "android" ]]; then glxinfo; fi
install:
- if [[ ${MASON_PLATFORM} != "android" ]]; then make config.gypi; fi
- ulimit -c
before_script:

287
Makefile
View File

@@ -1,143 +1,174 @@
BUILDTYPE ?= Release
PYTHON ?= python
V ?= 1
PREFIX ?= /usr/local
ANDROID_ABI ?= arm-v7
JOBS ?= 1
ifeq ($(shell uname -s), Darwin)
PLATFORM ?= osx
HOST ?= osx
endif
PLATFORM ?= linux
HOST ?= linux
.PHONY: all
all: mbgl-core mbgl-platform mbgl-headless
all: mbgl
config.gypi: configure
./configure
include config/defaults.mk
config-ios.gypi: configure
MASON_PLATFORM=ios ./configure config-ios.gypi
#### Dependencies ##############################################################
# Wildcard targets get removed after build by default, but we want to preserve the config.
.PRECIOUS: config/%.gypi
config/%.gypi: CMD = ./configure config/$*.gypi
config/%.gypi: configure
@$(ENV_$*) ./scripts/flock.py build/Configure.lock ./configure config/$*.gypi
#### Library builds ############################################################
.PHONY: mbgl-core
mbgl-core: build/mbgl/Makefile
$(MAKE) -C build/mbgl BUILDTYPE=$(BUILDTYPE) V=$(V) mbgl-core
.PRECOIUS: Makefile/mbgl
Makefile/mbgl: config/$(HOST).gypi
deps/run_gyp mbgl.gyp $(CONFIG_$(HOST)) $(LIBS_$(HOST)) --generator-output=./build/$(HOST) -f make
.PHONY: mbgl-platform
mbgl-platform: build/mbgl/Makefile
$(MAKE) -C build/mbgl BUILDTYPE=$(BUILDTYPE) V=$(V) mbgl-$(PLATFORM)
mbgl: Makefile/mbgl
$(MAKE) -C build/$(HOST) BUILDTYPE=$(BUILDTYPE) everything
.PHONY: mbgl-headless
mbgl-headless: build/mbgl/Makefile
$(MAKE) -C build/mbgl BUILDTYPE=$(BUILDTYPE) V=$(V) mbgl-headless
standalone: Makefile/mbgl
LINK=`pwd`/gyp/link.py $(MAKE) -C build/$(HOST) BUILDTYPE=$(BUILDTYPE) standalone
.PHONY: install
install: build/mbgl/Makefile
$(MAKE) -C build/mbgl BUILDTYPE=$(BUILDTYPE) V=$(V) install
#### Build scripts #############################################################
.PHONY: build/mbgl/Makefile
build/mbgl/Makefile: mapboxgl.gyp config.gypi
deps/run_gyp mapboxgl.gyp -Iconfig.gypi -Dplatform=$(PLATFORM) -Dinstall_prefix=$(PREFIX) --depth=. -Goutput_dir=.. --generator-output=./build/mbgl -f make
.PHONY: build/test/Makefile
build/test/Makefile: test/test.gyp config.gypi
deps/run_gyp test/test.gyp -Iconfig.gypi -Dplatform=$(PLATFORM) --depth=. -Goutput_dir=.. --generator-output=./build/test -f make
.PHONY: build/linux/Makefile
build/linux/Makefile: linux/mapboxgl-app.gyp config.gypi
deps/run_gyp linux/mapboxgl-app.gyp -Iconfig.gypi -Dplatform=linux --depth=. -Goutput_dir=.. --generator-output=./build/linux -f make
.PHONY: build/macosx/Makefile
build/macosx/Makefile: macosx/mapboxgl-app.gyp config.gypi
deps/run_gyp macosx/mapboxgl-app.gyp -Iconfig.gypi -Dplatform=osx --depth=. -Goutput_dir=.. --generator-output=./build/macosx -f make
.PHONY: build/render/Makefile
build/render/Makefile: bin/render.gyp config.gypi
deps/run_gyp bin/render.gyp -Iconfig.gypi -Dplatform=$(PLATFORM) --depth=. -Goutput_dir=.. --generator-output=./build/render -f make
.PHONY: build/test/test.xcodeproj
build/test/test.xcodeproj: test/test.gyp config.gypi
deps/run_gyp test/test.gyp -Iconfig.gypi -Dplatform=$(PLATFORM) --depth=. -Goutput_dir=.. --generator-output=./build -f xcode
.PHONY: build/macosx/mapboxgl-app.xcodeproj
build/macosx/mapboxgl-app.xcodeproj: macosx/mapboxgl-app.gyp config.gypi
deps/run_gyp macosx/mapboxgl-app.gyp -Iconfig.gypi -Dplatform=osx --depth=. --generator-output=./build -f xcode
.PHONY: build/ios/mapbox-gl-cocoa/app/mapboxgl-app.xcodeproj
build/ios/mapbox-gl-cocoa/app/mapboxgl-app.xcodeproj: ios/mapbox-gl-cocoa/app/mapboxgl-app.gyp config-ios.gypi
deps/run_gyp ios/mapbox-gl-cocoa/app/mapboxgl-app.gyp -Iconfig-ios.gypi -Dplatform=ios --depth=. --generator-output=./build -f xcode
.PHONY: build/linux/mapboxgl-app.xcodeproj
build/linux/mapboxgl-app.xcodeproj: linux/mapboxgl-app.gyp config.gypi
deps/run_gyp linux/mapboxgl-app.gyp -Iconfig.gypi -Dplatform=linux --depth=. --generator-output=./build -f xcode
.PHONY: build/bin/render.xcodeproj
build/bin/render.xcodeproj: bin/render.gyp config.gypi
deps/run_gyp bin/render.gyp -Iconfig.gypi -Dplatform=$(PLATFORM) --depth=. --generator-output=./build -f xcode
.PHONY: android
android:
./scripts/local_mason.sh && \
MASON_DIR=./.mason MASON_PLATFORM=android MASON_ANDROID_ABI=$(MASON_ANDROID_ABI) ./.mason/mason env PATH && \
export CXX="`MASON_DIR=./.mason MASON_PLATFORM=android MASON_ANDROID_ABI=${MASON_ANDROID_ABI} ./.mason/mason env CXX`" && \
export CC="`MASON_DIR=./.mason MASON_PLATFORM=android MASON_ANDROID_ABI=${MASON_ANDROID_ABI} ./.mason/mason env CC`" && \
export LD="`MASON_DIR=./.mason MASON_PLATFORM=android MASON_ANDROID_ABI=${MASON_ANDROID_ABI} ./.mason/mason env LD`" && \
export LINK="`MASON_DIR=./.mason MASON_PLATFORM=android MASON_ANDROID_ABI=${MASON_ANDROID_ABI} ./.mason/mason env CXX`" && \
export AR="`MASON_DIR=./.mason MASON_PLATFORM=android MASON_ANDROID_ABI=${MASON_ANDROID_ABI} ./.mason/mason env AR`" && \
export RANLIB="`MASON_DIR=./.mason MASON_PLATFORM=android MASON_ANDROID_ABI=${MASON_ANDROID_ABI} ./.mason/mason env RANLIB`" && \
export STRIP="`MASON_DIR=./.mason MASON_PLATFORM=android MASON_ANDROID_ABI=${MASON_ANDROID_ABI} ./.mason/mason env STRIP`" && \
export LDFLAGS="`MASON_DIR=./.mason MASON_PLATFORM=android MASON_ANDROID_ABI=${MASON_ANDROID_ABI} ./.mason/mason env LDFLAGS` ${LDFLAGS}" && \
export CFLAGS="`MASON_DIR=./.mason MASON_PLATFORM= MASON_ANDROID_ABI=${MASON_ANDROID_ABI} ./.mason/mason env CFLAGS` ${CFLAGS}" && \
export CPPFLAGS="`MASON_DIR=./.mason MASON_PLATFORM=android MASON_ANDROID_ABI=${MASON_ANDROID_ABI} ./.mason/mason env CPPFLAGS` ${CPPFLAGS}" && \
export PATH="`MASON_DIR=./.mason MASON_PLATFORM=android MASON_ANDROID_ABI=${MASON_ANDROID_ABI} ./.mason/mason env PATH`:${PATH}" && \
export JNIDIR="`MASON_DIR=./.mason MASON_PLATFORM=android MASON_ANDROID_ABI=${MASON_ANDROID_ABI} ./.mason/mason env JNIDIR`" && \
MASON_PLATFORM=android MASON_ANDROID_ABI=$(MASON_ANDROID_ABI) ./configure config-android.gypi && \
deps/run_gyp android/mapboxgl-app.gyp -Iconfig-android.gypi -Dplatform=android --depth=. --generator-output=./build/android/$(MASON_ANDROID_ABI) -f make-android && \
$(MAKE) -C build/android/$(MASON_ANDROID_ABI) -j$(JOBS) BUILDTYPE=$(BUILDTYPE) V=$(V) androidapp && \
BUILDTYPE=$(BUILDTYPE) MASON_ANDROID_ABI=$(MASON_ANDROID_ABI) ./android/scripts/copy-files.sh && \
cd android/java && \
./gradlew --parallel-threads=$(JOBS) build
##### Test cases ###############################################################
test: build/test/Makefile
$(MAKE) -C build/test BUILDTYPE=$(BUILDTYPE) V=$(V) test
test_%: build/test/Makefile
$(MAKE) -C build/test BUILDTYPE=$(BUILDTYPE) V=$(V) $*
(cd build/$(BUILDTYPE) && exec ./test_$*)
# build Mac OS X project for Xcode
xtest: build/test/test.xcodeproj
open ./build/test/test.xcodeproj
##### Makefile builds ##########################################################
install: Makefile/mbgl
LINK=`pwd`/gyp/link.py $(MAKE) -C build/$(HOST) BUILDTYPE=$(BUILDTYPE) install
# Builds the linux app with make.
linux: build/linux/Makefile
$(MAKE) -C build/linux BUILDTYPE=$(BUILDTYPE) V=$(V) linuxapp
##### Test builds ##############################################################
# Executes the Linux binary
run-linux: linux
(cd build/$(BUILDTYPE) && ./mapbox-gl)
.PRECIOUS: Makefile/test
Makefile/test: test/test.gyp config/$(HOST).gypi
deps/run_gyp test/test.gyp $(CONFIG_$(HOST)) $(LIBS_$(HOST)) --generator-output=./build/$(HOST) -f make
# Builds the OS X app with make.
osx: build/macosx/Makefile
$(MAKE) -C build/macosx BUILDTYPE=$(BUILDTYPE) V=$(V) osxapp
test: Makefile/test
$(MAKE) -C build/$(HOST) BUILDTYPE=$(BUILDTYPE) test
test-%: test
./scripts/run_tests.sh "build/$(HOST)/$(BUILDTYPE)/test" --gtest_filter=$*
.PRECIOUS: Xcode/test
Xcode/test: test/test.gyp config/osx.gypi
deps/run_gyp test/test.gyp $(CONFIG_osx) $(LIBS_osx) --generator-output=./build/osx -f xcode
.PHONY: lproj lbuild run-xlinux
xtest-proj: Xcode/test
open ./build/osx/test/test.xcodeproj
xtest: Xcode/test
xcodebuild -project ./build/osx/test/test.xcodeproj -configuration $(BUILDTYPE) -target test -jobs `sysctl -n hw.ncpu`
xtest-%: xtest
./scripts/run_tests.sh "build/osx/Build/Products/$(BUILDTYPE)/test" --gtest_filter=$*
#### Mac OS X application builds ###############################################
.PRECIOUS: Makefile/osx
Makefile/osx: macosx/mapboxgl-app.gyp config/osx.gypi
deps/run_gyp macosx/mapboxgl-app.gyp $(CONFIG_osx) $(LIBS_osx) --generator-output=./build/osx -f make
.PHONY: osx run-osx
osx: Makefile/osx
$(MAKE) -C build/osx BUILDTYPE=$(BUILDTYPE) osxapp
# Executes the OS X binary
run-osx: osx
build/$(BUILDTYPE)/Mapbox\ GL.app/Contents/MacOS/MAPBOX\ GL
"build/osx/$(BUILDTYPE)/Mapbox GL.app/Contents/MacOS/Mapbox GL"
# Builds the CLI render app
render: build/render/Makefile
$(MAKE) -C build/render BUILDTYPE=$(BUILDTYPE) V=$(V) mbgl-render
##### Xcode projects ###########################################################
.PRECIOUS: Xcode/osx
Xcode/osx: macosx/mapboxgl-app.gyp config/osx.gypi
deps/run_gyp macosx/mapboxgl-app.gyp $(CONFIG_osx) $(LIBS_osx) --generator-output=./build/osx -f xcode
.PHONY: xosx-proj xosx run-xosx
xosx-proj: Xcode/osx
open ./build/osx/macosx/mapboxgl-app.xcodeproj
xosx: Xcode/osx
xcodebuild -project ./build/osx/macosx/mapboxgl-app.xcodeproj -configuration $(BUILDTYPE) -target osxapp -jobs `sysctl -n hw.ncpu`
run-xosx: xosx
"build/osx/Build/Products/$(BUILDTYPE)/Mapbox GL.app/Contents/MacOS/Mapbox GL"
# Legacy name
xproj: xosx-proj
#### iOS application builds ####################################################
.PRECIOUS: Xcode/ios
Xcode/ios: ios/mapbox-gl-cocoa/app/mapboxgl-app.gyp config/ios.gypi
deps/run_gyp ios/mapbox-gl-cocoa/app/mapboxgl-app.gyp $(CONFIG_ios) $(LIBS_ios) --generator-output=./build/ios -f xcode
.PHONY: ios-proj ios run-ios
ios-proj: Xcode/ios
open ./build/ios/ios/mapbox-gl-cocoa/app/mapboxgl-app.xcodeproj
ios: Xcode/ios
xcodebuild -sdk iphonesimulator ARCHS=x86_64 -project ./build/ios/ios/mapbox-gl-cocoa/app/mapboxgl-app.xcodeproj -configuration $(BUILDTYPE) -target iosapp -jobs `sysctl -n hw.ncpu`
# Legacy name
iproj: ios-proj
#### Linux application builds ##################################################
.PRECIOUS: Makefile/linux
Makefile/linux: linux/mapboxgl-app.gyp config/$(HOST).gypi
deps/run_gyp linux/mapboxgl-app.gyp $(CONFIG_$(HOST)) $(LIBS_linux) --generator-output=./build/$(HOST) -f make
.PHONY: linux run-linux
linux: Makefile/linux
$(MAKE) -C build/$(HOST) BUILDTYPE=$(BUILDTYPE) linuxapp
run-linux: linux
(cd build/$(HOST)/$(BUILDTYPE) && ./mapbox-gl)
.PRECIOUS: Xcode/linux
Xcode/linux: linux/mapboxgl-app.gyp config/osx.gypi
deps/run_gyp linux/mapboxgl-app.gyp $(CONFIG_osx) $(LIBS_linux) --generator-output=./build/osx -f xcode
.PHONY: lproj lbuild run-xlinux
xlinux-proj: Xcode/linux
open ./build/osx/linux/mapboxgl-app.xcodeproj
xlinux: Xcode/linux
xcodebuild -project ./build/osx/linux/mapboxgl-app.xcodeproj -configuration $(BUILDTYPE) -target linuxapp
run-xlinux: xlinux
"build/osx/Build/Products/$(BUILDTYPE)/mapbox-gl"
# Legacy name
lproj: xlinux-proj
#### Android libaries #########################################################
.PRECIOUS: Makefile/android-%
Makefile/android-%: CMD = deps/run_gyp android/mapboxgl-app.gyp $(CONFIG_android-$*) $(LIBS_android) --generator-output=./build/android-$* -f make-android
Makefile/android-%: config/android-%.gypi
@echo $(CMD)
@$(ENV_android-$*) $(CMD)
# Builds a particular android architecture.
android-lib-%: Makefile/android-%
@$(ENV_android-$*) ./scripts/flock.py -v build/Android.lock $(MAKE) -C build/android-$* BUILDTYPE=$(BUILDTYPE) androidapp
# Builds the selected/default Android library
android: android-lib-$(ANDROID_ABI)
cd android/java && ./gradlew --parallel-threads=$(JOBS) build
# Builds all android architectures.
android-all: $(ANDROID_ABIS)
cd android/java && ./gradlew --parallel-threads=$(JOBS) build
##### Maintenace operations ####################################################
.PHONY: clear_xcode_cache
clear_xcode_cache:
@@ -153,22 +184,6 @@ ifeq ($(PLATFORM), osx)
fi
endif
xproj: build/macosx/mapboxgl-app.xcodeproj
open ./build/macosx/mapboxgl-app.xcodeproj
iproj: build/ios/mapbox-gl-cocoa/app/mapboxgl-app.xcodeproj
open ./build/ios/mapbox-gl-cocoa/app/mapboxgl-app.xcodeproj
rproj: build/bin/render.xcodeproj
open ./build/bin/render.xcodeproj
# build Linux project for Xcode (Runs on Mac OS X too, but without platform-specific code)
lproj: build/linux/mapboxgl-app.xcodeproj
open ./build/linux/mapboxgl-app.xcodeproj
##### Maintenace operations ####################################################
.PHONY: clear_sqlite_cache
clear_sqlite_cache:
ifeq ($(PLATFORM), osx)
@@ -180,8 +195,12 @@ endif
clean: clear_sqlite_cache clear_xcode_cache
-find ./deps/gyp -name "*.pyc" -exec rm {} \;
-rm -rf ./build/
-rm -rf ./macosx/build/
-rm -rf ./config.gypi ./config-ios.gypi ./config-android.gypi
-rm -rf ./macosx/build
-rm -rf ./linux/build
-rm -rf ./ios/mapbox-gl-cocoa/build
-rm -rf ./ios/mapbox-gl-cocoa/app/build
-rm -rf ./test/build
-rm -rf ./config/*.gypi
-rm -rf ./android/java/build ./android/java/app/build ./android/java/lib/build
-rm -rf ./android/java/lib/src/main/jniLibs ./android/java/lib/src/main/assets
-rm -f ./android/test/features.zip

View File

@@ -36,6 +36,7 @@ To create projects, you can run:
- `make lproj`: Creates an Xcode project with platform-independent handlers for downloads and settings storage. This is what is also being built on Linux.
- `make osx run-osx`: Builds and runs the OS X application on the command line with `xcodebuild`.
- `make linux run-linux`: Builds and runs the Linux application with `make`.
- `make test-*` Builds and runs all tests. You can specify individual tests by replacing * with their name.
Note that you can't have more than one project in Xcode open at a time since they the static library project is shared across the OS X, Linux and iOS project.

View File

@@ -18,6 +18,7 @@
#include <mbgl/platform/android/log_android.hpp>
#include <mbgl/platform/event.hpp>
#include <mbgl/platform/log.hpp>
#include <mbgl/storage/network_status.hpp>
#pragma clang diagnostic ignored "-Wunused-parameter"
@@ -380,19 +381,19 @@ jobject JNICALL nativeGetClasses(JNIEnv *env, jobject obj, jlong nativeMapViewPt
}
void JNICALL nativeSetDefaultTransitionDuration(JNIEnv *env, jobject obj, jlong nativeMapViewPtr,
jlong milliseconds) {
jlong duration) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetDefaultTransitionDuration");
assert(nativeMapViewPtr != 0);
assert(milliseconds >= 0);
assert(duration >= 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
nativeMapView->getMap().setDefaultTransitionDuration(milliseconds);
nativeMapView->getMap().setDefaultTransitionDuration(std::chrono::milliseconds(duration));
}
jlong JNICALL nativeGetDefaultTransitionDuration(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetDefaultTransitionDuration");
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
return nativeMapView->getMap().getDefaultTransitionDuration();
return std::chrono::duration_cast<std::chrono::milliseconds>(nativeMapView->getMap().getDefaultTransitionDuration()).count();
}
void JNICALL nativeSetStyleURL(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jstring url) {
@@ -423,14 +424,14 @@ nativeSetAccessToken(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jstring a
mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetAccessToken");
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
nativeMapView->getFileSource().setAccessToken(std_string_from_jstring(env, accessToken));
nativeMapView->getMap().setAccessToken(std_string_from_jstring(env, accessToken));
}
jstring JNICALL nativeGetAccessToken(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeGetAccessToken");
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
return std_string_to_jstring(env, nativeMapView->getFileSource().getAccessToken());
return std_string_to_jstring(env, nativeMapView->getMap().getAccessToken());
}
void JNICALL nativeCancelTransitions(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) {
@@ -441,15 +442,15 @@ void JNICALL nativeCancelTransitions(JNIEnv *env, jobject obj, jlong nativeMapVi
}
void JNICALL nativeMoveBy(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jdouble dx, jdouble dy,
jdouble duration) {
jlong duration) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeMoveBy");
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
nativeMapView->getMap().moveBy(dx, dy, duration);
nativeMapView->getMap().moveBy(dx, dy, std::chrono::milliseconds(duration));
}
void JNICALL nativeSetLonLat(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jobject lonLat,
jdouble duration) {
jlong duration) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetLonLat");
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
@@ -466,7 +467,7 @@ void JNICALL nativeSetLonLat(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, j
return;
}
nativeMapView->getMap().setLonLat(lon, lat, duration);
nativeMapView->getMap().setLonLat(lon, lat, std::chrono::milliseconds(duration));
}
jobject JNICALL nativeGetLonLat(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) {
@@ -507,19 +508,19 @@ void JNICALL nativeResetPosition(JNIEnv *env, jobject obj, jlong nativeMapViewPt
}
void JNICALL nativeScaleBy(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jdouble ds, jdouble cx,
jdouble cy, jdouble duration) {
jdouble cy, jlong duration) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeScaleBy");
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
nativeMapView->getMap().scaleBy(ds, cx, cy, duration);
nativeMapView->getMap().scaleBy(ds, cx, cy, std::chrono::milliseconds(duration));
}
void JNICALL nativeSetScale(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jdouble scale,
jdouble cx, jdouble cy, jdouble duration) {
jdouble cx, jdouble cy, jlong duration) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetScale");
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
nativeMapView->getMap().setScale(scale, cx, cy, duration);
nativeMapView->getMap().setScale(scale, cx, cy, std::chrono::milliseconds(duration));
}
jdouble JNICALL nativeGetScale(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) {
@@ -530,11 +531,11 @@ jdouble JNICALL nativeGetScale(JNIEnv *env, jobject obj, jlong nativeMapViewPtr)
}
void JNICALL
nativeSetZoom(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jdouble zoom, jdouble duration) {
nativeSetZoom(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jdouble zoom, jlong duration) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetZoom");
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
nativeMapView->getMap().setZoom(zoom, duration);
nativeMapView->getMap().setZoom(zoom, std::chrono::milliseconds(duration));
}
jdouble JNICALL nativeGetZoom(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) {
@@ -545,7 +546,7 @@ jdouble JNICALL nativeGetZoom(JNIEnv *env, jobject obj, jlong nativeMapViewPtr)
}
void JNICALL nativeSetLonLatZoom(JNIEnv *env, jobject obj, jlong nativeMapViewPtr,
jobject lonLatZoom, jdouble duration) {
jobject lonLatZoom, jlong duration) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetLonLatZoom");
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
@@ -568,7 +569,7 @@ void JNICALL nativeSetLonLatZoom(JNIEnv *env, jobject obj, jlong nativeMapViewPt
return;
}
nativeMapView->getMap().setLonLatZoom(lon, lat, zoom, duration);
nativeMapView->getMap().setLonLatZoom(lon, lat, zoom, std::chrono::milliseconds(duration));
}
jobject JNICALL nativeGetLonLatZoom(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) {
@@ -623,19 +624,19 @@ jdouble JNICALL nativeGetMaxZoom(JNIEnv *env, jobject obj, jlong nativeMapViewPt
}
void JNICALL nativeRotateBy(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jdouble sx,
jdouble sy, jdouble ex, jdouble ey, jdouble duration) {
jdouble sy, jdouble ex, jdouble ey, jlong duration) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeRotateBy");
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
nativeMapView->getMap().rotateBy(sx, sy, ex, ey, duration);
nativeMapView->getMap().rotateBy(sx, sy, ex, ey, std::chrono::milliseconds(duration));
}
void JNICALL nativeSetBearing(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jdouble degrees,
jdouble duration) {
jlong duration) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetBearing");
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
nativeMapView->getMap().setBearing(degrees, duration);
nativeMapView->getMap().setBearing(degrees, std::chrono::milliseconds(duration));
}
void JNICALL nativeSetBearing(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jdouble degrees,
@@ -701,8 +702,9 @@ void JNICALL
nativeSetReachability(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jboolean status) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeSetReachability");
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
nativeMapView->getFileSource().setReachability(status);
if (status) {
mbgl::NetworkStatus::Reachable();
}
}
}
@@ -889,20 +891,20 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
{"nativeGetAccessToken", "(J)Ljava/lang/String;",
reinterpret_cast<void *>(&nativeGetAccessToken)},
{"nativeCancelTransitions", "(J)V", reinterpret_cast<void *>(&nativeCancelTransitions)},
{"nativeMoveBy", "(JDDD)V", reinterpret_cast<void *>(&nativeMoveBy)},
{"nativeSetLonLat", "(JLcom/mapbox/mapboxgl/lib/LonLat;D)V",
{"nativeMoveBy", "(JDDJ)V", reinterpret_cast<void *>(&nativeMoveBy)},
{"nativeSetLonLat", "(JLcom/mapbox/mapboxgl/lib/LonLat;J)V",
reinterpret_cast<void *>(&nativeSetLonLat)},
{"nativeGetLonLat", "(J)Lcom/mapbox/mapboxgl/lib/LonLat;",
reinterpret_cast<void *>(&nativeGetLonLat)},
{"nativeStartPanning", "(J)V", reinterpret_cast<void *>(&nativeStartPanning)},
{"nativeStopPanning", "(J)V", reinterpret_cast<void *>(&nativeStopPanning)},
{"nativeResetPosition", "(J)V", reinterpret_cast<void *>(&nativeResetPosition)},
{"nativeScaleBy", "(JDDDD)V", reinterpret_cast<void *>(&nativeScaleBy)},
{"nativeSetScale", "(JDDDD)V", reinterpret_cast<void *>(&nativeSetScale)},
{"nativeScaleBy", "(JDDDJ)V", reinterpret_cast<void *>(&nativeScaleBy)},
{"nativeSetScale", "(JDDDJ)V", reinterpret_cast<void *>(&nativeSetScale)},
{"nativeGetScale", "(J)D", reinterpret_cast<void *>(&nativeGetScale)},
{"nativeSetZoom", "(JDD)V", reinterpret_cast<void *>(&nativeSetZoom)},
{"nativeSetZoom", "(JDJ)V", reinterpret_cast<void *>(&nativeSetZoom)},
{"nativeGetZoom", "(J)D", reinterpret_cast<void *>(&nativeGetZoom)},
{"nativeSetLonLatZoom", "(JLcom/mapbox/mapboxgl/lib/LonLatZoom;D)V",
{"nativeSetLonLatZoom", "(JLcom/mapbox/mapboxgl/lib/LonLatZoom;J)V",
reinterpret_cast<void *>(&nativeSetLonLatZoom)},
{"nativeGetLonLatZoom", "(J)Lcom/mapbox/mapboxgl/lib/LonLatZoom;",
reinterpret_cast<void *>(&nativeGetLonLatZoom)},
@@ -911,10 +913,10 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
{"nativeStopPanning", "(J)V", reinterpret_cast<void *>(&nativeStopScaling)},
{"nativeGetMinZoom", "(J)D", reinterpret_cast<void *>(&nativeGetMinZoom)},
{"nativeGetMaxZoom", "(J)D", reinterpret_cast<void *>(&nativeGetMaxZoom)},
{"nativeRotateBy", "(JDDDDD)V", reinterpret_cast<void *>(&nativeRotateBy)},
{"nativeSetBearing", "(JDD)V",
{"nativeRotateBy", "(JDDDDJ)V", reinterpret_cast<void *>(&nativeRotateBy)},
{"nativeSetBearing", "(JDJ)V",
reinterpret_cast<void *>(
static_cast<void JNICALL (*)(JNIEnv *, jobject, jlong, jdouble, jdouble)>(
static_cast<void JNICALL (*)(JNIEnv *, jobject, jlong, jdouble, jlong)>(
&nativeSetBearing))},
{"nativeSetBearing", "(JDDD)V",
reinterpret_cast<void *>(

View File

@@ -54,7 +54,8 @@ void log_gl_string(GLenum name, const char *label) {
NativeMapView::NativeMapView(JNIEnv *env, jobject obj_)
: mbgl::View(*this),
fileSource(mbgl::platform::defaultCacheDatabase()),
fileCache(mbgl::android::cachePath + "/mbgl-cache.db"),
fileSource(&fileCache),
map(*this, fileSource) {
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::NativeMapView");
@@ -140,7 +141,7 @@ void NativeMapView::notify() {
mbgl::Map &NativeMapView::getMap() { return map; }
mbgl::CachingHTTPFileSource &NativeMapView::getFileSource() { return fileSource; }
mbgl::DefaultFileSource &NativeMapView::getFileSource() { return fileSource; }
bool NativeMapView::inEmulator() {
// Detect if we are in emulator
@@ -718,7 +719,7 @@ void NativeMapView::resume() {
}
}
void NativeMapView::notifyMapChange(mbgl::MapChange, mbgl::timestamp) {
void NativeMapView::notifyMapChange(mbgl::MapChange, std::chrono::steady_clock::duration) {
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::notifyMapChange()");
assert(vm != nullptr);

View File

@@ -46,6 +46,9 @@ public class MapView extends SurfaceView {
// Tag used for logging
private static final String TAG = "MapView";
// Used for animation
private static final long ANIMATION_DURATION = 300;
// Used for saving instance state
private static final String STATE_CENTER_COORDINATE = "centerCoordinate";
private static final String STATE_CENTER_DIRECTION = "centerDirection";
@@ -188,7 +191,7 @@ public class MapView extends SurfaceView {
if (!isInEditMode()) {
if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH)) {
mZoomButtonsController = new ZoomButtonsController(this);
mZoomButtonsController.setZoomSpeed(300);
mZoomButtonsController.setZoomSpeed(ANIMATION_DURATION);
mZoomButtonsController.setOnZoomListener(new OnZoomListener());
}
@@ -213,7 +216,7 @@ public class MapView extends SurfaceView {
}
public void setCenterCoordinate(LonLat centerCoordinate, boolean animated) {
double duration = animated ? 0.3 : 0.0;
long duration = animated ? ANIMATION_DURATION : 0;
mNativeMapView.setLonLat(centerCoordinate, duration);
}
@@ -223,7 +226,7 @@ public class MapView extends SurfaceView {
public void setCenterCoordinate(LonLatZoom centerCoordinate,
boolean animated) {
double duration = animated ? 0.3 : 0.0;
long duration = animated ? ANIMATION_DURATION : 0;
mNativeMapView.setLonLatZoom(centerCoordinate, duration);
}
@@ -243,8 +246,7 @@ public class MapView extends SurfaceView {
}
public void setDirection(double direction, boolean animated) {
double duration = animated ? 0.3 : 0.0;
long duration = animated ? ANIMATION_DURATION : 0;
mNativeMapView.setBearing(-direction, duration);
}
@@ -265,7 +267,7 @@ public class MapView extends SurfaceView {
}
public void setZoomLevel(double zoomLevel, boolean animated) {
double duration = animated ? 0.3 : 0.0;
long duration = animated ? ANIMATION_DURATION : 0;
mNativeMapView.setZoom(zoomLevel, duration);
}
@@ -565,10 +567,10 @@ public class MapView extends SurfaceView {
mNativeMapView.cancelTransitions();
if (zoomIn) {
mNativeMapView.scaleBy(2.0, x / mScreenDensity, y / mScreenDensity, 0.3);
mNativeMapView.scaleBy(2.0, x / mScreenDensity, y / mScreenDensity, ANIMATION_DURATION);
} else {
// TODO two finger tap zoom out
mNativeMapView.scaleBy(0.5, x / mScreenDensity, y / mScreenDensity, 0.3);
mNativeMapView.scaleBy(0.5, x / mScreenDensity, y / mScreenDensity, ANIMATION_DURATION);
}
}
@@ -695,7 +697,7 @@ public class MapView extends SurfaceView {
// Cancel any animation
mNativeMapView.cancelTransitions();
mNativeMapView.moveBy(velocityX * duration / 2.0 / mScreenDensity, velocityY * duration / 2.0 / mScreenDensity, duration);
mNativeMapView.moveBy(velocityX * duration / 2.0 / mScreenDensity, velocityY * duration / 2.0 / mScreenDensity, (long)(duration * 1000.0f));
return true;
}

View File

@@ -234,18 +234,18 @@ class NativeMapView {
}
public void moveBy(double dx, double dy) {
moveBy(dx, dy, 0.0);
moveBy(dx, dy, 0);
}
public void moveBy(double dx, double dy, double duration) {
public void moveBy(double dx, double dy, long duration) {
nativeMoveBy(mNativeMapViewPtr, dx, dy, duration);
}
public void setLonLat(LonLat lonLat) {
setLonLat(lonLat, 0.0);
setLonLat(lonLat, 0);
}
public void setLonLat(LonLat lonLat, double duration) {
public void setLonLat(LonLat lonLat, long duration) {
nativeSetLonLat(mNativeMapViewPtr, lonLat, duration);
}
@@ -270,10 +270,10 @@ class NativeMapView {
}
public void scaleBy(double ds, double cx, double cy) {
scaleBy(ds, cx, cy, 0.0);
scaleBy(ds, cx, cy, 0);
}
public void scaleBy(double ds, double cx, double cy, double duration) {
public void scaleBy(double ds, double cx, double cy, long duration) {
nativeScaleBy(mNativeMapViewPtr, ds, cx, cy, duration);
}
@@ -282,10 +282,10 @@ class NativeMapView {
}
public void setScale(double scale, double cx, double cy) {
setScale(scale, cx, cy, 0.0);
setScale(scale, cx, cy, 0);
}
public void setScale(double scale, double cx, double cy, double duration) {
public void setScale(double scale, double cx, double cy, long duration) {
nativeSetScale(mNativeMapViewPtr, scale, cx, cy, duration);
}
@@ -294,10 +294,10 @@ class NativeMapView {
}
public void setZoom(double zoom) {
setZoom(zoom, 0.0);
setZoom(zoom, 0);
}
public void setZoom(double zoom, double duration) {
public void setZoom(double zoom, long duration) {
nativeSetZoom(mNativeMapViewPtr, zoom, duration);
}
@@ -306,10 +306,10 @@ class NativeMapView {
}
public void setLonLatZoom(LonLatZoom lonLatZoom) {
setLonLatZoom(lonLatZoom, 0.0);
setLonLatZoom(lonLatZoom, 0);
}
public void setLonLatZoom(LonLatZoom lonLatZoom, double duration) {
public void setLonLatZoom(LonLatZoom lonLatZoom, long duration) {
nativeSetLonLatZoom(mNativeMapViewPtr, lonLatZoom, duration);
}
@@ -338,19 +338,19 @@ class NativeMapView {
}
public void rotateBy(double sx, double sy, double ex, double ey) {
rotateBy(sx, sy, ex, ey, 0.0);
rotateBy(sx, sy, ex, ey, 0);
}
public void rotateBy(double sx, double sy, double ex, double ey,
double duration) {
long duration) {
nativeRotateBy(mNativeMapViewPtr, sx, sy, ex, ey, duration);
}
public void setBearing(double degrees) {
setBearing(degrees, 0.0);
setBearing(degrees, 0);
}
public void setBearing(double degrees, double duration) {
public void setBearing(double degrees, long duration) {
nativeSetBearing(mNativeMapViewPtr, degrees, duration);
}
@@ -468,7 +468,7 @@ class NativeMapView {
private native List<String> nativeGetClasses(long nativeMapViewPtr);
private native void nativeSetDefaultTransitionDuration(
long nativeMapViewPtr, long milliseconds);
long nativeMapViewPtr, long duration);
private native long nativeGetDefaultTransitionDuration(long nativeMapViewPtr);
@@ -486,10 +486,10 @@ class NativeMapView {
private native void nativeCancelTransitions(long nativeMapViewPtr);
private native void nativeMoveBy(long nativeMapViewPtr, double dx,
double dy, double duration);
double dy, long duration);
private native void nativeSetLonLat(long nativeMapViewPtr, LonLat lonLat,
double duration);
long duration);
private native LonLat nativeGetLonLat(long nativeMapViewPtr);
@@ -500,20 +500,20 @@ class NativeMapView {
private native void nativeResetPosition(long nativeMapViewPtr);
private native void nativeScaleBy(long nativeMapViewPtr, double ds,
double cx, double cy, double duration);
double cx, double cy, long duration);
private native void nativeSetScale(long nativeMapViewPtr, double scale,
double cx, double cy, double duration);
double cx, double cy, long duration);
private native double nativeGetScale(long nativeMapViewPtr);
private native void nativeSetZoom(long nativeMapViewPtr, double zoom,
double duration);
long duration);
private native double nativeGetZoom(long nativeMapViewPtr);
private native void nativeSetLonLatZoom(long nativeMapViewPtr,
LonLatZoom lonLatZoom, double duration);
LonLatZoom lonLatZoom, long duration);
private native LonLatZoom nativeGetLonLatZoom(long nativeMapViewPtr);
@@ -528,10 +528,10 @@ class NativeMapView {
private native double nativeGetMaxZoom(long nativeMapViewPtr);
private native void nativeRotateBy(long nativeMapViewPtr, double sx,
double sy, double ex, double ey, double duration);
double sy, double ex, double ey, long duration);
private native void nativeSetBearing(long nativeMapViewPtr, double degrees,
double duration);
long duration);
private native void nativeSetBearing(long nativeMapViewPtr, double degrees,
double cx, double cy);

View File

@@ -3,16 +3,26 @@
'../gyp/common.gypi',
],
'targets': [
{
'target_name': 'androidapp',
{ 'target_name': 'android-lib',
'product_name': 'mapbox-gl',
'type': 'shared_library',
'hard_dependency': 1,
'dependencies': [
'../mbgl.gyp:core',
'../mbgl.gyp:platform-<(platform_lib)',
'../mbgl.gyp:http-<(http_lib)',
'../mbgl.gyp:asset-<(asset_lib)',
'../mbgl.gyp:cache-<(cache_lib)',
],
'sources': [
'./cpp/native_map_view.cpp',
'./cpp/jni.cpp',
],
'cflags_cc': [
'-I<(boost_root)/include',
'<@(boost_cflags)',
],
'libraries': [
'<@(openssl_static_libs)',
@@ -50,15 +60,35 @@
'libraries': [ '<@(ldflags)' ],
}]
],
'dependencies': [
'../mapboxgl.gyp:mbgl-standalone',
'../mapboxgl.gyp:mbgl-android',
'../mapboxgl.gyp:copy_certificate_bundle',
},
{ 'target_name': 'androidapp',
'type': 'none',
'hard_dependency': 1,
'variables': {
'pwd': '<!(pwd)',
},
'copies': [
{
'files': [
'../common/ca-bundle.crt',
'../styles/styles'
],
'destination': '<(pwd)/java/lib/src/main/assets'
},
],
'actions': [
{
'action_name': 'Strip dynamic library',
'inputs': [ '<(PRODUCT_DIR)/lib.target/libmapbox-gl.so' ],
'outputs': [ '<(pwd)/java/lib/src/main/jniLibs/$(JNIDIR)/libmapbox-gl.so' ],
'action': [ '$(STRIP)', '<@(_inputs)', '-o', '<@(_outputs)' ]
},
],
'copies': [{
'files': [ '../styles' ],
'destination': '<(PRODUCT_DIR)'
}],
},
],
}

View File

@@ -7,8 +7,6 @@ NAME=$1
export JOBS=2
export CC=clang CXX=clang++
export CXXFLAGS="-Wno-unknown-warning-option -Wno-unused-local-typedefs -Wno-unknown-pragmas ${CXXFLAGS}";
export MASON_PLATFORM=android
mkdir ./android/java/app/src/main/res/raw/

View File

@@ -34,6 +34,7 @@ user_data="#!/bin/bash
export TESTMUNK_KEY=$TESTMUNK_KEY
export TESTMUNK=$TESTMUNK
export MASON_ANDROID_ABI=$MASON_ANDROID_ABI
export ANDROID_ABI=$MASON_ANDROID_ABI
if ./android/scripts/build-$CONFIG.sh $NAME &>../build.log; then
echo 'ANDROID BUILD PASSED'

View File

@@ -9,7 +9,8 @@
#include <mbgl/platform/default/headless_view.hpp>
#include <mbgl/platform/default/headless_display.hpp>
#include <mbgl/storage/caching_http_file_source.hpp>
#include <mbgl/storage/default_file_source.hpp>
#include <mbgl/storage/default/sqlite_cache.hpp>
#if __APPLE__
#include <mbgl/platform/darwin/log_nslog.hpp>
@@ -35,7 +36,7 @@ int main(int argc, char *argv[]) {
int height = 256;
double pixelRatio = 1.0;
std::string output = "out.png";
std::string cache = "cache.sqlite";
std::string cache_file = "cache.sqlite";
std::vector<std::string> classes;
std::string token;
@@ -51,7 +52,7 @@ int main(int argc, char *argv[]) {
("class,c", po::value(&classes)->value_name("name"), "Class name")
("token,t", po::value(&token)->value_name("key")->default_value(token), "Mapbox access token")
("output,o", po::value(&output)->value_name("file")->default_value(output), "Output file name")
("cache,d", po::value(&cache)->value_name("file")->default_value(cache), "Cache database file name")
("cache,d", po::value(&cache_file)->value_name("file")->default_value(cache_file), "Cache database file name")
;
try {
@@ -74,7 +75,8 @@ int main(int argc, char *argv[]) {
Log::Set<StderrLogBackend>();
#endif
CachingHTTPFileSource fileSource(cache);
mbgl::SQLiteCache cache(cache_file);
mbgl::DefaultFileSource fileSource(&cache);
// Try to load the token from the environment.
if (!token.size()) {
@@ -84,14 +86,15 @@ int main(int argc, char *argv[]) {
}
}
// Set access token if present
if (token.size()) {
fileSource.setAccessToken(std::string(token));
}
HeadlessView view;
Map map(view, fileSource);
// Set access token if present
if (token.size()) {
map.setAccessToken(std::string(token));
}
map.setStyleJSON(style, ".");
map.setClasses(classes);

View File

@@ -3,51 +3,54 @@
'../gyp/common.gypi',
],
'targets': [
{
'target_name': 'mbgl-render',
{ 'target_name': 'mbgl-render',
'product_name': 'mbgl-render',
'type': 'executable',
'dependencies': [
'../mbgl.gyp:core',
'../mbgl.gyp:platform-<(platform_lib)',
'../mbgl.gyp:headless-<(headless_lib)',
'../mbgl.gyp:http-<(http_lib)',
'../mbgl.gyp:asset-<(asset_lib)',
'../mbgl.gyp:cache-<(cache_lib)',
'../mbgl.gyp:copy_certificate_bundle',
],
'include_dirs': [
'../src',
],
'sources': [
'./render.cpp',
],
'variables' : {
'cflags': [
'<@(uv_cflags)',
'<@(png_cflags)',
'-I<(boost_root)/include',
'cflags_cc': [
'<@(glfw3_cflags)',
'<@(boost_cflags)',
],
'ldflags': [
'<@(glfw3_ldflags)',
'<@(uv_ldflags)',
'<@(sqlite3_static_libs)',
'<@(sqlite3_ldflags)',
'<@(curl_ldflags)',
'<@(png_ldflags)',
'<@(uv_static_libs)',
'-L<(boost_root)/lib',
'<@(boost_ldflags)',
'-lboost_program_options'
],
'libraries': [
'<@(glfw3_static_libs)',
],
},
'conditions': [
# add libuv include path and OpenGL libs
['OS == "mac"',
{
'xcode_settings': {
'OTHER_CPLUSPLUSFLAGS': ['<@(cflags)'],
'OTHER_LDFLAGS': ['<@(ldflags)'],
},
},
{
'cflags': ['<@(cflags)'],
'libraries': ['<@(ldflags)'],
}],
],
'include_dirs': [ '../src' ],
'dependencies': [
'../mapboxgl.gyp:mbgl-standalone',
'../mapboxgl.gyp:mbgl-headless',
'../mapboxgl.gyp:mbgl-<(platform)',
'../mapboxgl.gyp:copy_certificate_bundle',
['OS == "mac"', {
'libraries': [ '<@(libraries)' ],
'xcode_settings': {
'OTHER_CPLUSPLUSFLAGS': [ '<@(cflags_cc)' ],
'OTHER_LDFLAGS': [ '<@(ldflags)' ],
}
}, {
'cflags_cc': [ '<@(cflags_cc)' ],
'libraries': [ '<@(libraries)', '<@(ldflags)' ],
}]
],
},
],

67
config/defaults.mk Normal file
View File

@@ -0,0 +1,67 @@
#### Configuration defaults ####################################################
ENV_osx = MASON_PLATFORM=osx
CONFIG_osx = -Dhost=osx -Iconfig/osx.gypi -Dinstall_prefix=$(PREFIX)
LIBS_osx = -Dheadless_lib=$(word 1,$(HEADLESS) cgl)
LIBS_osx += -Dplatform_lib=$(word 1,$(PLATFORM) osx)
LIBS_osx += -Dasset_lib=$(word 1,$(ASSET) fs)
LIBS_osx += -Dhttp_lib=$(word 1,$(HTTP) nsurl)
LIBS_osx += -Dcache_lib=$(word 1,$(CACHE) sqlite)
LIBS_osx += --depth=. -Goutput_dir=.
ENV_ios = MASON_PLATFORM=ios
CONFIG_ios = -Dhost=ios -Iconfig/ios.gypi -Dinstall_prefix=$(PREFIX)
LIBS_ios = -Dheadless_lib=none
LIBS_ios += -Dplatform_lib=$(word 1,$(PLATFORM) ios)
LIBS_ios += -Dasset_lib=$(word 1,$(ASSET) fs)
LIBS_ios += -Dhttp_lib=$(word 1,$(HTTP) nsurl)
LIBS_ios += -Dcache_lib=$(word 1,$(CACHE) sqlite)
LIBS_ios += --depth=. -Goutput_dir=.
ENV_linux = MASON_PLATFORM=linux
CONFIG_linux = -Dhost=linux -Iconfig/linux.gypi -Dinstall_prefix=$(PREFIX)
LIBS_linux = -Dheadless_lib=$(word 1,$(HEADLESS) glx)
LIBS_linux += -Dplatform_lib=$(word 1,$(PLATFORM) linux)
LIBS_linux += -Dasset_lib=$(word 1,$(ASSET) fs)
LIBS_linux += -Dhttp_lib=$(word 1,$(HTTP) curl)
LIBS_linux += -Dcache_lib=$(word 1,$(CACHE) sqlite)
LIBS_linux += --depth=. -Goutput_dir=.
ANDROID_ABIS += android-lib-arm-v8
ENV_android-arm-v8 = $(shell MASON_ANDROID_ABI=arm-v8 ./scripts/android_env.sh)
CONFIG_android-arm-v8 = -Dhost=android -Iconfig/android-arm-v8.gypi
ANDROID_ABIS += android-lib-arm-v7
ENV_android-arm-v7 = $(shell MASON_ANDROID_ABI=arm-v7 ./scripts/android_env.sh)
CONFIG_android-arm-v7 = -Dhost=android -Iconfig/android-arm-v7.gypi
ANDROID_ABIS += android-lib-arm-v5
ENV_android-arm-v5 = $(shell MASON_ANDROID_ABI=arm-v5 ./scripts/android_env.sh)
CONFIG_android-arm-v5 = -Dhost=android -Iconfig/android-arm-v5.gypi
ANDROID_ABIS += android-lib-x86
ENV_android-x86 = $(shell MASON_ANDROID_ABI=x86 ./scripts/android_env.sh)
CONFIG_android-x86 = -Dhost=android -Iconfig/android-x86.gypi
# OpenSSL build is incomplete.
# ANDROID_ABIS += android-lib-x86-64
# ENV_android-x86-64 = $(shell MASON_ANDROID_ABI=x86-64 ./scripts/android_env.sh)
# CONFIG_android-x86-64 = -Dhost=android -Iconfig/android-x86-64.gypi
ANDROID_ABIS += android-lib-mips
ENV_android-mips = $(shell MASON_ANDROID_ABI=mips ./scripts/android_env.sh)
CONFIG_android-mips = -Dhost=android -Iconfig/android-mips.gypi
ANDROID_ABIS += android-lib-mips-64
ENV_android-mips-64 = $(shell MASON_ANDROID_ABI=mips-64 ./scripts/android_env.sh)
CONFIG_android-mips-64 = -Dhost=android -Iconfig/android-mips-64.gypi
LIBS_android = -Dheadless_lib=none
LIBS_android += -Dplatform_lib=$(word 1,$(PLATFORM) android)
LIBS_android += -Dasset_lib=$(word 1,$(ASSET) zip)
LIBS_android += -Dhttp_lib=$(word 1,$(HTTP) curl)
LIBS_android += -Dcache_lib=$(word 1,$(CACHE) sqlite)
LIBS_android += --depth=. -Goutput_dir=.

83
configure vendored
View File

@@ -3,7 +3,7 @@
set -e
set -o pipefail
CONFIG_FILE=${1:-config.gypi}
CONFIG_FILE=$1
if [ `uname -s` = 'Darwin' ]; then
MASON_PLATFORM=${MASON_PLATFORM:-osx}
@@ -46,11 +46,24 @@ case ${MASON_PLATFORM} in
ZLIB_VERSION=system
BOOST_VERSION=system
NUNICODE_VERSION=1.5.1
LIBZIP_VERSION=0.11.2
;;
esac
function abort { >&2 echo -e "\033[1m\033[31m$1\033[0m"; exit 1; }
if [ -z ${CONFIG_FILE} ]; then
abort 'You need to specify an output path for the configuration file'
fi
if [[ ${MASON_PLATFORM} = 'android' && -z ${MASON_ANDROID_ABI} ]]; then
abort 'You need to specify an ABI for android platforms'
fi
echo -n "MASON_PLATFORM=${MASON_PLATFORM} "
if [ ${MASON_PLATFORM} = 'android' ]; then echo -n "MASON_ANDROID_ABI=${MASON_ANDROID_ABI} " ; fi
echo $0 $@
PYTHON=`which python || abort 'Cannot find python'`
>&2 echo -en "\033[1m\033[32m* Using "
@@ -72,7 +85,7 @@ LN=$'\n'
CONFIG="# Do not edit. Generated by the configure script.
{
'target_defaults': {
'cflags': [],
'cflags%': [],
'default_configuration': 'Release',
'defines': [],
'include_dirs': [],
@@ -84,79 +97,78 @@ CONFIG="# Do not edit. Generated by the configure script.
if [ ! -z ${BOOST_VERSION} ]; then
mason install boost ${BOOST_VERSION}
CONFIG+=" 'boost_root': '$(mason prefix boost ${BOOST_VERSION})',"$LN
CONFIG+=" 'boost_cflags%': $(quote_flags $(mason cflags boost ${BOOST_VERSION})),"$LN
CONFIG+=" 'boost_ldflags%': $(quote_flags $(mason ldflags boost ${BOOST_VERSION})),"$LN
fi
if [ ! -z ${OPENSSL_VERSION} ]; then
mason install openssl ${OPENSSL_VERSION}
CONFIG+=" 'openssl_static_libs': $(quote_flags $(mason static_libs openssl ${OPENSSL_VERSION})),"$LN
CONFIG+=" 'openssl_cflags': $(quote_flags $(mason cflags openssl ${OPENSSL_VERSION})),"$LN
CONFIG+=" 'openssl_ldflags': $(quote_flags $(mason ldflags openssl ${OPENSSL_VERSION})),"$LN
CONFIG+=" 'openssl_static_libs%': $(quote_flags $(mason static_libs openssl ${OPENSSL_VERSION})),"$LN
CONFIG+=" 'openssl_cflags%': $(quote_flags $(mason cflags openssl ${OPENSSL_VERSION})),"$LN
CONFIG+=" 'openssl_ldflags%': $(quote_flags $(mason ldflags openssl ${OPENSSL_VERSION})),"$LN
fi
if [ ! -z ${LIBCURL_VERSION} ]; then
mason install libcurl ${LIBCURL_VERSION}
CONFIG+=" 'curl_static_libs': $(quote_flags $(mason static_libs libcurl ${LIBCURL_VERSION})),"$LN
CONFIG+=" 'curl_cflags': $(quote_flags $(mason cflags libcurl ${LIBCURL_VERSION})),"$LN
CONFIG+=" 'curl_ldflags': $(quote_flags $(mason ldflags libcurl ${LIBCURL_VERSION})),"$LN
else
CONFIG+=" 'curl_static_libs': [],"$LN
CONFIG+=" 'curl_static_libs%': $(quote_flags $(mason static_libs libcurl ${LIBCURL_VERSION})),"$LN
CONFIG+=" 'curl_cflags%': $(quote_flags $(mason cflags libcurl ${LIBCURL_VERSION})),"$LN
CONFIG+=" 'curl_ldflags%': $(quote_flags $(mason ldflags libcurl ${LIBCURL_VERSION})),"$LN
fi
if [ ! -z ${GLFW_VERSION} ]; then
mason install glfw ${GLFW_VERSION}
CONFIG+=" 'glfw3_static_libs': $(quote_flags $(mason static_libs glfw ${GLFW_VERSION})),"$LN
CONFIG+=" 'glfw3_cflags': $(quote_flags $(mason cflags glfw ${GLFW_VERSION})),"$LN
CONFIG+=" 'glfw3_ldflags': $(quote_flags $(mason ldflags glfw ${GLFW_VERSION})),"$LN
CONFIG+=" 'glfw3_static_libs%': $(quote_flags $(mason static_libs glfw ${GLFW_VERSION})),"$LN
CONFIG+=" 'glfw3_cflags%': $(quote_flags $(mason cflags glfw ${GLFW_VERSION})),"$LN
CONFIG+=" 'glfw3_ldflags%': $(quote_flags $(mason ldflags glfw ${GLFW_VERSION})),"$LN
fi
if [ ! -z ${LIBPNG_VERSION} ]; then
mason install libpng ${LIBPNG_VERSION}
CONFIG+=" 'png_static_libs': $(quote_flags $(mason static_libs libpng ${LIBPNG_VERSION})),"$LN
CONFIG+=" 'png_cflags': $(quote_flags $(mason cflags libpng ${LIBPNG_VERSION})),"$LN
CONFIG+=" 'png_ldflags': $(quote_flags $(mason ldflags libpng ${LIBPNG_VERSION})),"$LN
CONFIG+=" 'png_static_libs%': $(quote_flags $(mason static_libs libpng ${LIBPNG_VERSION})),"$LN
CONFIG+=" 'png_cflags%': $(quote_flags $(mason cflags libpng ${LIBPNG_VERSION})),"$LN
CONFIG+=" 'png_ldflags%': $(quote_flags $(mason ldflags libpng ${LIBPNG_VERSION})),"$LN
fi
if [ ! -z ${LIBJPEG_VERSION} ]; then
mason install jpeg ${LIBJPEG_VERSION}
CONFIG+=" 'jpeg_static_libs': $(quote_flags $(mason static_libs jpeg ${LIBJPEG_VERSION})),"$LN
CONFIG+=" 'jpeg_cflags': $(quote_flags $(mason cflags jpeg ${LIBJPEG_VERSION})),"$LN
CONFIG+=" 'jpeg_ldflags': $(quote_flags $(mason ldflags jpeg ${LIBJPEG_VERSION})),"$LN
CONFIG+=" 'jpeg_static_libs%': $(quote_flags $(mason static_libs jpeg ${LIBJPEG_VERSION})),"$LN
CONFIG+=" 'jpeg_cflags%': $(quote_flags $(mason cflags jpeg ${LIBJPEG_VERSION})),"$LN
CONFIG+=" 'jpeg_ldflags%': $(quote_flags $(mason ldflags jpeg ${LIBJPEG_VERSION})),"$LN
fi
if [ ! -z ${SQLITE_VERSION} ]; then
mason install sqlite ${SQLITE_VERSION}
CONFIG+=" 'sqlite3_static_libs': $(quote_flags $(mason static_libs sqlite ${SQLITE_VERSION})),"$LN
CONFIG+=" 'sqlite3_cflags': $(quote_flags $(mason cflags sqlite ${SQLITE_VERSION})),"$LN
CONFIG+=" 'sqlite3_ldflags': $(quote_flags $(mason ldflags sqlite ${SQLITE_VERSION})),"$LN
CONFIG+=" 'sqlite3_static_libs%': $(quote_flags $(mason static_libs sqlite ${SQLITE_VERSION})),"$LN
CONFIG+=" 'sqlite3_cflags%': $(quote_flags $(mason cflags sqlite ${SQLITE_VERSION})),"$LN
CONFIG+=" 'sqlite3_ldflags%': $(quote_flags $(mason ldflags sqlite ${SQLITE_VERSION})),"$LN
fi
if [ ! -z ${LIBUV_VERSION} ]; then
mason install libuv ${LIBUV_VERSION}
CONFIG+=" 'uv_static_libs': $(quote_flags $(mason static_libs libuv ${LIBUV_VERSION})),"$LN
CONFIG+=" 'uv_cflags': $(quote_flags $(mason cflags libuv ${LIBUV_VERSION})),"$LN
CONFIG+=" 'uv_ldflags': $(quote_flags $(mason ldflags libuv ${LIBUV_VERSION})),"$LN
CONFIG+=" 'uv_static_libs%': $(quote_flags $(mason static_libs libuv ${LIBUV_VERSION})),"$LN
CONFIG+=" 'uv_cflags%': $(quote_flags $(mason cflags libuv ${LIBUV_VERSION})),"$LN
CONFIG+=" 'uv_ldflags%': $(quote_flags $(mason ldflags libuv ${LIBUV_VERSION})),"$LN
fi
if [ ! -z ${ZLIB_VERSION} ]; then
mason install zlib ${ZLIB_VERSION}
CONFIG+=" 'zlib_static_libs': $(quote_flags $(mason static_libs zlib ${ZLIB_VERSION})),"$LN
CONFIG+=" 'zlib_cflags': $(quote_flags $(mason cflags zlib ${ZLIB_VERSION})),"$LN
CONFIG+=" 'zlib_ldflags': $(quote_flags $(mason ldflags zlib ${ZLIB_VERSION})),"$LN
CONFIG+=" 'zlib_static_libs%': $(quote_flags $(mason static_libs zlib ${ZLIB_VERSION})),"$LN
CONFIG+=" 'zlib_cflags%': $(quote_flags $(mason cflags zlib ${ZLIB_VERSION})),"$LN
CONFIG+=" 'zlib_ldflags%': $(quote_flags $(mason ldflags zlib ${ZLIB_VERSION})),"$LN
fi
if [ ! -z ${NUNICODE_VERSION} ]; then
mason install nunicode ${NUNICODE_VERSION}
CONFIG+=" 'nu_static_libs': $(quote_flags $(mason static_libs nunicode ${NUNICODE_VERSION})),"$LN
CONFIG+=" 'nu_cflags': $(quote_flags $(mason cflags nunicode ${NUNICODE_VERSION})),"$LN
CONFIG+=" 'nu_ldflags': $(quote_flags $(mason ldflags nunicode ${NUNICODE_VERSION})),"$LN
CONFIG+=" 'nu_static_libs%': $(quote_flags $(mason static_libs nunicode ${NUNICODE_VERSION})),"$LN
CONFIG+=" 'nu_cflags%': $(quote_flags $(mason cflags nunicode ${NUNICODE_VERSION})),"$LN
CONFIG+=" 'nu_ldflags%': $(quote_flags $(mason ldflags nunicode ${NUNICODE_VERSION})),"$LN
fi
if [ ! -z ${LIBZIP_VERSION} ]; then
mason install libzip ${LIBZIP_VERSION}
CONFIG+=" 'zip_static_libs': $(quote_flags $(mason static_libs libzip ${LIBZIP_VERSION})),"$LN
CONFIG+=" 'zip_cflags': $(quote_flags $(mason cflags libzip ${LIBZIP_VERSION})),"$LN
CONFIG+=" 'zip_ldflags': $(quote_flags $(mason ldflags libzip ${LIBZIP_VERSION})),"$LN
CONFIG+=" 'zip_static_libs%': $(quote_flags $(mason static_libs libzip ${LIBZIP_VERSION})),"$LN
CONFIG+=" 'zip_cflags%': $(quote_flags $(mason cflags libzip ${LIBZIP_VERSION})),"$LN
CONFIG+=" 'zip_ldflags%': $(quote_flags $(mason ldflags libzip ${LIBZIP_VERSION})),"$LN
fi
CONFIG+=" }
@@ -164,5 +176,4 @@ CONFIG+=" }
"
echo "${CONFIG}" > ${CONFIG_FILE}
cat ${CONFIG_FILE}

52
gyp/asset-fs.gypi Normal file
View File

@@ -0,0 +1,52 @@
{
'targets': [
{ 'target_name': 'asset-fs',
'product_name': 'mbgl-asset-fs',
'type': 'static_library',
'standalone_static_library': 1,
'hard_dependency': 1,
'sources': [
'../platform/default/asset_request_fs.cpp',
],
'include_dirs': [
'../include',
],
'variables': {
'cflags_cc': [
'<@(uv_cflags)',
'<@(boost_cflags)',
],
'ldflags': [
'<@(uv_ldflags)',
],
'libraries': [
'<@(uv_static_libs)',
],
},
'conditions': [
['OS == "mac"', {
'xcode_settings': {
'OTHER_CPLUSPLUSFLAGS': [ '<@(cflags_cc)' ],
},
}, {
'cflags_cc': [ '<@(cflags_cc)' ],
}],
],
'link_settings': {
'conditions': [
['OS == "mac"', {
'libraries': [ '<@(libraries)' ],
'xcode_settings': { 'OTHER_LDFLAGS': [ '<@(ldflags)' ] }
}, {
'libraries': [ '<@(libraries)', '<@(ldflags)' ],
}]
],
},
},
],
}

62
gyp/asset-zip.gypi Normal file
View File

@@ -0,0 +1,62 @@
{
'targets': [
{ 'target_name': 'asset-zip',
'product_name': 'mbgl-asset-zip',
'type': 'static_library',
'standalone_static_library': 1,
'hard_dependency': 1,
'sources': [
'../platform/default/asset_request_zip.cpp',
'../platform/default/uv_zip.c',
],
'include_dirs': [
'../include',
],
'variables': {
'cflags': [
'<@(uv_cflags)',
'<@(zip_cflags)',
],
'cflags_cc': [
'<@(uv_cflags)',
'<@(zip_cflags)',
'<@(boost_cflags)',
],
'ldflags': [
'<@(uv_ldflags)',
'<@(zip_ldflags)',
],
'libraries': [
'<@(uv_static_libs)',
'<@(zip_static_libs)',
],
},
'conditions': [
['OS == "mac"', {
'xcode_settings': {
'OTHER_CFLAGS': [ '<@(cflags)' ],
'OTHER_CPLUSPLUSFLAGS': [ '<@(cflags_cc)' ],
},
}, {
'cflags': [ '<@(cflags)' ],
'cflags_cc': [ '<@(cflags_cc)' ],
}],
],
'link_settings': {
'conditions': [
['OS == "mac"', {
'libraries': [ '<@(libraries)' ],
'xcode_settings': { 'OTHER_LDFLAGS': [ '<@(ldflags)' ] }
}, {
'libraries': [ '<@(libraries)', '<@(ldflags)' ],
}]
],
},
},
],
}

64
gyp/cache-sqlite.gypi Normal file
View File

@@ -0,0 +1,64 @@
{
'targets': [
{ 'target_name': 'cache-sqlite',
'product_name': 'mbgl-cache-sqlite',
'type': 'static_library',
'standalone_static_library': 1,
'hard_dependency': 1,
'sources': [
'../platform/default/sqlite_cache.cpp',
'../platform/default/sqlite3.hpp',
'../platform/default/sqlite3.cpp',
'../platform/default/compression.hpp',
'../platform/default/compression.cpp',
],
'include_dirs': [
'../include',
],
'variables': {
'cflags_cc': [
'<@(uv_cflags)',
'<@(sqlite3_cflags)',
],
'ldflags': [
'<@(uv_ldflags)',
'<@(sqlite3_ldflags)',
'<@(zlib_ldflags)',
],
'libraries': [
'<@(uv_static_libs)',
'<@(sqlite3_static_libs)',
'<@(zlib_static_libs)',
],
},
'conditions': [
['OS == "mac"', {
'xcode_settings': {
'OTHER_CPLUSPLUSFLAGS': [ '<@(cflags_cc)' ],
},
}, {
'cflags_cc': [ '<@(cflags_cc)' ],
}],
],
'link_settings': {
'conditions': [
['OS == "mac"', {
'libraries': [ '<@(libraries)' ],
'xcode_settings': { 'OTHER_LDFLAGS': [ '<@(ldflags)' ] }
}, {
'libraries': [ '<@(libraries)', '<@(ldflags)' ],
}]
],
},
'direct_dependent_settings': {
'include_dirs': [ '../include' ],
},
},
],
}

View File

@@ -1,19 +1,18 @@
{
'variables': {
'install_prefix%': '',
'standalone_product_dir':'<!@(pwd)/build'
},
'target_defaults': {
'default_configuration': 'Release',
'conditions': [
['OS=="mac"', {
'xcode_settings': {
'MACOSX_DEPLOYMENT_TARGET':'10.9',
'MACOSX_DEPLOYMENT_TARGET': '10.9',
'CLANG_CXX_LIBRARY': 'libc++',
'CLANG_CXX_LANGUAGE_STANDARD':'c++11',
'CLANG_CXX_LANGUAGE_STANDARD': 'c++11',
'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
'GCC_ENABLE_CPP_EXCEPTIONS': 'YES',
'GCC_ENABLE_CPP_RTTI':'YES',
'GCC_ENABLE_CPP_RTTI': 'YES',
'OTHER_CPLUSPLUSFLAGS': [
'-Werror',
'-Wall',
@@ -22,18 +21,27 @@
'-Wno-variadic-macros',
'-frtti',
'-fexceptions',
'-Wno-error=unused-parameter',
],
'GCC_WARN_PEDANTIC': 'YES',
'GCC_WARN_UNINITIALIZED_AUTOS': 'YES_AGGRESSIVE',
},
}, {
'cflags_cc': [
'-std=c++11',
'-Werror',
'-Wall',
'-Wextra',
'-Wshadow',
'-Wno-variadic-macros',
'-Wno-error=unused-parameter',
'-Wno-unknown-warning-option',
'-frtti',
'-fexceptions',
],
}],
['OS=="linux"', {
'cflags_cc': [
'-Wno-unknown-pragmas', # We are using '#pragma mark', but it is only available on Darwin.
'-Wno-literal-suffix', # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61653
'-Wno-unknown-warning-option',
'-Wno-error=unused-parameter',
],
}],
],
@@ -43,14 +51,31 @@
['OS=="mac"', {
'xcode_settings': {
'OTHER_CPLUSPLUSFLAGS': [ '-fPIC' ],
'SKIP_INSTALL': 'YES',
},
}, {
'cflags_cc': [ '-fPIC' ],
}]
}],
['host == "ios"', {
'xcode_settings': {
'SDKROOT': 'iphoneos',
'SUPPORTED_PLATFORMS': 'iphonesimulator iphoneos',
'IPHONEOS_DEPLOYMENT_TARGET': '7.0',
'TARGETED_DEVICE_FAMILY': '1,2',
'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
'CODE_SIGN_IDENTITY': 'iPhone Developer',
},
'configurations': {
'Release': {
'xcode_settings': {
'ARCHS': [ "armv7", "armv7s", "arm64", "i386", "x86_64" ],
},
},
},
}],
],
}],
],
'cflags_cc': [ '-std=c++11', '-Werror', '-Wall', '-Wextra', '-Wshadow', '-frtti', '-fexceptions' ],
'configurations': {
'Debug': {
'cflags_cc': [ '-g', '-O0', '-fno-omit-frame-pointer','-fwrapv', '-fstack-protector-all', '-fno-common' ],
@@ -64,12 +89,12 @@
}
},
'Release': {
'cflags_cc': [ '-O3' ],
'cflags_cc': [ '-g', '-O3' ],
'defines': [ 'NDEBUG' ],
'xcode_settings': {
'GCC_OPTIMIZATION_LEVEL': '3',
'GCC_GENERATE_DEBUGGING_SYMBOLS': 'NO',
'DEAD_CODE_STRIPPING': 'YES',
'GCC_GENERATE_DEBUGGING_SYMBOLS': 'YES',
'DEAD_CODE_STRIPPING': 'NO',
'GCC_INLINES_ARE_PRIVATE_EXTERN': 'NO'
}
},

View File

@@ -1,26 +1,17 @@
{
'targets': [
{ 'target_name': 'mbgl-core',
{ 'target_name': 'core',
'product_name': 'mbgl-core',
'type': 'static_library',
'standalone_static_library': 1,
'hard_dependency': 1,
'dependencies': [
'shaders',
'version',
'shaders',
'version',
],
'variables': {
'cflags_cc': [
'<@(uv_cflags)',
'<@(sqlite3_cflags)',
'<@(zlib_cflags)',
'-I<(boost_root)/include',
],
'cflags': [
'<@(uv_cflags)','-fPIC'
],
},
'sources': [
'<!@(find src -name "*.hpp")',
'<!@(find src -name "*.cpp")',
'<!@(find src -name "*.c")',
'<!@(find src -name "*.h")',
@@ -29,67 +20,57 @@
'<!@(find src -name "*.glsl")',
'bin/style.json'
],
'include_dirs': [
'../include',
'../src',
],
'variables': {
'cflags_cc': [
'<@(uv_cflags)',
'<@(boost_cflags)',
],
'cflags': [
'<@(uv_cflags)',
'-fPIC'
],
'ldflags': [
'<@(uv_ldflags)',
],
'libraries': [
'<@(uv_static_libs)',
],
},
'conditions': [
['OS == "mac"', {
'xcode_settings': {
'OTHER_CPLUSPLUSFLAGS': [ '<@(cflags_cc)' ],
'OTHER_CFLAGS': [ '<@(cflags)' ],
'SKIP_INSTALL': 'YES'
},
}, {
'cflags_cc': [ '<@(cflags_cc)' ],
'cflags': [ '<@(cflags)' ],
}]
]
},
{
'target_name': 'mbgl-standalone',
'type': 'none',
'hard_dependency': 1,
'dependencies': [
'mbgl-core'
],
'variables': {
'core_lib':'<(PRODUCT_DIR)/libmbgl-core.a',
'standalone_lib':'<(standalone_product_dir)/libmbgl.a'
'link_settings': {
'conditions': [
['OS == "mac"', {
'libraries': [ '<@(libraries)' ],
'xcode_settings': { 'OTHER_LDFLAGS': [ '<@(ldflags)' ] }
}, {
'libraries': [ '<@(libraries)', '<@(ldflags)' ],
}]
],
},
'direct_dependent_settings': {
'include_dirs': [
'../include',
],
'conditions': [
['OS == "mac"', {
'xcode_settings': {
'OTHER_LDFLAGS': [ '<(standalone_lib)' ],
}
}, {
'ldflags': [ '<(standalone_lib)' ],
}]
],
},
'actions': [
{
'action_name': 'build standalone core lib',
'inputs': [
'<(core_lib)'
],
'outputs': [
'<(standalone_lib)'
],
'action': [
'./gyp/merge_static_libs.py',
'<(standalone_lib)',
'<@(uv_static_libs)',
'<@(curl_static_libs)',
'<@(sqlite3_static_libs)',
'<(core_lib)'
],
}
]
}
},
]
}

18
gyp/headless-cgl.gypi Normal file
View File

@@ -0,0 +1,18 @@
{
'targets': [
{ 'target_name': 'headless-cgl',
'product_name': 'mbgl-headless-cgl',
'type': 'static_library',
'standalone_static_library': 1,
'sources': [
'../platform/default/headless_view.cpp',
'../platform/default/headless_display.cpp',
],
'include_dirs': [
'../include',
],
},
],
}

18
gyp/headless-glx.gypi Normal file
View File

@@ -0,0 +1,18 @@
{
'targets': [
{ 'target_name': 'headless-glx',
'product_name': 'mbgl-headless-glx',
'type': 'static_library',
'standalone_static_library': 1,
'sources': [
'../platform/default/headless_view.cpp',
'../platform/default/headless_display.cpp',
],
'include_dirs': [
'../include',
],
},
],
}

55
gyp/http-curl.gypi Normal file
View File

@@ -0,0 +1,55 @@
{
'targets': [
{ 'target_name': 'http-curl',
'product_name': 'mbgl-http-curl',
'type': 'static_library',
'standalone_static_library': 1,
'hard_dependency': 1,
'sources': [
'../platform/default/http_request_curl.cpp',
],
'include_dirs': [
'../include',
],
'variables': {
'cflags_cc': [
'<@(uv_cflags)',
'<@(curl_cflags)',
'<@(boost_cflags)',
],
'ldflags': [
'<@(uv_ldflags)',
'<@(curl_ldflags)',
],
'libraries': [
'<@(uv_static_libs)',
'<@(curl_static_libs)',
],
},
'conditions': [
['OS == "mac"', {
'xcode_settings': {
'OTHER_CPLUSPLUSFLAGS': [ '<@(cflags_cc)' ],
},
}, {
'cflags_cc': [ '<@(cflags_cc)' ],
}],
],
'link_settings': {
'conditions': [
['OS == "mac"', {
'libraries': [ '<@(libraries)' ],
'xcode_settings': { 'OTHER_LDFLAGS': [ '<@(ldflags)' ] }
}, {
'libraries': [ '<@(libraries)', '<@(ldflags)' ],
}]
],
},
},
],
}

43
gyp/http-nsurl.gypi Normal file
View File

@@ -0,0 +1,43 @@
{
'targets': [
{ 'target_name': 'http-nsurl',
'product_name': 'mbgl-http-nsurl',
'type': 'static_library',
'standalone_static_library': 1,
'hard_dependency': 1,
'sources': [
'../platform/darwin/http_request_nsurl.mm',
],
'include_dirs': [
'../include',
],
'variables': {
'cflags_cc': [
'<@(uv_cflags)',
],
'ldflags': [
'-framework Foundation', # For NSURLRequest
'<@(uv_ldflags)',
],
'libraries': [
'<@(uv_static_libs)',
],
},
'xcode_settings': {
'OTHER_CPLUSPLUSFLAGS': [ '<@(cflags_cc)' ],
'CLANG_ENABLE_OBJC_ARC': 'NO',
},
'link_settings': {
'libraries': [ '<@(libraries)' ],
'xcode_settings': {
'OTHER_LDFLAGS': [ '<@(ldflags)' ],
},
},
},
],
}

View File

@@ -6,66 +6,45 @@
'type': 'none',
'hard_dependency': 1,
'dependencies': [
'mbgl-core',
'mbgl-standalone',
'mbgl-headless',
'mbgl-<(platform)',
],
'copies': [
{ 'files': [ '<(standalone_product_dir)/libmbgl.a' ], 'destination': '<(install_prefix)/lib' },
{ 'files': [ '<(PRODUCT_DIR)/libmbgl-core.a' ], 'destination': '<(install_prefix)/lib' },
{ 'files': [ '<(PRODUCT_DIR)/libmbgl-headless.a' ], 'destination': '<(install_prefix)/lib' },
{ 'files': [ '<(PRODUCT_DIR)/libmbgl-<(platform).a' ], 'destination': '<(install_prefix)/lib' },
{ 'files': [ '../include/mbgl' ], 'destination': '<(install_prefix)/include' },
],
'variables': {
'conditions': [
['OS == "linux"', {
'other_ldflags': [
'<@(nu_static_libs)',
'<@(png_static_libs)',
'<@(jpeg_static_libs)',
'<@(glfw3_static_libs)',
'<@(glfw3_ldflags)',
]
}, {
'other_ldflags': [ ]
}]
],
},
'actions': [
{ 'action_name': 'mbgl-config',
'inputs': [
'../utils/mbgl-config/mbgl-config.template.sh',
'../utils/mbgl-config/build.sh',
],
'outputs': [
'<(install_prefix)/bin/mbgl-config',
],
'action': [
'./utils/mbgl-config/build.sh',
'<(install_prefix)',
'<(platform)',
'<@(sqlite3_static_libs)',
'<@(sqlite3_ldflags)',
'<@(curl_ldflags)',
'<@(png_ldflags)',
'<@(other_ldflags)'
]
}
]
},
{ 'target_name': 'copy_version',
'type': 'none',
'hard_dependency': 1,
'dependencies': [
'install',
'core',
'platform-<(platform_lib)',
'http-<(http_lib)',
'asset-<(asset_lib)',
'cache-<(cache_lib)',
'headless-<(headless_lib)',
'standalone',
],
'copies': [
{ 'files': [ '<(PRODUCT_DIR)/libmbgl.a' ], 'destination': '<(install_prefix)/lib' },
{ 'files': [ '<(SHARED_INTERMEDIATE_DIR)/include/mbgl/util/version.hpp' ], 'destination': '<(install_prefix)/include/mbgl/util' },
],
}
]
'actions': [
{
'action_name': 'Copy header files',
'inputs': [ '../include/mbgl/mbgl.hpp' ],
'outputs': [ '../include/mbgl/mbgl.hpp' ],
'action': [ 'cp', '-r', 'include', '<(install_prefix)/' ]
},
{ 'action_name': 'mbgl-config',
'inputs': [
'../utils/mbgl-config/mbgl-config.template.sh',
'../utils/mbgl-config/build.sh',
],
'outputs': [
'<(install_prefix)/bin/mbgl-config',
],
'action': [
'./utils/mbgl-config/build.sh',
'<(install_prefix)',
'<(PRODUCT_DIR)/libmbgl.a.ldflags',
]
}
]
},
],
}],
],
}

47
gyp/link.py Executable file
View File

@@ -0,0 +1,47 @@
#!/usr/bin/env python
import sys
import os
from merge_static_libs import MergeLibs
args = sys.argv[1:]
out_lib = ''
in_libs = []
flags = []
i = 0
l = len(args)
while i < l:
arg = args[i]
if arg[0:2] == '-l':
flags.append(arg)
elif arg[0:2] == '-L':
flags.append(arg)
elif arg == '-arch':
i += 1
elif arg == '-framework':
i += 1
flags.append(arg + ' ' + args[i])
elif arg == '-o':
i += 1
out_lib = args[i]
elif arg[0] != '-':
in_libs.append(arg)
else:
print 'Ignored linker directive: ' + arg
i += 1
flags.reverse()
unique_flags = []
for flag in flags:
if flag not in unique_flags:
unique_flags.append(flag)
unique_flags.reverse()
with open(out_lib + '.ldflags', 'w+') as f:
f.write(' '.join(unique_flags));
MergeLibs(in_libs, out_lib)

6
gyp/load.gypi Normal file
View File

@@ -0,0 +1,6 @@
{
'conditions': [
['platform_library == "mbglosx"', {
}],
],
}

View File

@@ -1,35 +0,0 @@
{
'targets': [
{ 'target_name': 'mbgl-headless',
'product_name': 'mbgl-headless',
'type': 'static_library',
'standalone_static_library': 1,
'variables': {
'cflags_cc': [
'<@(uv_cflags)',
],
'cflags': [
'<@(uv_cflags)',
],
},
'include_dirs': [
'../include',
],
'conditions': [
['OS == "mac"', {
'xcode_settings': {
'OTHER_CPLUSPLUSFLAGS': [ '<@(cflags_cc)' ],
'OTHER_CFLAGS': [ '<@(cflags)' ],
}
}, {
'cflags_cc': [ '<@(cflags_cc)' ],
'cflags': [ '<@(cflags)' ],
}]
],
'sources': [
'../platform/default/headless_view.cpp',
'../platform/default/headless_display.cpp',
],
},
],
}

View File

@@ -1,65 +0,0 @@
{
'target_defaults': {
'target_conditions': [
['_type == "static_library"', {
'xcode_settings': {
'SDKROOT': 'iphoneos',
'SUPPORTED_PLATFORMS': 'iphonesimulator iphoneos',
'CLANG_CXX_LIBRARY': 'libc++',
'CLANG_CXX_LANGUAGE_STANDARD':'c++11',
'IPHONEOS_DEPLOYMENT_TARGET':'7.0',
'TARGETED_DEVICE_FAMILY': '1,2',
'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
'CLANG_ENABLE_OBJC_ARC': 'YES',
'CODE_SIGN_IDENTITY': 'iPhone Developer',
'SKIP_INSTALL': 'YES'
},
'configurations': {
'Release': {
'xcode_settings': {
'ARCHS': [ "armv7", "armv7s", "arm64", "i386", "x86_64" ],
},
},
},
}],
],
},
'targets': [
{ 'target_name': 'mbgl-ios',
'product_name': 'mbgl-ios',
'type': 'static_library',
'standalone_static_library': 1,
'hard_dependency': 1,
'dependencies': [
'version',
],
'sources': [
'../platform/ios/cache_database_library.mm',
'../platform/darwin/log_nslog.mm',
'../platform/darwin/string_nsstring.mm',
'../platform/darwin/http_request_baton_cocoa.mm',
'../platform/darwin/application_root.mm',
'../platform/darwin/image.mm',
'../platform/default/asset_request_libuv.cpp',
],
'include_dirs': [
'../include',
'../src',
],
'xcode_settings': {
'OTHER_CPLUSPLUSFLAGS': [ '<@(uv_cflags)' ],
},
'direct_dependent_settings': {
'include_dirs': [
'../include',
],
'xcode_settings': {
'OTHER_LDFLAGS': [
'-framework ImageIO',
'-framework MobileCoreServices',
],
},
},
},
],
}

View File

@@ -1,20 +0,0 @@
{
'conditions': [
['platform == "osx"', {
'includes': ['mbgl-osx.gypi'],
'variables': { 'platform_library': 'mbgl-osx' },
}],
['platform == "ios"', {
'includes': ['mbgl-ios.gypi'],
'variables': { 'platform_library': 'mbgl-ios' },
}],
['platform == "linux"', {
'includes': ['mbgl-linux.gypi'],
'variables': { 'platform_library': 'mbgl-linux' },
}],
['platform == "android"', {
'includes': ['mbgl-android.gypi'],
'variables': { 'platform_library': 'mbgl-android' },
}],
],
}

20
gyp/none.gypi Normal file
View File

@@ -0,0 +1,20 @@
{
'targets': [
{ 'target_name': 'http-none',
'product_name': 'mbgl-http-none',
'type': 'none',
},
{ 'target_name': 'asset-none',
'product_name': 'mbgl-asset-none',
'type': 'none',
},
{ 'target_name': 'cache-none',
'product_name': 'mbgl-cache-none',
'type': 'none',
},
{ 'target_name': 'headless-none',
'product_name': 'mbgl-headless-none',
'type': 'none',
},
],
}

View File

@@ -1,81 +1,75 @@
{
'targets': [
{ 'target_name': 'mbgl-android',
'product_name': 'mbgl-android',
{ 'target_name': 'platform-android',
'product_name': 'mbgl-platform-android',
'type': 'static_library',
'standalone_static_library': 1,
'hard_dependency': 1,
'dependencies': [
'version',
],
'variables': {
'cflags_cc': [
'<@(png_cflags)',
'<@(jpeg_cflags)',
'<@(uv_cflags)',
'<@(curl_cflags)',
'<@(nu_cflags)',
'<@(zip_cflags)',
'<@(openssl_cflags)',
'-I<(boost_root)/include',
],
'cflags': [
'<@(uv_cflags)',
'<@(nu_cflags)',
],
'ldflags': [
'<@(png_ldflags)',
'<@(jpeg_ldflags)',
'<@(uv_ldflags)',
'<@(curl_ldflags)',
'<@(nu_ldflags)',
'<@(zip_ldflags)',
],
},
'sources': [
'../platform/android/cache_database_data.cpp',
'../platform/android/log_android.cpp',
'../platform/android/asset_request_libzip.cpp',
'../platform/default/string_stdlib.cpp',
'../platform/default/http_request_baton_curl.cpp',
'../platform/default/image.cpp',
'../platform/default/image_reader.cpp',
'../platform/default/png_reader.cpp',
'../platform/default/jpeg_reader.cpp',
],
'variables': {
'cflags_cc': [
'<@(png_cflags)',
'<@(jpeg_cflags)',
'<@(uv_cflags)',
'<@(nu_cflags)',
'<@(boost_cflags)',
],
'ldflags': [
'<@(png_ldflags)',
'<@(jpeg_ldflags)',
'<@(uv_ldflags)',
'<@(nu_ldflags)',
],
'libraries': [
'<@(png_static_libs)',
'<@(jpeg_static_libs)',
'<@(uv_static_libs)',
'<@(nu_static_libs)',
],
},
'include_dirs': [
'../include',
'../src',
],
'link_settings': {
'libraries': [
'<@(png_static_libs)',
],
},
'conditions': [
['OS == "mac"', {
'xcode_settings': {
'OTHER_CPLUSPLUSFLAGS': [ '<@(cflags_cc)' ],
'OTHER_CFLAGS': [ '<@(cflags)' ],
}
}, {
'cflags_cc': [ '<@(cflags_cc)' ],
'cflags': [ '<@(cflags)' ],
}]
],
'link_settings': {
'conditions': [
['OS == "mac"', {
'libraries': [ '<@(libraries)' ],
'xcode_settings': { 'OTHER_LDFLAGS': [ '<@(ldflags)' ] }
}, {
'libraries': [ '<@(libraries)', '<@(ldflags)' ],
}]
],
},
'direct_dependent_settings': {
'include_dirs': [
'../include',
],
'conditions': [
['OS == "mac"', {
'xcode_settings': {
'OTHER_LDFLAGS': [ '<@(ldflags)' ],
}
}, {
'ldflags': [ '<@(ldflags)' ],
}]
],
},
},
],

View File

@@ -1,39 +1,55 @@
{
'targets': [
{ 'target_name': 'mbgl-osx',
'product_name': 'mbgl-osx',
{ 'target_name': 'platform-ios',
'product_name': 'mbgl-platform-ios',
'type': 'static_library',
'standalone_static_library': 1,
'hard_dependency': 1,
'dependencies': [
'version',
],
'sources': [
'../platform/osx/cache_database_application_support.mm',
'../platform/darwin/log_nslog.mm',
'../platform/darwin/string_nsstring.mm',
'../platform/darwin/http_request_baton_cocoa.mm',
'../platform/darwin/application_root.mm',
'../platform/darwin/asset_root.mm',
'../platform/darwin/image.mm',
'../platform/default/asset_request_libuv.cpp',
],
'variables': {
'cflags_cc': [
'<@(uv_cflags)',
'<@(boost_cflags)',
],
'libraries': [
'<@(uv_static_libs)',
],
'ldflags': [
'-framework ImageIO',
'-framework MobileCoreServices',
],
},
'include_dirs': [
'../include',
'../src',
],
'xcode_settings': {
'OTHER_CPLUSPLUSFLAGS': [ '<@(uv_cflags)' ],
'OTHER_CPLUSPLUSFLAGS': [ '<@(cflags_cc)' ],
},
'link_settings': {
'libraries': [ '<@(libraries)' ],
'xcode_settings': {
'OTHER_LDFLAGS': [ '<@(ldflags)' ],
},
},
'direct_dependent_settings': {
'include_dirs': [
'../include',
],
'xcode_settings': {
'OTHER_LDFLAGS': [
'-framework ImageIO',
'-framework CoreServices',
],
},
},
},
],

View File

@@ -1,79 +1,77 @@
{
'targets': [
{ 'target_name': 'mbgl-linux',
'product_name': 'mbgl-linux',
{ 'target_name': 'platform-linux',
'product_name': 'mbgl-platform-linux',
'type': 'static_library',
'standalone_static_library': 1,
'hard_dependency': 1,
'dependencies': [
'version',
],
'variables': {
'cflags_cc': [
'<@(png_cflags)',
'<@(jpeg_cflags)',
'<@(uv_cflags)',
'<@(curl_cflags)',
'<@(nu_cflags)',
'-I<(boost_root)/include',
],
'cflags': [
'<@(uv_cflags)',
'<@(nu_cflags)',
],
'ldflags': [
'<@(png_ldflags)',
'<@(jpeg_ldflags)',
'<@(uv_ldflags)',
'<@(curl_ldflags)',
'<@(nu_ldflags)',
],
},
'sources': [
'../platform/default/cache_database_tmp.cpp',
'../platform/default/log_stderr.cpp',
'../platform/default/string_stdlib.cpp',
'../platform/default/asset_request_libuv.cpp',
'../platform/default/http_request_baton_curl.cpp',
'../platform/default/application_root.cpp',
'../platform/default/asset_root.cpp',
'../platform/default/image.cpp',
'../platform/default/image_reader.cpp',
'../platform/default/png_reader.cpp',
'../platform/default/jpeg_reader.cpp',
],
'variables': {
'cflags_cc': [
'<@(png_cflags)',
'<@(jpeg_cflags)',
'<@(uv_cflags)',
'<@(nu_cflags)',
'<@(boost_cflags)',
],
'ldflags': [
'<@(png_ldflags)',
'<@(jpeg_ldflags)',
'<@(uv_ldflags)',
'<@(nu_ldflags)',
],
'libraries': [
'<@(png_static_libs)',
'<@(jpeg_static_libs)',
'<@(uv_static_libs)',
'<@(nu_static_libs)',
],
},
'include_dirs': [
'../include',
'../src',
],
'link_settings': {
'libraries': [
'<@(png_static_libs)',
],
},
'conditions': [
['OS == "mac"', {
'xcode_settings': {
'OTHER_CPLUSPLUSFLAGS': [ '<@(cflags_cc)' ],
'OTHER_CFLAGS': [ '<@(cflags)' ],
}
}, {
'cflags_cc': [ '<@(cflags_cc)' ],
'cflags': [ '<@(cflags)' ],
}]
],
'link_settings': {
'conditions': [
['OS == "mac"', {
'libraries': [ '<@(libraries)' ],
'xcode_settings': { 'OTHER_LDFLAGS': [ '<@(ldflags)' ] }
}, {
'libraries': [ '<@(libraries)', '<@(ldflags)' ],
}]
],
},
'direct_dependent_settings': {
'include_dirs': [
'../include',
],
'conditions': [
['OS == "mac"', {
'xcode_settings': {
'OTHER_LDFLAGS': [ '<@(ldflags)' ],
}
}, {
'ldflags': [ '<@(ldflags)' ],
}]
],
},
},
],

58
gyp/platform-osx.gypi Normal file
View File

@@ -0,0 +1,58 @@
{
'targets': [
{ 'target_name': 'platform-osx',
'product_name': 'mbgl-platform-osx',
'type': 'static_library',
'standalone_static_library': 1,
'hard_dependency': 1,
'dependencies': [
'version',
],
'sources': [
'../platform/darwin/log_nslog.mm',
'../platform/darwin/string_nsstring.mm',
'../platform/darwin/application_root.mm',
'../platform/darwin/asset_root.mm',
'../platform/darwin/image.mm',
],
'variables': {
'cflags_cc': [
'<@(uv_cflags)',
'<@(boost_cflags)',
],
'libraries': [
'<@(uv_static_libs)',
],
'ldflags': [
'-framework Foundation',
'-framework ImageIO',
'-framework CoreServices',
],
},
'include_dirs': [
'../include',
'../src',
],
'xcode_settings': {
'OTHER_CPLUSPLUSFLAGS': [ '<@(cflags_cc)' ],
},
'link_settings': {
'libraries': [ '<@(libraries)' ],
'xcode_settings': {
'OTHER_LDFLAGS': [ '<@(ldflags)' ],
},
},
'direct_dependent_settings': {
'include_dirs': [
'../include',
],
},
},
],
}

32
gyp/standalone.gypi Normal file
View File

@@ -0,0 +1,32 @@
{
'targets': [
{ 'target_name': 'everything',
'type': 'none',
'hard_dependency': 1,
'dependencies': [
'core',
'platform-<(platform_lib)',
'http-<(http_lib)',
'asset-<(asset_lib)',
'cache-<(cache_lib)',
'headless-<(headless_lib)',
],
},
{ 'target_name': 'standalone',
'product_name': 'libmbgl.a',
'type': 'executable',
'hard_dependency': 1,
'dependencies': [
'core',
'platform-<(platform_lib)',
'http-<(http_lib)',
'asset-<(asset_lib)',
'cache-<(cache_lib)',
'headless-<(headless_lib)',
],
},
],
}

View File

@@ -13,7 +13,7 @@
'outputs': [
'<(SHARED_INTERMEDIATE_DIR)/include/mbgl/util/version.hpp',
],
'action': ['<@(python)', 'scripts/build-version.py', '<(SHARED_INTERMEDIATE_DIR)', '<!@(git describe --tags --always --abbrev=0)', '<!@(git rev-parse HEAD)'],
'action': ['<@(python)', '<@(_inputs)', '<(SHARED_INTERMEDIATE_DIR)', '<!@(git describe --tags --always --abbrev=0)', '<!@(git rev-parse HEAD)'],
}
],
'direct_dependent_settings': {

View File

@@ -2,7 +2,11 @@
#define MBGL_ANDROID_JNI
#include <string>
#include <jni.h>
// Forward definition of JNI types
typedef class _jclass* jclass;
typedef struct _jmethodID* jmethodID;
typedef struct _jfieldID* jfieldID;
namespace mbgl {
namespace android {

View File

@@ -4,7 +4,8 @@
#include <mbgl/map/map.hpp>
#include <mbgl/map/view.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/storage/caching_http_file_source.hpp>
#include <mbgl/storage/default/sqlite_cache.hpp>
#include <mbgl/storage/default_file_source.hpp>
#include <string>
#include <jni.h>
@@ -25,10 +26,10 @@ public:
void swap() override;
void notify() override;
void notifyMapChange(mbgl::MapChange change, mbgl::timestamp delay) override;
void notifyMapChange(mbgl::MapChange change, std::chrono::steady_clock::duration delay = std::chrono::steady_clock::duration::zero()) override;
mbgl::Map &getMap();
mbgl::CachingHTTPFileSource &getFileSource();
mbgl::DefaultFileSource &getFileSource();
void initializeDisplay();
void terminateDisplay();
@@ -61,7 +62,8 @@ private:
ANativeWindow *window = nullptr;
mbgl::CachingHTTPFileSource fileSource;
mbgl::SQLiteCache fileCache;
mbgl::DefaultFileSource fileSource;
mbgl::Map map;
EGLDisplay display = EGL_NO_DISPLAY;

View File

@@ -3,7 +3,6 @@
#include <mbgl/map/transform.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/time.hpp>
#include <mbgl/util/uv.hpp>
#include <mbgl/util/ptr.hpp>
@@ -16,6 +15,7 @@
#include <mutex>
#include <condition_variable>
#include <functional>
#include <chrono>
namespace mbgl {
@@ -83,8 +83,8 @@ public:
void setClasses(const std::vector<std::string>&);
std::vector<std::string> getClasses() const;
void setDefaultTransitionDuration(uint64_t milliseconds = 0);
uint64_t getDefaultTransitionDuration();
void setDefaultTransitionDuration(std::chrono::steady_clock::duration duration = std::chrono::steady_clock::duration::zero());
std::chrono::steady_clock::duration getDefaultTransitionDuration();
void setStyleURL(const std::string &url);
void setStyleJSON(std::string newStyleJSON, const std::string &base = "");
std::string getStyleJSON() const;
@@ -93,20 +93,20 @@ public:
void cancelTransitions();
// Position
void moveBy(double dx, double dy, double duration = 0);
void setLonLat(double lon, double lat, double duration = 0);
void moveBy(double dx, double dy, std::chrono::steady_clock::duration duration = std::chrono::steady_clock::duration::zero());
void setLonLat(double lon, double lat, std::chrono::steady_clock::duration duration = std::chrono::steady_clock::duration::zero());
void getLonLat(double &lon, double &lat) const;
void startPanning();
void stopPanning();
void resetPosition();
// Scale
void scaleBy(double ds, double cx = -1, double cy = -1, double duration = 0);
void setScale(double scale, double cx = -1, double cy = -1, double duration = 0);
void scaleBy(double ds, double cx = -1, double cy = -1, std::chrono::steady_clock::duration duration = std::chrono::steady_clock::duration::zero());
void setScale(double scale, double cx = -1, double cy = -1, std::chrono::steady_clock::duration duration = std::chrono::steady_clock::duration::zero());
double getScale() const;
void setZoom(double zoom, double duration = 0);
void setZoom(double zoom, std::chrono::steady_clock::duration duration = std::chrono::steady_clock::duration::zero());
double getZoom() const;
void setLonLatZoom(double lon, double lat, double zoom, double duration = 0);
void setLonLatZoom(double lon, double lat, double zoom, std::chrono::steady_clock::duration duration = std::chrono::steady_clock::duration::zero());
void getLonLatZoom(double &lon, double &lat, double &zoom) const;
void resetZoom();
void startScaling();
@@ -115,21 +115,25 @@ public:
double getMaxZoom() const;
// Rotation
void rotateBy(double sx, double sy, double ex, double ey, double duration = 0);
void setBearing(double degrees, double duration = 0);
void rotateBy(double sx, double sy, double ex, double ey, std::chrono::steady_clock::duration duration = std::chrono::steady_clock::duration::zero());
void setBearing(double degrees, std::chrono::steady_clock::duration duration = std::chrono::steady_clock::duration::zero());
void setBearing(double degrees, double cx, double cy);
double getBearing() const;
void resetNorth();
void startRotating();
void stopRotating();
// API
void setAccessToken(const std::string &token);
const std::string &getAccessToken() const;
// Debug
void setDebug(bool value);
void toggleDebug();
bool getDebug() const;
inline const TransformState &getState() const { return state; }
inline timestamp getTime() const { return animationTime; }
inline std::chrono::steady_clock::time_point getTime() const { return animationTime; }
private:
util::ptr<Sprite> getSprite();
@@ -160,7 +164,10 @@ private:
Mode mode = Mode::None;
public: // TODO: make private again
std::unique_ptr<uv::loop> loop;
private:
std::unique_ptr<uv::worker> workers;
std::thread thread;
std::unique_ptr<uv::async> asyncTerminate;
@@ -191,7 +198,7 @@ private:
View &view;
#ifndef NDEBUG
#ifdef DEBUG
const std::thread::id mainThread;
std::thread::id mapThread;
#endif
@@ -214,11 +221,12 @@ private:
std::string styleURL;
std::string styleJSON = "";
std::vector<std::string> classes;
std::string accessToken;
std::atomic_uint_fast64_t defaultTransitionDuration;
std::chrono::steady_clock::duration defaultTransitionDuration;
bool debug = false;
timestamp animationTime = 0;
std::chrono::steady_clock::time_point animationTime = std::chrono::steady_clock::time_point::min();
std::set<util::ptr<StyleSource>> activeSources;
};

View File

@@ -1,7 +1,6 @@
#ifndef MBGL_MAP_TRANSFORM
#define MBGL_MAP_TRANSFORM
#include <mbgl/util/time.hpp>
#include <mbgl/map/transform_state.hpp>
#include <mbgl/util/noncopyable.hpp>
@@ -9,6 +8,7 @@
#include <cmath>
#include <forward_list>
#include <mutex>
#include <chrono>
namespace mbgl {
@@ -25,18 +25,18 @@ public:
uint16_t fb_width, uint16_t fb_height);
// Position
void moveBy(double dx, double dy, timestamp duration = 0);
void setLonLat(double lon, double lat, timestamp duration = 0);
void setLonLatZoom(double lon, double lat, double zoom, timestamp duration = 0);
void moveBy(double dx, double dy, std::chrono::steady_clock::duration duration = std::chrono::steady_clock::duration::zero());
void setLonLat(double lon, double lat, std::chrono::steady_clock::duration duration = std::chrono::steady_clock::duration::zero());
void setLonLatZoom(double lon, double lat, double zoom, std::chrono::steady_clock::duration duration = std::chrono::steady_clock::duration::zero());
void getLonLat(double& lon, double& lat) const;
void getLonLatZoom(double& lon, double& lat, double& zoom) const;
void startPanning();
void stopPanning();
// Zoom
void scaleBy(double ds, double cx = -1, double cy = -1, timestamp duration = 0);
void setScale(double scale, double cx = -1, double cy = -1, timestamp duration = 0);
void setZoom(double zoom, timestamp duration = 0);
void scaleBy(double ds, double cx = -1, double cy = -1, std::chrono::steady_clock::duration duration = std::chrono::steady_clock::duration::zero());
void setScale(double scale, double cx = -1, double cy = -1, std::chrono::steady_clock::duration duration = std::chrono::steady_clock::duration::zero());
void setZoom(double zoom, std::chrono::steady_clock::duration duration = std::chrono::steady_clock::duration::zero());
double getZoom() const;
double getScale() const;
void startScaling();
@@ -45,8 +45,8 @@ public:
double getMaxZoom() const;
// Angle
void rotateBy(double sx, double sy, double ex, double ey, timestamp duration = 0);
void setAngle(double angle, timestamp duration = 0);
void rotateBy(double sx, double sy, double ex, double ey, std::chrono::steady_clock::duration duration = std::chrono::steady_clock::duration::zero());
void setAngle(double angle, std::chrono::steady_clock::duration duration = std::chrono::steady_clock::duration::zero());
void setAngle(double angle, double cx, double cy);
double getAngle() const;
void startRotating();
@@ -54,7 +54,7 @@ public:
// Transitions
bool needsTransition() const;
void updateTransitions(timestamp now);
void updateTransitions(std::chrono::steady_clock::time_point now);
void cancelTransitions();
// Transform state
@@ -64,10 +64,10 @@ public:
private:
// Functions prefixed with underscores will *not* perform any locks. It is the caller's
// responsibility to lock this object.
void _moveBy(double dx, double dy, timestamp duration = 0);
void _setScale(double scale, double cx, double cy, timestamp duration = 0);
void _setScaleXY(double new_scale, double xn, double yn, timestamp duration = 0);
void _setAngle(double angle, timestamp duration = 0);
void _moveBy(double dx, double dy, std::chrono::steady_clock::duration duration = std::chrono::steady_clock::duration::zero());
void _setScale(double scale, double cx, double cy, std::chrono::steady_clock::duration duration = std::chrono::steady_clock::duration::zero());
void _setScaleXY(double new_scale, double xn, double yn, std::chrono::steady_clock::duration duration = std::chrono::steady_clock::duration::zero());
void _setAngle(double angle, std::chrono::steady_clock::duration duration = std::chrono::steady_clock::duration::zero());
void _clearPanning();
void _clearRotating();
void _clearScaling();

View File

@@ -1,7 +1,7 @@
#ifndef MBGL_MAP_VIEW
#define MBGL_MAP_VIEW
#include <mbgl/util/time.hpp>
#include <chrono>
namespace mbgl {
@@ -44,7 +44,7 @@ public:
// Notifies a watcher of map x/y/scale/rotation changes.
// Must only be called from the same thread that caused the change.
// Must not be called from the render thread.
virtual void notifyMapChange(MapChange change, timestamp delay = 0) = 0;
virtual void notifyMapChange(MapChange change, std::chrono::steady_clock::duration delay = std::chrono::steady_clock::duration::zero()) = 0;
protected:
mbgl::Map *map = nullptr;

View File

@@ -2,7 +2,6 @@
#define MBGL_COMMON_GLFW_VIEW
#include <mbgl/mbgl.hpp>
#include <mbgl/util/time.hpp>
#ifdef NVIDIA
#define GLFW_INCLUDE_ES2
@@ -19,7 +18,7 @@ public:
void activate();
void deactivate();
void notify();
void notifyMapChange(mbgl::MapChange change, mbgl::timestamp delay = 0);
void notifyMapChange(mbgl::MapChange change, std::chrono::steady_clock::duration delay = std::chrono::steady_clock::duration::zero());
static void key(GLFWwindow *window, int key, int scancode, int action, int mods);
static void scroll(GLFWwindow *window, double xoffset, double yoffset);

View File

@@ -7,6 +7,7 @@
#define GL_GLEXT_PROTOTYPES
#include <mbgl/platform/default/glx.h>
#define MBGL_USE_GLX 1
#undef Status
#endif
#include <mbgl/map/view.hpp>
@@ -31,7 +32,7 @@ public:
std::unique_ptr<uint32_t[]> readPixels();
void notify();
void notifyMapChange(MapChange change, timestamp delay = 0);
void notifyMapChange(MapChange change, std::chrono::steady_clock::duration delay = std::chrono::steady_clock::duration::zero());
void activate();
void deactivate();
void swap();

View File

@@ -9,7 +9,13 @@ extern "C"
#include <jpeglib.h>
}
#pragma GCC diagnostic push
#ifndef __clang__
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wshadow"
#endif
#include <boost/iostreams/stream.hpp>
#pragma GCC diagnostic pop
namespace mbgl { namespace util {

View File

@@ -11,7 +11,13 @@ extern "C"
#include <cstring>
#include <memory>
#pragma GCC diagnostic push
#ifndef __clang__
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wshadow"
#endif
#include <boost/iostreams/stream.hpp>
#pragma GCC diagnostic pop
namespace mbgl { namespace util {

View File

@@ -17,10 +17,11 @@ std::string uppercase(const std::string &string);
// Lowercase a string, potentially using platform-specific routines.
std::string lowercase(const std::string &string);
// Returns the path to the default cache database on this system.
std::string defaultCacheDatabase();
// Returns the path to the root folder of the application.
const std::string &applicationRoot();
std::string applicationRoot();
// Returns the path to the asset location.
const std::string &assetRoot();
// Shows an alpha image with the specified dimensions in a named window.
void show_debug_image(std::string name, const char *data, size_t width, size_t height);

View File

@@ -1,27 +0,0 @@
#ifndef MBGL_STORAGE_ASSET_REQUEST
#define MBGL_STORAGE_ASSET_REQUEST
#include <mbgl/storage/base_request.hpp>
namespace mbgl {
typedef struct uv_loop_s uv_loop_t;
struct AssetRequestBaton;
class AssetRequest : public BaseRequest {
public:
AssetRequest(const std::string &path, uv_loop_t *loop);
~AssetRequest();
void cancel();
private:
AssetRequestBaton *ptr = nullptr;
friend struct AssetRequestBaton;
};
}
#endif

View File

@@ -1,38 +0,0 @@
#ifndef MBGL_STORAGE_ASSET_REQUEST_BATON
#define MBGL_STORAGE_ASSET_REQUEST_BATON
#include <mbgl/util/uv.hpp>
#include <thread>
#include <uv.h>
namespace mbgl {
class AssetRequest;
struct AssetRequestBaton {
AssetRequestBaton(AssetRequest *request_, const std::string &path, uv_loop_t *loop);
const std::thread::id threadId;
AssetRequest *request = nullptr;
std::unique_ptr<uv::async> asyncRun;
std::string path;
bool canceled = false;
void cancel();
static void notifyError(AssetRequestBaton *ptr, const int code, const char *message);
static void notifySuccess(AssetRequestBaton *ptr, const std::string body);
static void cleanup(AssetRequestBaton *ptr);
// IMPLEMENT THIS PLATFORM SPECIFIC FUNCTION:
// Called to load the asset. Platform-specific implementation.
static void run(AssetRequestBaton *ptr);
};
}
#endif

View File

@@ -1,62 +0,0 @@
#ifndef MBGL_STORAGE_CACHING_HTTP_FILE_SOURCE
#define MBGL_STORAGE_CACHING_HTTP_FILE_SOURCE
#include <mbgl/storage/file_source.hpp>
#include <thread>
#include <unordered_map>
typedef struct uv_messenger_s uv_messenger_t;
namespace mbgl {
class BaseRequest;
class SQLiteStore;
class CachingHTTPFileSource : public FileSource {
public:
CachingHTTPFileSource(const std::string &path_);
virtual ~CachingHTTPFileSource();
// Stores and checks the libuv loop for requests
void setLoop(uv_loop_t*);
bool hasLoop();
void clearLoop();
// Set the base path/URL for relative requests
void setBase(std::string);
// Set the Mapbox API access token
void setAccessToken(std::string);
// Get the Mapbox API access token
std::string getAccessToken() const;
std::unique_ptr<Request> request(ResourceType type, const std::string &url);
void prepare(std::function<void()> fn);
// Call this when the network status reachability changed.
void setReachability(bool reachable);
private:
std::thread::id threadId;
// Mapbox API access token.
std::string accessToken;
// Path to the cache database.
std::string path;
// Stores a URL that is used as a base for loading resources with relative path.
std::string base;
std::unordered_map<std::string, std::weak_ptr<BaseRequest>> pending;
util::ptr<SQLiteStore> store;
uv_loop_t *loop = nullptr;
uv_messenger_t *queue = nullptr;
};
}
#endif

View File

@@ -0,0 +1,24 @@
#ifndef MBGL_STORAGE_DEFAULT_ASSET_REQUEST
#define MBGL_STORAGE_DEFAULT_ASSET_REQUEST
#include "shared_request_base.hpp"
namespace mbgl {
class AssetRequest : public SharedRequestBase {
public:
AssetRequest(DefaultFileSource *source, const Resource &resource);
void start(uv_loop_t *loop, std::unique_ptr<Response> response = nullptr);
void cancel();
private:
~AssetRequest();
void *ptr = nullptr;
friend class AssetRequestImpl;
};
}
#endif

View File

@@ -0,0 +1,76 @@
#ifndef MBGL_STORAGE_DEFAULT_HTTP_CONTEXT
#define MBGL_STORAGE_DEFAULT_HTTP_CONTEXT
#include "thread_context.hpp"
#include <mbgl/storage/network_status.hpp>
#include <set>
namespace mbgl {
class HTTPRequest;
// This is a template class that provides a per-thread Context object. It can be used by HTTP
// implementations to store global state. It also implements the NetworkStatus mechanism and
// triggers immediate retries on all requests waiting for network status changes.
template <typename Context>
class HTTPContext : public ThreadContext<Context> {
public:
HTTPContext(uv_loop_t *loop);
~HTTPContext();
void addRequest(HTTPRequest *request);
void removeRequest(HTTPRequest *baton);
public:
// Will be fired when the network status becomes reachable.
uv_async_t *reachability = nullptr;
// A list of all pending HTTPRequestImpls that we need to notify when the network status
// changes.
std::set<HTTPRequest *> requests;
};
template <typename Context>
HTTPContext<Context>::HTTPContext(uv_loop_t *loop_)
: ThreadContext<Context>(loop_) {
reachability = new uv_async_t;
reachability->data = this;
#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
uv_async_init(loop_, reachability, [](uv_async_t *async, int) {
#else
uv_async_init(loop_, reachability, [](uv_async_t *async) {
#endif
for (auto request : reinterpret_cast<Context *>(async->data)->requests) {
request->retryImmediately();
}
});
// Allow the loop to quit even though this handle is still active.
uv_unref(reinterpret_cast<uv_handle_t *>(reachability));
NetworkStatus::Subscribe(reachability);
}
template <typename Context>
HTTPContext<Context>::~HTTPContext() {
MBGL_VERIFY_THREAD(HTTPContext<Context>::tid);
assert(requests.empty());
NetworkStatus::Unsubscribe(reachability);
uv::close(reachability);
}
template <typename Context>
void HTTPContext<Context>::addRequest(HTTPRequest *request) {
requests.insert(request);
}
template <typename Context>
void HTTPContext<Context>::removeRequest(HTTPRequest *request) {
requests.erase(request);
}
}
#endif

View File

@@ -0,0 +1,26 @@
#ifndef MBGL_STORAGE_DEFAULT_HTTP_REQUEST
#define MBGL_STORAGE_DEFAULT_HTTP_REQUEST
#include "shared_request_base.hpp"
namespace mbgl {
class HTTPRequest : public SharedRequestBase {
public:
HTTPRequest(DefaultFileSource *source, const Resource &resource);
void start(uv_loop_t *loop, std::unique_ptr<Response> response = nullptr);
void cancel();
void retryImmediately();
private:
~HTTPRequest();
void *ptr = nullptr;
friend class HTTPRequestImpl;
};
}
#endif

View File

@@ -0,0 +1,51 @@
#ifndef MBGL_STORAGE_DEFAULT_REQUEST
#define MBGL_STORAGE_DEFAULT_REQUEST
#include <mbgl/storage/resource.hpp>
#include <mbgl/util/util.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <functional>
#include <memory>
typedef struct uv_async_s uv_async_t;
typedef struct uv_loop_s uv_loop_t;
namespace mbgl {
class Response;
class Request : private util::noncopyable {
MBGL_STORE_THREAD(tid)
public:
using Callback = std::function<void(const Response &)>;
Request(const Resource &resource, uv_loop_t *loop, Callback callback);
~Request();
public:
// May be called from any thread.
void notify(const std::shared_ptr<const Response> &response);
void destruct();
// May be called only from the thread the Request was created in.
void cancel();
private:
static void notifyCallback(uv_async_t *async);
static void cancelCallback(uv_async_t *async);
private:
uv_async_t *notify_async = nullptr;
uv_async_t *destruct_async = nullptr;
Callback callback;
std::shared_ptr<const Response> response;
public:
const Resource resource;
};
}
#endif

View File

@@ -0,0 +1,88 @@
#ifndef MBGL_STORAGE_DEFAULT_SHARED_REQUEST_BASE
#define MBGL_STORAGE_DEFAULT_SHARED_REQUEST_BASE
#include <mbgl/storage/resource.hpp>
#include <mbgl/storage/file_cache.hpp>
#include <mbgl/storage/default_file_source.hpp>
#include <mbgl/util/util.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <string>
#include <set>
#include <cassert>
typedef struct uv_loop_s uv_loop_t;
namespace mbgl {
class Request;
class Response;
class DefaultFileSource;
class SharedRequestBase : private util::noncopyable {
protected:
MBGL_STORE_THREAD(tid)
public:
SharedRequestBase(DefaultFileSource *source_, const Resource &resource_)
: resource(resource_), source(source_) {}
virtual void start(uv_loop_t *loop, std::unique_ptr<Response> response = nullptr) = 0;
virtual void cancel() = 0;
void notify(std::unique_ptr<Response> response, FileCache::Hint hint) {
MBGL_VERIFY_THREAD(tid);
if (source) {
source->notify(this, observers, std::shared_ptr<const Response>(response.release()),
hint);
}
}
void subscribe(Request *request) {
MBGL_VERIFY_THREAD(tid);
observers.insert(request);
}
void unsubscribeAll() {
MBGL_VERIFY_THREAD(tid);
source = nullptr;
observers.clear();
cancel();
}
void unsubscribe(Request *request) {
MBGL_VERIFY_THREAD(tid);
observers.erase(request);
if (observers.empty()) {
// There are no observers anymore. We are initiating cancelation.
if (source) {
// First, remove this SharedRequestBase from the source.
source->notify(this, observers, nullptr, FileCache::Hint::No);
}
// Then, initiate cancelation of this request
cancel();
}
}
protected:
virtual ~SharedRequestBase() {
MBGL_VERIFY_THREAD(tid);
}
public:
const Resource resource;
private:
DefaultFileSource *source = nullptr;
std::set<Request *> observers;
};
}
#endif

View File

@@ -0,0 +1,52 @@
#ifndef MBGL_STORAGE_DEFAULT_SQLITE_CACHE
#define MBGL_STORAGE_DEFAULT_SQLITE_CACHE
#include <mbgl/storage/file_cache.hpp>
#include <string>
#include <thread>
typedef struct uv_loop_s uv_loop_t;
namespace mapbox { namespace util { template<typename... Types> class variant; } }
namespace mapbox { namespace sqlite { class Database; class Statement; } }
namespace mbgl {
namespace util { template <typename T> class AsyncQueue; }
class SQLiteCache : public FileCache {
struct GetAction;
struct PutAction;
struct RefreshAction;
struct StopAction;
using Action = mapbox::util::variant<GetAction, PutAction, RefreshAction, StopAction>;
using Queue = util::AsyncQueue<Action>;
public:
SQLiteCache(const std::string &path = ":memory:");
~SQLiteCache();
void get(const Resource &resource, std::function<void(std::unique_ptr<Response>)> callback);
void put(const Resource &resource, std::shared_ptr<const Response> response, Hint hint);
private:
struct ActionDispatcher;
void process(GetAction &action);
void process(PutAction &action);
void process(RefreshAction &action);
void process(StopAction &action);
void createDatabase();
const std::string path;
uv_loop_t *loop = nullptr;
Queue *queue = nullptr;
std::thread thread;
std::unique_ptr<::mapbox::sqlite::Database> db;
std::unique_ptr<::mapbox::sqlite::Statement> getStmt, putStmt, refreshStmt;
};
}
#endif

View File

@@ -0,0 +1,78 @@
#ifndef MBGL_STORAGE_DEFAULT_THREAD_CONTEXT
#define MBGL_STORAGE_DEFAULT_THREAD_CONTEXT
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/std.hpp>
#include <mbgl/util/util.hpp>
#include <mbgl/util/uv.hpp>
#include <uv.h>
#include <pthread.h>
#include <map>
#include <cassert>
namespace mbgl {
// This is a template class that provides a per-thread and per-loop Context object. It can be used
// by implementations to store global state.
template <typename Context>
class ThreadContext : private util::noncopyable {
protected:
MBGL_STORE_THREAD(tid)
using Map = std::map<uv_loop_t *, std::unique_ptr<Context>>;
public:
static Context *Get(uv_loop_t *loop);
private:
static pthread_key_t key;
static pthread_once_t once;
public:
ThreadContext(uv_loop_t *loop);
~ThreadContext();
public:
uv_loop_t *loop;
};
template <typename Context>
Context *ThreadContext<Context>::Get(uv_loop_t *loop) {
pthread_once(&once, []() {
pthread_key_create(&key, [](void *ptr) {
assert(ptr);
delete reinterpret_cast<Map *>(ptr);
});
});
auto contexts = reinterpret_cast<Map *>(pthread_getspecific(key));
if (!contexts) {
contexts = new Map();
pthread_setspecific(key, contexts);
}
// Now find a ThreadContext that matches the requested loop.
auto it = contexts->find(loop);
if (it == contexts->end()) {
auto result = contexts->emplace(loop, util::make_unique<Context>(loop));
assert(result.second); // Make sure it was actually inserted.
return result.first->second.get();
} else {
return it->second.get();
}
}
template <typename Context>
ThreadContext<Context>::ThreadContext(uv_loop_t *loop_) : loop(loop_) {
}
template <typename Context>
ThreadContext<Context>::~ThreadContext() {
MBGL_VERIFY_THREAD(tid);
}
}
#endif

View File

@@ -0,0 +1,60 @@
#ifndef MBGL_STORAGE_DEFAULT_DEFAULT_FILE_SOURCE
#define MBGL_STORAGE_DEFAULT_DEFAULT_FILE_SOURCE
#include <mbgl/storage/file_source.hpp>
#include <mbgl/storage/file_cache.hpp>
#include <set>
#include <unordered_map>
#include <thread>
namespace mapbox { namespace util { template<typename... Types> class variant; } }
namespace mbgl {
namespace util { template <typename T> class AsyncQueue; }
class SharedRequestBase;
class DefaultFileSource : public FileSource {
public:
DefaultFileSource(FileCache *cache);
DefaultFileSource(FileCache *cache, uv_loop_t *loop);
~DefaultFileSource();
Request *request(const Resource &resource, uv_loop_t *loop, Callback callback);
void cancel(Request *request);
void request(const Resource &resource, Callback callback);
enum class CacheHint : uint8_t { Full, Refresh, No };
void notify(SharedRequestBase *sharedRequest, const std::set<Request *> &observers,
std::shared_ptr<const Response> response, FileCache::Hint hint);
private:
struct ActionDispatcher;
struct AddRequestAction;
struct RemoveRequestAction;
struct ResultAction;
struct StopAction;
using Action =
mapbox::util::variant<AddRequestAction, RemoveRequestAction, ResultAction, StopAction>;
using Queue = util::AsyncQueue<Action>;
void process(AddRequestAction &action);
void process(RemoveRequestAction &action);
void process(ResultAction &action);
void process(StopAction &action);
SharedRequestBase *find(const Resource &resource);
std::unordered_map<Resource, SharedRequestBase *, Resource::Hash> pending;
uv_loop_t *loop = nullptr;
FileCache *cache = nullptr;
Queue *queue = nullptr;
std::thread thread;
};
}
#endif

View File

@@ -0,0 +1,27 @@
#ifndef MBGL_STORAGE_FILE_CACHE
#define MBGL_STORAGE_FILE_CACHE
#include <mbgl/util/noncopyable.hpp>
#include <functional>
#include <memory>
namespace mbgl {
struct Resource;
class Response;
class FileCache : private util::noncopyable {
public:
virtual ~FileCache() = default;
enum class Hint : uint8_t { Full, Refresh, No };
virtual void get(const Resource &resource,
std::function<void(std::unique_ptr<Response>)> callback) = 0;
virtual void put(const Resource &resource, std::shared_ptr<const Response> response, Hint hint) = 0;
};
}
#endif

View File

@@ -1,29 +1,38 @@
#ifndef MBGL_STORAGE_FILE_SOURCE
#define MBGL_STORAGE_FILE_SOURCE
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/storage/resource_type.hpp>
#include <mbgl/storage/request.hpp>
#include "response.hpp"
#include "resource.hpp"
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/std.hpp>
#include <mbgl/util/util.hpp>
#include <string>
#include <functional>
typedef struct uv_loop_s uv_loop_t;
namespace mbgl {
class FileSource : public util::noncopyable {
class Request;
class FileSource : private util::noncopyable {
protected:
MBGL_STORE_THREAD(tid)
public:
virtual ~FileSource() = default;
virtual void setLoop(uv_loop_t*) = 0;
virtual bool hasLoop() = 0;
virtual void clearLoop() = 0;
using Callback = std::function<void(const Response &)>;
virtual void setBase(std::string) = 0;
virtual std::unique_ptr<Request> request(ResourceType type, const std::string &url) = 0;
virtual void prepare(std::function<void()> fn) = 0;
// These can be called from any thread. The callback will be invoked in the loop.
// You can only cancel a request from the same thread it was created in.
virtual Request *request(const Resource &resource, uv_loop_t *loop, Callback callback) = 0;
virtual void cancel(Request *request) = 0;
// These can be called from any thread. The callback will be invoked in an arbitrary other thread.
// You cannot cancel these requests.
virtual void request(const Resource &resource, Callback callback) = 0;
};
}

View File

@@ -1,74 +0,0 @@
#ifndef MBGL_STORAGE_HTTP_REQUEST_BATON
#define MBGL_STORAGE_HTTP_REQUEST_BATON
#include <mbgl/storage/response.hpp>
#include <mbgl/util/ptr.hpp>
#include <string>
#include <thread>
typedef struct uv_async_s uv_async_t;
namespace mbgl {
class HTTPRequest;
enum class HTTPResponseType : int8_t {
// This error probably won't be resolved by retrying anytime soon. We are giving up.
PermanentError = -5,
// This error might be resolved by waiting some time (e.g. server issues).
// We are going to do an exponential back-off and will try again in a few seconds.
TemporaryError = -4,
// This error was caused by a temporary error and it is likely that it will be resolved
// immediately. We are going to try again right away. This is like the TemporaryError, except
// that we will not perform exponential back-off.
SingularError = -3,
// This error might be resolved once the network reachability status changes.
// We are going to watch the network status for changes and will retry as soon as the operating
// system notifies us of a network status change.
ConnectionError = -2,
// The request was canceled programatically.
Canceled = -1,
// The request is still in progress.
Unknown = 0,
// The request returned data successfully. We retrieved and decoded the data successfully.
Successful = 1,
// The request confirmed that the data wasn't changed. We already have the data.
NotModified = 2,
};
struct HTTPRequestBaton {
HTTPRequestBaton(const std::string &path);
~HTTPRequestBaton();
const std::thread::id threadId;
const std::string path;
HTTPRequest *request = nullptr;
uv_async_t *async = nullptr;
HTTPResponseType type = HTTPResponseType::Unknown;
std::unique_ptr<Response> response;
// Implementation specific use.
void *ptr = nullptr;
// IMPLEMENT THESE 3 PLATFORM SPECIFIC FUNCTIONS:
// Begin the HTTP request. Platform-specific implementation.
static void start(const util::ptr<HTTPRequestBaton> &ptr);
// This will be called to stop/cancel the HTTP request (if possible). Platform-specific implementation.
static void stop(const util::ptr<HTTPRequestBaton> &ptr);
};
}
#endif

View File

@@ -0,0 +1,25 @@
#ifndef MBGL_STORAGE_NETWORK_STATUS
#define MBGL_STORAGE_NETWORK_STATUS
#include <mutex>
#include <set>
typedef struct uv_async_s uv_async_t;
namespace mbgl {
class NetworkStatus {
public:
static void Reachable();
static void Subscribe(uv_async_t *async);
static void Unsubscribe(uv_async_t *async);
private:
static std::mutex mtx;
static std::set<uv_async_t *> observers;
};
}
#endif

View File

@@ -1,41 +0,0 @@
#ifndef MBGL_STORAGE_REQUEST
#define MBGL_STORAGE_REQUEST
#include <mbgl/storage/request_callback.hpp>
#include <mbgl/storage/response.hpp>
#include <mbgl/util/ptr.hpp>
#include <thread>
#include <forward_list>
typedef struct uv_loop_s uv_loop_t;
namespace mbgl {
class BaseRequest;
class Request {
private:
Request(const Request &) = delete;
Request(Request &&) = delete;
Request& operator=(const Request &) = delete;
Request& operator=(Request &&) = delete;
public:
Request(const util::ptr<BaseRequest> &base);
~Request();
void onload(CompletedCallback cb);
void oncancel(AbortedCallback cb);
void cancel();
private:
const std::thread::id thread_id;
util::ptr<BaseRequest> base;
std::forward_list<Callback *> callbacks;
};
}
#endif

View File

@@ -1,22 +0,0 @@
#ifndef MBGL_STORAGE_REQUEST_CALLBACK
#define MBGL_STORAGE_REQUEST_CALLBACK
#include <mbgl/util/variant.hpp>
#include <functional>
namespace mbgl {
class Response;
using CompletedCallback = std::function<void(const Response &)>;
using AbortedCallback = std::function<void()>;
using Callback = mapbox::util::variant<
CompletedCallback,
AbortedCallback
>;
}
#endif

View File

@@ -0,0 +1,35 @@
#ifndef MBGL_STORAGE_RESOURCE
#define MBGL_STORAGE_RESOURCE
#include <string>
#include <functional>
namespace mbgl {
struct Resource {
enum Kind : uint8_t {
Unknown = 0,
Tile = 1,
Glyphs = 2,
Image = 3,
JSON = 4,
};
const Kind kind;
const std::string url;
inline bool operator==(const Resource &res) const {
return kind == res.kind && url == res.url;
}
struct Hash {
std::size_t operator()(Resource const& r) const {
return std::hash<std::string>()(r.url) ^ (std::hash<uint8_t>()(r.kind) << 1);
}
};
};
}
#endif

View File

@@ -1,18 +0,0 @@
#ifndef MBGL_STORAGE_RESOURCE_TYPE
#define MBGL_STORAGE_RESOURCE_TYPE
#include <cstdint>
namespace mbgl {
enum class ResourceType : uint8_t {
Unknown = 0,
Tile = 1,
Glyphs = 2,
Image = 3,
JSON = 4
};
}
#endif

View File

@@ -2,25 +2,21 @@
#define MBGL_STORAGE_RESPONSE
#include <string>
#include <ctime>
namespace mbgl {
class Response {
public:
long code = 0;
enum Status : bool { Error, Successful };
Status status = Error;
std::string message;
int64_t modified = 0;
int64_t expires = 0;
std::string etag;
std::string data;
std::string message;
static int64_t parseCacheControl(const char *value);
};
}
#endif
#endif

View File

@@ -0,0 +1,95 @@
#ifndef MBGL_UTIL_ASYNC_QUEUE
#define MBGL_UTIL_ASYNC_QUEUE
#include "std.hpp"
#include <uv.h>
#include <thread>
#include <mutex>
#include <functional>
#include <queue>
#include <string>
#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
#define UV_ASYNC_PARAMS(handle) uv_async_t *handle, int
#else
#define UV_ASYNC_PARAMS(handle) uv_async_t *handle
#endif
namespace mbgl {
namespace util {
template <typename T>
class AsyncQueue {
public:
AsyncQueue(uv_loop_t *loop, std::function<void(T &)> fn) :
callback(fn) {
async.data = this;
uv_async_init(loop, &async, [](UV_ASYNC_PARAMS(handle)) {
auto q = reinterpret_cast<AsyncQueue *>(handle->data);
q->process();
});
}
void send(T &&data) {
{
std::lock_guard<std::mutex> lock(mutex);
queue.push(util::make_unique<T>(std::move(data)));
}
uv_async_send(&async);
}
void send(std::unique_ptr<T> data) {
{
std::lock_guard<std::mutex> lock(mutex);
queue.push(std::move(data));
}
uv_async_send(&async);
}
void stop() {
uv_close((uv_handle_t *)&async, [](uv_handle_t *handle) {
delete reinterpret_cast<AsyncQueue *>(handle->data);
});
}
void ref() {
uv_ref((uv_handle_t *)&async);
}
void unref() {
uv_unref((uv_handle_t *)&async);
}
private:
~AsyncQueue() {
}
void process() {
std::unique_ptr<T> item;
while (true) {
mutex.lock();
if (queue.empty()) {
mutex.unlock();
break;
}
item = std::move(queue.front());
queue.pop();
mutex.unlock();
callback(*item);
}
}
private:
std::mutex mutex;
uv_async_t async;
std::queue<std::unique_ptr<T>> queue;
std::function<void(T &)> callback;
};
}
}
#endif

View File

@@ -7,41 +7,13 @@
namespace mbgl {
typedef uint64_t timestamp;
namespace util {
// Returns time in nanoseconds since an arbitrary point in the past. This has
// no relation to the current time, but is continuously increasing, so
// comparisons between different timestamps produce meaningful values.
timestamp now();
// Returns the RFC1123 formatted date. E.g. "Tue, 04 Nov 2014 02:13:24 GMT"
std::string rfc1123(std::time_t time);
}
// used for time conversions
constexpr timestamp operator"" _nanoseconds (long double ns) { return ns; }
constexpr timestamp operator"" _nanosecond (long double ns) { return ns; }
constexpr timestamp operator"" _microseconds (long double us) { return us * 1e3; }
constexpr timestamp operator"" _microsecond (long double us) { return us * 1e3; }
constexpr timestamp operator"" _milliseconds (long double ms) { return ms * 1e6; }
constexpr timestamp operator"" _millisecond (long double ms) { return ms * 1e6; }
constexpr timestamp operator"" _seconds (long double s) { return s * 1e9; }
constexpr timestamp operator"" _second (long double s) { return s * 1e9; }
constexpr timestamp operator"" _nanoseconds (unsigned long long ns) { return ns; }
constexpr timestamp operator"" _nanosecond (unsigned long long ns) { return ns; }
constexpr timestamp operator"" _microseconds (unsigned long long us) { return us * 1e3; }
constexpr timestamp operator"" _microsecond (unsigned long long us) { return us * 1e3; }
constexpr timestamp operator"" _milliseconds (unsigned long long ms) { return ms * 1e6; }
constexpr timestamp operator"" _millisecond (unsigned long long ms) { return ms * 1e6; }
constexpr timestamp operator"" _seconds (unsigned long long s) { return s * 1e9; }
constexpr timestamp operator"" _second (unsigned long long s) { return s * 1e9; }
}
#endif

View File

@@ -0,0 +1,17 @@
#ifndef MBGL_UTIL_UTIL
#define MBGL_UTIL_UTIL
#ifdef DEBUG
#include <thread>
#define MBGL_STORE_THREAD(tid) const std::thread::id tid = std::this_thread::get_id();
#define MBGL_VERIFY_THREAD(tid) assert(tid == std::this_thread::get_id());
#else
#define MBGL_STORE_THREAD(tid)
#define MBGL_VERIFY_THREAD(tid)
#endif
#endif

View File

@@ -3,10 +3,11 @@
#include <string>
typedef struct uv_handle_s uv_handle_t;
typedef struct uv_async_s uv_async_t;
typedef struct uv_timer_s uv_timer_t;
typedef struct uv_handle_s uv_handle_t;
typedef struct uv_loop_s uv_loop_t;
typedef struct uv_fs_s uv_fs_t;
namespace uv {
@@ -19,6 +20,15 @@ class worker;
class mutex;
class cond;
const char *getFileRequestError(uv_fs_t *req);
template <typename T>
void close(T *specific) {
uv_close(reinterpret_cast<uv_handle_t *>(specific), [](uv_handle_t *generic) {
delete reinterpret_cast<T *>(generic);
});
}
}
#endif

View File

@@ -10,7 +10,7 @@
#include <iosfwd>
#include <string>
#include <mbgl/util/recursive_wrapper.hpp>
#include "recursive_wrapper.hpp"
#ifdef _MSC_VER
// http://msdn.microsoft.com/en-us/library/z8y1yy88.aspx
@@ -34,7 +34,19 @@
// translates to 100
#define VARIANT_VERSION (VARIANT_MAJOR_VERSION*100000) + (VARIANT_MINOR_VERSION*100) + (VARIANT_PATCH_VERSION)
namespace mapbox { namespace util { namespace detail {
namespace mapbox { namespace util {
// static visitor
template <typename R = void>
struct static_visitor
{
using result_type = R;
protected:
static_visitor() {}
~static_visitor() {}
};
namespace detail {
static constexpr std::size_t invalid_value = std::size_t(-1);
@@ -109,18 +121,38 @@ struct select_type<0, T, Types...>
using type = T;
};
} // namespace detail
// static visitor
template <typename R = void>
struct static_visitor
template <typename T, typename R = void>
struct enable_if_type { using type = R; };
template <typename F, typename V, typename Enable = void>
struct result_of_unary_visit
{
using result_type = R;
protected:
static_visitor() {}
~static_visitor() {}
using type = typename std::result_of<F(V&)>::type;
};
template <typename F, typename V>
struct result_of_unary_visit<F, V, typename enable_if_type<typename F::result_type>::type >
{
using type = typename F::result_type;
};
template <typename F, typename V, class Enable = void>
struct result_of_binary_visit
{
using type = typename std::result_of<F(V&,V&)>::type;
};
template <typename F, typename V>
struct result_of_binary_visit<F, V, typename enable_if_type<typename F::result_type>::type >
{
using type = typename F::result_type;
};
} // namespace detail
template <std::size_t arg1, std::size_t ... others>
struct static_max;
@@ -225,7 +257,7 @@ struct dispatcher;
template <typename F, typename V, typename T, typename...Types>
struct dispatcher<F, V, T, Types...>
{
using result_type = typename F::result_type;
using result_type = typename detail::result_of_unary_visit<F, V>::type;
VARIANT_INLINE static result_type apply_const(V const& v, F f)
{
if (v.get_type_index() == sizeof...(Types))
@@ -254,7 +286,7 @@ struct dispatcher<F, V, T, Types...>
template<typename F, typename V>
struct dispatcher<F, V>
{
using result_type = typename F::result_type;
using result_type = typename detail::result_of_unary_visit<F, V>::type;
VARIANT_INLINE static result_type apply_const(V const&, F)
{
throw std::runtime_error(std::string("unary dispatch: FAIL ") + typeid(V).name());
@@ -273,7 +305,7 @@ struct binary_dispatcher_rhs;
template <typename F, typename V, typename T0, typename T1, typename...Types>
struct binary_dispatcher_rhs<F, V, T0, T1, Types...>
{
using result_type = typename F::result_type;
using result_type = typename detail::result_of_binary_visit<F, V>::type;
VARIANT_INLINE static result_type apply_const(V const& lhs, V const& rhs, F f)
{
if (rhs.get_type_index() == sizeof...(Types)) // call binary functor
@@ -305,7 +337,7 @@ struct binary_dispatcher_rhs<F, V, T0, T1, Types...>
template<typename F, typename V, typename T>
struct binary_dispatcher_rhs<F, V, T>
{
using result_type = typename F::result_type;
using result_type = typename detail::result_of_binary_visit<F, V>::type;
VARIANT_INLINE static result_type apply_const(V const&, V const&, F)
{
throw std::runtime_error("binary dispatch: FAIL");
@@ -323,7 +355,7 @@ struct binary_dispatcher_lhs;
template <typename F, typename V, typename T0, typename T1, typename...Types>
struct binary_dispatcher_lhs<F, V, T0, T1, Types...>
{
using result_type = typename F::result_type;
using result_type = typename detail::result_of_binary_visit<F, V>::type;
VARIANT_INLINE static result_type apply_const(V const& lhs, V const& rhs, F f)
{
if (lhs.get_type_index() == sizeof...(Types)) // call binary functor
@@ -353,7 +385,7 @@ struct binary_dispatcher_lhs<F, V, T0, T1, Types...>
template<typename F, typename V, typename T>
struct binary_dispatcher_lhs<F, V, T>
{
using result_type = typename F::result_type;
using result_type = typename detail::result_of_binary_visit<F, V>::type;
VARIANT_INLINE static result_type apply_const(V const&, V const&, F)
{
throw std::runtime_error("binary dispatch: FAIL");
@@ -371,7 +403,7 @@ struct binary_dispatcher;
template <typename F, typename V, typename T, typename...Types>
struct binary_dispatcher<F, V, T, Types...>
{
using result_type = typename F::result_type;
using result_type = typename detail::result_of_binary_visit<F, V>::type;
VARIANT_INLINE static result_type apply_const(V const& v0, V const& v1, F f)
{
if (v0.get_type_index() == sizeof...(Types))
@@ -416,7 +448,7 @@ struct binary_dispatcher<F, V, T, Types...>
template<typename F, typename V>
struct binary_dispatcher<F, V>
{
using result_type = typename F::result_type;
using result_type = typename detail::result_of_binary_visit<F, V>::type;
VARIANT_INLINE static result_type apply_const(V const&, V const&, F)
{
throw std::runtime_error("binary dispatch: FAIL");
@@ -448,7 +480,7 @@ struct less_comp
};
template <typename Variant, typename Comp>
class comparer : public static_visitor<bool>
class comparer
{
public:
explicit comparer(Variant const& lhs) noexcept
@@ -467,7 +499,7 @@ private:
// operator<< helper
template <typename Out>
class printer : public static_visitor<>
class printer
{
public:
explicit printer(Out & out)

View File

@@ -4,7 +4,8 @@
#include <mbgl/platform/default/settings_json.hpp>
#include <mbgl/platform/default/glfw_view.hpp>
#include <mbgl/platform/default/log_stderr.hpp>
#include <mbgl/storage/caching_http_file_source.hpp>
#include <mbgl/storage/default_file_source.hpp>
#include <mbgl/storage/default/sqlite_cache.hpp>
#include <signal.h>
#include <getopt.h>
@@ -64,7 +65,9 @@ int main(int argc, char *argv[]) {
sigaction(SIGINT, &sigIntHandler, NULL);
view = new GLFWView();
mbgl::CachingHTTPFileSource fileSource(mbgl::platform::defaultCacheDatabase());
mbgl::SQLiteCache cache("/tmp/mbgl-cache.db");
mbgl::DefaultFileSource fileSource(&cache);
mbgl::Map map(*view, fileSource);
// Load settings
@@ -78,12 +81,13 @@ int main(int argc, char *argv[]) {
if (token == nullptr) {
mbgl::Log::Warning(mbgl::Event::Setup, "no access token set. mapbox.com tiles won't work.");
} else {
fileSource.setAccessToken(std::string(token));
map.setAccessToken(std::string(token));
}
// Load style
if (style.empty())
if (style.empty()) {
style = std::string("asset://") + std::string("styles/bright-v7.json");
}
map.setStyleURL(style);

View File

@@ -3,55 +3,52 @@
'../gyp/common.gypi',
],
'targets': [
{
'target_name': 'linuxapp',
{ 'target_name': 'linuxapp',
'product_name': 'mapbox-gl',
'type': 'executable',
'dependencies': [
'../mbgl.gyp:core',
'../mbgl.gyp:platform-<(platform_lib)',
'../mbgl.gyp:http-<(http_lib)',
'../mbgl.gyp:asset-<(asset_lib)',
'../mbgl.gyp:cache-<(cache_lib)',
'../mbgl.gyp:bundle_styles',
'../mbgl.gyp:copy_certificate_bundle',
],
'sources': [
'./main.cpp',
'main.cpp',
'../platform/default/settings_json.cpp',
'../platform/default/glfw_view.cpp',
'../platform/default/log_stderr.cpp',
],
'xcode_settings': {
'OTHER_CPLUSPLUSFLAGS':[
'variables' : {
'cflags_cc': [
'<@(glfw3_cflags)',
'<@(png_cflags)',
'<@(jpeg_cflags)',
],
},
'cflags_cc': [
'<@(glfw3_cflags)',
'<@(png_cflags)',
'<@(jpeg_cflags)',
'-I<(boost_root)/include',
],
'variables': {
'ldflags': [
'<@(png_ldflags)',
'<@(sqlite3_static_libs)',
'<@(sqlite3_ldflags)',
'<@(glfw3_static_libs)',
'<@(glfw3_ldflags)',
'<@(curl_ldflags)',
'<@(zlib_ldflags)',
],
'libraries': [
'<@(glfw3_static_libs)',
],
},
'conditions': [
['OS == "mac"', {
'libraries': [ '<@(libraries)' ],
'xcode_settings': {
'OTHER_CPLUSPLUSFLAGS': [ '<@(cflags_cc)' ],
'OTHER_LDFLAGS': [ '<@(ldflags)' ],
}
}, {
'libraries': [ '<@(ldflags)' ],
'cflags_cc': [ '<@(cflags_cc)' ],
'libraries': [ '<@(libraries)', '<@(ldflags)' ],
}]
],
'dependencies': [
'../mapboxgl.gyp:mbgl-standalone',
'../mapboxgl.gyp:mbgl-linux',
'../mapboxgl.gyp:bundle_styles',
'../mapboxgl.gyp:copy_certificate_bundle',
],
'copies': [{
'files': [ '../styles/styles' ],
'destination': '<(PRODUCT_DIR)'

View File

@@ -3,7 +3,9 @@
#include <mbgl/platform/darwin/log_nslog.hpp>
#include <mbgl/platform/darwin/Reachability.h>
#include <mbgl/platform/default/glfw_view.hpp>
#include <mbgl/storage/caching_http_file_source.hpp>
#include <mbgl/storage/default_file_source.hpp>
#include <mbgl/storage/default/sqlite_cache.hpp>
#include <mbgl/storage/network_status.hpp>
#import <Foundation/Foundation.h>
@@ -70,13 +72,39 @@
}
@end
// Returns the path to the default cache database on this system.
const std::string &defaultCacheDatabase() {
static const std::string path = []() -> std::string {
NSArray *paths = NSSearchPathForDirectoriesInDomains(
NSApplicationSupportDirectory, NSUserDomainMask, YES);
if ([paths count] == 0) {
// Disable the cache if we don't have a location to write.
return "";
}
NSString *p = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"Mapbox GL"];
if (![[NSFileManager defaultManager] createDirectoryAtPath:p
withIntermediateDirectories:YES
attributes:nil
error:nil]) {
// Disable the cache if we couldn't create the directory.
return "";
}
return [[p stringByAppendingPathComponent:@"cache.db"] UTF8String];
}();
return path;
}
int main() {
mbgl::Log::Set<mbgl::NSLogBackend>();
GLFWView view;
mbgl::CachingHTTPFileSource fileSource(mbgl::platform::defaultCacheDatabase());
mbgl::SQLiteCache cache(defaultCacheDatabase());
mbgl::DefaultFileSource fileSource(&cache);
mbgl::Map map(view, fileSource);
mbgl::CachingHTTPFileSource *fileSourcePtr = &fileSource;
URLHandler *handler = [[URLHandler alloc] init];
[handler setMap:&map];
@@ -86,7 +114,7 @@ int main() {
// Notify map object when network reachability status changes.
Reachability* reachability = [Reachability reachabilityForInternetConnection];
reachability.reachableBlock = ^(Reachability *) {
fileSourcePtr->setReachability(true);
mbgl::NetworkStatus::Reachable();
};
[reachability startNotifier];
@@ -99,7 +127,7 @@ int main() {
// Set access token if present
NSString *accessToken = [[NSProcessInfo processInfo] environment][@"MAPBOX_ACCESS_TOKEN"];
if (!accessToken) mbgl::Log::Warning(mbgl::Event::Setup, "No access token set. Mapbox vector tiles won't work.");
if (accessToken) fileSource.setAccessToken([accessToken cStringUsingEncoding:[NSString defaultCStringEncoding]]);
if (accessToken) map.setAccessToken([accessToken cStringUsingEncoding:[NSString defaultCStringEncoding]]);
// Load style
map.setStyleURL("asset://styles/bright-v7.json");

View File

@@ -3,10 +3,24 @@
'../gyp/common.gypi',
],
'targets': [
{
'target_name': 'osxapp',
{ 'target_name': 'osxapp',
'product_name': 'Mapbox GL',
'type': 'executable',
'product_extension': 'app',
'mac_bundle': 1,
'mac_bundle_resources': [
'Icon.icns',
],
'dependencies': [
'../mbgl.gyp:bundle_styles',
'../mbgl.gyp:core',
'../mbgl.gyp:platform-<(platform_lib)',
'../mbgl.gyp:http-<(http_lib)',
'../mbgl.gyp:asset-<(asset_lib)',
'../mbgl.gyp:cache-<(cache_lib)',
],
'sources': [
'./main.mm',
'../platform/darwin/settings_nsuserdefaults.hpp',
@@ -15,51 +29,34 @@
'../platform/default/glfw_view.hpp',
'../platform/default/glfw_view.cpp',
],
'product_extension': 'app',
'mac_bundle': 1,
'mac_bundle_resources': [
'Icon.icns',
'variables' : {
'cflags_cc': [
'<@(glfw3_cflags)',
],
'ldflags': [
'-framework SystemConfiguration', # For NSUserDefaults and Reachability
'<@(glfw3_ldflags)',
],
'libraries': [
'<@(glfw3_static_libs)',
],
},
'libraries': [
'<@(libraries)',
],
'xcode_settings': {
'SDKROOT': 'macosx',
'SUPPORTED_PLATFORMS':'macosx',
'OTHER_CPLUSPLUSFLAGS': [
'<@(glfw3_cflags)'
],
'OTHER_LDFLAGS': [
'<@(glfw3_ldflags)',
'-framework SystemConfiguration',
],
'OTHER_CPLUSPLUSFLAGS': [ '<@(cflags_cc)' ],
'OTHER_LDFLAGS': [ '<@(ldflags)' ],
'SDKROOT': 'macosx',
'INFOPLIST_FILE': 'Info.plist',
'MACOSX_DEPLOYMENT_TARGET':'10.9',
'MACOSX_DEPLOYMENT_TARGET': '10.9',
'CLANG_ENABLE_OBJC_ARC': 'YES'
},
'variables' : {
'ldflags': [
'<@(uv_ldflags)',
'<@(uv_static_libs)',
'<@(sqlite3_static_libs)',
'<@(sqlite3_ldflags)',
'<@(glfw3_static_libs)',
'<@(glfw3_ldflags)',
'<@(zlib_ldflags)',
]
},
'conditions': [
['OS == "mac"', {
'xcode_settings': {
'OTHER_LDFLAGS': [ '<@(ldflags)' ],
}
}, {
'ldflags': [ '<@(ldflags)' ],
}]
],
'dependencies': [
'../mapboxgl.gyp:bundle_styles',
'../mapboxgl.gyp:mbgl-core',
'../mapboxgl.gyp:mbgl-osx',
]
}
]
}

View File

@@ -1,13 +0,0 @@
{
'includes': [
'./gyp/common.gypi',
'./gyp/shaders.gypi',
'./gyp/version.gypi',
'./gyp/styles.gypi',
'./gyp/certificates.gypi',
'./gyp/mbgl-core.gypi',
'./gyp/mbgl-platform.gypi',
'./gyp/mbgl-headless.gypi',
'./gyp/install.gypi',
],
}

26
mbgl.gyp Normal file
View File

@@ -0,0 +1,26 @@
{
'includes': [
'./gyp/common.gypi',
'./gyp/shaders.gypi',
'./gyp/version.gypi',
'./gyp/styles.gypi',
'./gyp/certificates.gypi',
'./gyp/standalone.gypi',
'./gyp/core.gypi',
'./gyp/none.gypi',
'./gyp/install.gypi',
],
'conditions': [
['headless_lib == "cgl"', { 'includes': [ './gyp/headless-cgl.gypi' ] } ],
['headless_lib == "glx"', { 'includes': [ './gyp/headless-glx.gypi' ] } ],
['platform_lib == "osx"', { 'includes': [ './gyp/platform-osx.gypi' ] } ],
['platform_lib == "ios"', { 'includes': [ './gyp/platform-ios.gypi' ] } ],
['platform_lib == "linux"', { 'includes': [ './gyp/platform-linux.gypi' ] } ],
['platform_lib == "android"', { 'includes': [ './gyp/platform-android.gypi' ] } ],
['http_lib == "curl"', { 'includes': [ './gyp/http-curl.gypi' ] } ],
['http_lib == "nsurl"', { 'includes': [ './gyp/http-nsurl.gypi' ] } ],
['asset_lib == "fs"', { 'includes': [ './gyp/asset-fs.gypi' ] } ],
['asset_lib == "zip"', { 'includes': [ './gyp/asset-zip.gypi' ] } ],
['cache_lib == "sqlite"', { 'includes': [ './gyp/cache-sqlite.gypi' ] } ],
],
}

View File

@@ -1,202 +0,0 @@
#include <mbgl/android/jni.hpp>
#include <mbgl/storage/asset_request.hpp>
#include <mbgl/storage/response.hpp>
#include <mbgl/util/uv_detail.hpp>
#include <mbgl/util/std.hpp>
#include <cerrno>
// NOTE a bug in the Android NDK breaks std::errno
// See https://code.google.com/p/android/issues/detail?id=72349
// After this is fixed change usage errno to std::errno
#include <zip.h>
namespace mbgl {
struct AssetRequestBaton {
AssetRequestBaton(AssetRequest *request_, const std::string &path, uv_loop_t *loop);
~AssetRequestBaton();
const std::thread::id threadId;
AssetRequest *request = nullptr;
std::unique_ptr<uv::async> asyncRun;
std::string path;
bool canceled = false;
void cancel();
static void notifyError(AssetRequestBaton *ptr, const int code, const char *message);
static void notifySuccess(AssetRequestBaton *ptr, const std::string body);
static void cleanup(AssetRequestBaton *ptr);
static void run(AssetRequestBaton *ptr);
};
AssetRequestBaton::AssetRequestBaton(AssetRequest *request_, const std::string &path_, uv_loop_t *loop)
: threadId(std::this_thread::get_id()),
request(request_),
path(path_) {
asyncRun = mbgl::util::make_unique<uv::async>(loop, [this]() {
run(this);
});
asyncRun->send();
}
AssetRequestBaton::~AssetRequestBaton() {
}
void AssetRequestBaton::cancel() {
canceled = true;
}
void AssetRequestBaton::notifyError(AssetRequestBaton *ptr, const int code, const char *message) {
assert(std::this_thread::get_id() == ptr->threadId);
if (ptr->request && !ptr->canceled) {
ptr->request->response = std::unique_ptr<Response>(new Response);
ptr->request->response->code = code;
ptr->request->response->message = message;
ptr->request->notify();
}
}
void AssetRequestBaton::notifySuccess(AssetRequestBaton *ptr, const std::string body) {
assert(std::this_thread::get_id() == ptr->threadId);
if (ptr->request && !ptr->canceled) {
ptr->request->response = std::unique_ptr<Response>(new Response);
ptr->request->response->code = 200;
ptr->request->response->data = body;
ptr->request->notify();
}
}
void AssetRequestBaton::cleanup(AssetRequestBaton *ptr) {
assert(std::this_thread::get_id() == ptr->threadId);
if (ptr->request) {
ptr->request->ptr = nullptr;
}
ptr->asyncRun.reset();
delete ptr;
ptr = nullptr;
}
void AssetRequestBaton::run(AssetRequestBaton *ptr) {
assert(std::this_thread::get_id() == ptr->threadId);
if (ptr->canceled || !ptr->request) {
// Either the AssetRequest object has been destructed, or the
// request was canceled.
cleanup(ptr);
return;
}
int error = 0;
struct zip *apk = zip_open(mbgl::android::apkPath.c_str(), 0, &error);
if ((apk == nullptr) || ptr->canceled || !ptr->request) {
// Opening the APK failed or was canceled. There isn't much left we can do.
const int messageSize = zip_error_to_str(nullptr, 0, error, errno);
const std::unique_ptr<char[]> message = mbgl::util::make_unique<char[]>(messageSize);
zip_error_to_str(message.get(), 0, error, errno);
notifyError(ptr, 500, message.get());
cleanup(ptr);
return;
}
std::string apkFilePath = "assets/" + ptr->path;
struct zip_file *apkFile = zip_fopen(apk, apkFilePath.c_str(), ZIP_FL_NOCASE);
if ((apkFile == nullptr) || ptr->canceled || !ptr->request) {
// Opening the asset failed or was canceled. We already have an open file handle
// though, which we'll have to close.
zip_error_get(apk, &error, nullptr);
notifyError(ptr, error == ZIP_ER_NOENT ? 404 : 500, zip_strerror(apk));
zip_close(apk);
apk = nullptr;
cleanup(ptr);
return;
}
struct zip_stat stat;
if ((zip_stat(apk, apkFilePath.c_str(), ZIP_FL_NOCASE, &stat) != 0) || ptr->canceled || !ptr->request) {
// Stating failed or was canceled. We already have an open file handle
// though, which we'll have to close.
notifyError(ptr, 500, zip_strerror(apk));
zip_fclose(apkFile);
apkFile = nullptr;
zip_close(apk);
apk = nullptr;
cleanup(ptr);
return;
}
const std::unique_ptr<char[]> data = mbgl::util::make_unique<char[]>(stat.size);
if (static_cast<zip_uint64_t>(zip_fread(apkFile, reinterpret_cast<void *>(data.get()), stat.size)) != stat.size || ptr->canceled || !ptr->request) {
// Reading failed or was canceled. We already have an open file handle
// though, which we'll have to close.
notifyError(ptr, 500, zip_file_strerror(apkFile));
zip_fclose(apkFile);
apkFile = nullptr;
zip_close(apk);
apk = nullptr;
cleanup(ptr);
return;
}
std::string body(data.get(), stat.size);
notifySuccess(ptr, body);
if (zip_fclose(apkFile) != 0) {
// Closing the asset failed. But there isn't anything we can do.
}
apkFile = nullptr;
if (zip_close(apk) != 0) {
// Closing the APK failed. But there isn't anything we can do.
}
apk = nullptr;
cleanup(ptr);
}
AssetRequest::AssetRequest(const std::string &path_, uv_loop_t *loop)
: BaseRequest(path_) {
if (!path.empty() && path[0] == '/') {
// This is an absolute path. We don't allow this. Note that this is not a way to absolutely
// prevent access to resources outside the application bundle; e.g. there could be symlinks
// in the application bundle that link to outside. We don't care about these.
response = util::make_unique<Response>();
response->code = 403;
response->message = "Path is outside the application bundle";
notify();
} else {
// Note: The AssetRequestBaton object is deleted in AssetRequestBaton::cleanup().
ptr = new AssetRequestBaton(this, path, loop);
}
}
void AssetRequest::cancel() {
assert(std::this_thread::get_id() == threadId);
if (ptr) {
ptr->cancel();
// When deleting a AssetRequest object with a uv_fs_* call is in progress, we are making sure
// that the callback doesn't accidentally reference this object again.
ptr->request = nullptr;
ptr = nullptr;
}
notify();
}
AssetRequest::~AssetRequest() {
assert(std::this_thread::get_id() == threadId);
cancel();
// Note: The AssetRequestBaton object is deleted in AssetRequestBaton::cleanup().
}
}

View File

@@ -1,13 +0,0 @@
#include <mbgl/platform/platform.hpp>
#include <mbgl/android/jni.hpp>
namespace mbgl {
namespace platform {
// Returns the path to the default cache database on this system.
std::string defaultCacheDatabase() {
return mbgl::android::cachePath + "/mbgl-cache.db";
}
}
}

View File

@@ -5,8 +5,8 @@
namespace mbgl {
namespace platform {
// Returns the path to the default shader cache on this system.
std::string applicationRoot() {
// Returns the path to the root folder of the application.
const std::string &applicationRoot() {
static const std::string root = []() -> std::string {
NSString *path = [[[NSBundle mainBundle] resourceURL] path];
return {[path cStringUsingEncoding : NSUTF8StringEncoding],

View File

@@ -0,0 +1,18 @@
#import <Foundation/Foundation.h>
#include <mbgl/platform/platform.hpp>
namespace mbgl {
namespace platform {
// Returns the path to the root folder of the application.
const std::string &assetRoot() {
static const std::string root = []() -> std::string {
NSString *path = [[[NSBundle mainBundle] resourceURL] path];
return {[path cStringUsingEncoding : NSUTF8StringEncoding],
[path lengthOfBytesUsingEncoding:NSUTF8StringEncoding]};
}();
return root;
}
}
}

View File

@@ -1,155 +0,0 @@
#include <mbgl/storage/http_request_baton.hpp>
#include <mbgl/util/std.hpp>
#include <mbgl/util/parsedate.h>
#include <mbgl/util/time.hpp>
#include <mbgl/util/version.hpp>
#include <uv.h>
#include <mbgl/util/uv.hpp>
#import <Foundation/Foundation.h>
namespace mbgl {
dispatch_once_t request_initialize = 0;
NSURLSession *session = nullptr;
NSString *userAgent = nil;
void HTTPRequestBaton::start(const util::ptr<HTTPRequestBaton> &ptr) {
assert(std::this_thread::get_id() == ptr->threadId);
// Starts the request.
util::ptr<HTTPRequestBaton> baton = ptr;
dispatch_once(&request_initialize, ^{
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
sessionConfig.timeoutIntervalForResource = 30;
sessionConfig.HTTPMaximumConnectionsPerHost = 8;
sessionConfig.requestCachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
sessionConfig.URLCache = nil;
session = [NSURLSession sessionWithConfiguration:sessionConfig];
// Write user agent string
NSDictionary *systemVersion = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"];
userAgent = [NSString stringWithFormat:@"MapboxGL/%d.%d.%d (+https://mapbox.com/mapbox-gl/; %s; %@ %@)",
version::major, version::minor, version::patch, version::revision,
[systemVersion objectForKey:@"ProductName"],
[systemVersion objectForKey:@"ProductVersion"]
];
});
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@(baton->path.c_str())]];
if (baton->response) {
if (!baton->response->etag.empty()) {
[request addValue:@(baton->response->etag.c_str()) forHTTPHeaderField:@"If-None-Match"];
} else if (baton->response->modified) {
const std::string time = util::rfc1123(baton->response->modified);
[request addValue:@(time.c_str()) forHTTPHeaderField:@"If-Modified-Since"];
}
}
[request addValue:userAgent forHTTPHeaderField:@"User-Agent"];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *res, NSError *error) {
if (error) {
if ([error code] == NSURLErrorCancelled) {
// The response code remains at 0 to indicate cancelation.
// In addition, we don't need any response object.
baton->response.reset();
baton->type = HTTPResponseType::Canceled;
} else {
// TODO: Use different codes for host not found, timeout, invalid URL etc.
// These can be categorized in temporary and permanent errors.
baton->response = util::make_unique<Response>();
baton->response->code = [(NSHTTPURLResponse *)res statusCode];
baton->response->message = [[error localizedDescription] UTF8String];
switch ([error code]) {
case NSURLErrorBadServerResponse: // 5xx errors
baton->type = HTTPResponseType::TemporaryError;
break;
case NSURLErrorTimedOut:
case NSURLErrorUserCancelledAuthentication:
baton->type = HTTPResponseType::SingularError; // retry immediately
break;
case NSURLErrorNetworkConnectionLost:
case NSURLErrorCannotFindHost:
case NSURLErrorCannotConnectToHost:
case NSURLErrorDNSLookupFailed:
case NSURLErrorNotConnectedToInternet:
case NSURLErrorInternationalRoamingOff:
case NSURLErrorCallIsActive:
case NSURLErrorDataNotAllowed:
baton->type = HTTPResponseType::ConnectionError;
break;
default:
baton->type = HTTPResponseType::PermanentError;
}
}
} else if ([res isKindOfClass:[NSHTTPURLResponse class]]) {
const long code = [(NSHTTPURLResponse *)res statusCode];
if (code == 304) {
// Assume a Response object already exists.
assert(baton->response);
} else {
baton->response = util::make_unique<Response>();
baton->response->code = code;
baton->response->data = {(const char *)[data bytes], [data length]};
}
if (code == 304) {
baton->type = HTTPResponseType::NotModified;
} else if (code == 200) {
baton->type = HTTPResponseType::Successful;
} else {
baton->type = HTTPResponseType::PermanentError;
}
NSDictionary *headers = [(NSHTTPURLResponse *)res allHeaderFields];
NSString *cache_control = [headers objectForKey:@"Cache-Control"];
if (cache_control) {
baton->response->expires = Response::parseCacheControl([cache_control UTF8String]);
}
NSString *last_modified = [headers objectForKey:@"Last-Modified"];
if (last_modified) {
baton->response->modified = parse_date([last_modified UTF8String]);
}
NSString *etag = [headers objectForKey:@"ETag"];
if (etag) {
baton->response->etag = [etag UTF8String];
}
} else {
// This should never happen.
baton->type = HTTPResponseType::PermanentError;
baton->response = util::make_unique<Response>();
baton->response->code = -1;
baton->response->message = "response class is not NSHTTPURLResponse";
}
uv_async_send(baton->async);
}];
[task resume];
baton->ptr = const_cast<void *>(CFBridgingRetain(task));
}
void HTTPRequestBaton::stop(const util::ptr<HTTPRequestBaton> &ptr) {
assert(std::this_thread::get_id() == ptr->threadId);
assert(ptr->ptr);
NSURLSessionDataTask *task = CFBridgingRelease(ptr->ptr);
ptr->ptr = nullptr;
[task cancel];
}
}

View File

@@ -0,0 +1,419 @@
#include <mbgl/storage/default/http_request.hpp>
#include <mbgl/storage/default/http_context.hpp>
#include <mbgl/storage/response.hpp>
#include <mbgl/util/uv.hpp>
#include <mbgl/util/time.hpp>
#include <mbgl/util/parsedate.h>
#import <Foundation/Foundation.h>
#include <map>
#include <cassert>
namespace mbgl {
enum class ResponseStatus : uint8_t {
// This error probably won't be resolved by retrying anytime soon. We are giving up.
PermanentError,
// This error might be resolved by waiting some time (e.g. server issues).
// We are going to do an exponential back-off and will try again in a few seconds.
TemporaryError,
// This error was caused by a temporary error and it is likely that it will be resolved
// immediately. We are going to try again right away. This is like the TemporaryError, except
// that we will not perform exponential back-off.
SingularError,
// This error might be resolved once the network reachability status changes.
// We are going to watch the network status for changes and will retry as soon as the
// operating system notifies us of a network status change.
ConnectionError,
// The request was canceled mid-way.
Canceled,
// The request returned data successfully. We retrieved and decoded the data successfully.
Successful,
// The request confirmed that the data wasn't changed. We already have the data.
NotModified,
};
// -------------------------------------------------------------------------------------------------
class HTTPNSURLContext;
class HTTPRequestImpl {
public:
HTTPRequestImpl(HTTPRequest *request, uv_loop_t *loop, std::unique_ptr<Response> response);
~HTTPRequestImpl();
void cancel();
void cancelTimer();
void start();
void handleResult(NSData *data, NSURLResponse *res, NSError *error);
void handleResponse();
void retry(uint64_t timeout);
void retryImmediately();
static void restart(uv_timer_t *timer, int);
private:
HTTPNSURLContext *context = nullptr;
HTTPRequest *request = nullptr;
NSURLSessionDataTask *task = nullptr;
std::unique_ptr<Response> response;
std::unique_ptr<Response> existingResponse;
ResponseStatus status = ResponseStatus::PermanentError;
uv_async_t *async = nullptr;
int attempts = 0;
uv_timer_t *timer = nullptr;
enum : bool { PreemptImmediately, ExponentialBackoff } strategy = PreemptImmediately;
static const int maxAttempts = 4;
};
// -------------------------------------------------------------------------------------------------
class HTTPNSURLContext : public HTTPContext<HTTPNSURLContext> {
public:
HTTPNSURLContext(uv_loop_t *loop);
~HTTPNSURLContext();
NSURLSession *session = nil;
NSString *userAgent = nil;
};
template<> pthread_key_t ThreadContext<HTTPNSURLContext>::key{};
template<> pthread_once_t ThreadContext<HTTPNSURLContext>::once = PTHREAD_ONCE_INIT;
HTTPNSURLContext::HTTPNSURLContext(uv_loop_t *loop_) : HTTPContext(loop_) {
@autoreleasepool {
NSURLSessionConfiguration *sessionConfig =
[NSURLSessionConfiguration defaultSessionConfiguration];
sessionConfig.timeoutIntervalForResource = 30;
sessionConfig.HTTPMaximumConnectionsPerHost = 8;
sessionConfig.requestCachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
sessionConfig.URLCache = nil;
session = [NSURLSession sessionWithConfiguration:sessionConfig];
[session retain];
// Write user agent string
userAgent = @"MapboxGL";
}
}
HTTPNSURLContext::~HTTPNSURLContext() {
[session release];
session = nullptr;
[userAgent release];
userAgent = nullptr;
}
// -------------------------------------------------------------------------------------------------
HTTPRequestImpl::HTTPRequestImpl(HTTPRequest *request_, uv_loop_t *loop,
std::unique_ptr<Response> existingResponse_)
: context(HTTPNSURLContext::Get(loop)),
request(request_),
existingResponse(std::move(existingResponse_)),
async(new uv_async_t) {
assert(request);
context->addRequest(request);
async->data = this;
uv_async_init(loop, async, [](uv_async_t *as, int) {
auto impl = reinterpret_cast<HTTPRequestImpl *>(as->data);
impl->handleResponse();
});
start();
}
void HTTPRequestImpl::start() {
assert(!task);
attempts++;
@autoreleasepool {
NSMutableURLRequest *req = [[NSMutableURLRequest alloc]
initWithURL:[NSURL URLWithString:@(request->resource.url.c_str())]];
if (existingResponse) {
if (!existingResponse->etag.empty()) {
[req addValue:@(existingResponse->etag.c_str()) forHTTPHeaderField:@"If-None-Match"];
} else if (existingResponse->modified) {
const std::string time = util::rfc1123(existingResponse->modified);
[req addValue:@(time.c_str()) forHTTPHeaderField:@"If-Modified-Since"];
}
}
[req addValue:context->userAgent forHTTPHeaderField:@"User-Agent"];
task = [context->session dataTaskWithRequest:req
completionHandler:^(NSData *data, NSURLResponse *res,
NSError *error) { handleResult(data, res, error); }];
[req release];
[task retain];
[task resume];
}
}
void HTTPRequestImpl::handleResponse() {
if (task) {
[task release];
task = nullptr;
}
if (request) {
if (status == ResponseStatus::TemporaryError && attempts < maxAttempts) {
strategy = ExponentialBackoff;
return retry((1 << (attempts - 1)) * 1000);
} else if (status == ResponseStatus::ConnectionError && attempts < maxAttempts) {
// By default, we will retry every 30 seconds (network change notification will
// preempt the timeout).
strategy = PreemptImmediately;
return retry(30000);
}
// Actually return the response.
if (status == ResponseStatus::NotModified) {
request->notify(std::move(response), FileCache::Hint::Refresh);
} else {
request->notify(std::move(response), FileCache::Hint::Full);
}
context->removeRequest(request);
delete request;
request = nullptr;
}
delete this;
}
void HTTPRequestImpl::cancel() {
context->removeRequest(request);
request = nullptr;
// Stop the backoff timer to avoid re-triggering this request.
cancelTimer();
if (task) {
[task cancel];
[task release];
task = nullptr;
}
}
void HTTPRequestImpl::cancelTimer() {
if (timer) {
uv_timer_stop(timer);
uv::close(timer);
timer = nullptr;
}
}
HTTPRequestImpl::~HTTPRequestImpl() {
assert(!task);
assert(async);
// Stop the backoff timer to avoid re-triggering this request.
cancelTimer();
uv::close(async);
if (request) {
context->removeRequest(request);
request->ptr = nullptr;
}
}
int64_t parseCacheControl(const char *value) {
if (value) {
unsigned long long seconds = 0;
// TODO: cache-control may contain other information as well:
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
if (std::sscanf(value, "max-age=%llu", &seconds) == 1) {
return std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::system_clock::now().time_since_epoch()).count() +
seconds;
}
}
return 0;
}
void HTTPRequestImpl::handleResult(NSData *data, NSURLResponse *res, NSError *error) {
if (error) {
if ([error code] == NSURLErrorCancelled) {
status = ResponseStatus::Canceled;
} else {
// TODO: Use different codes for host not found, timeout, invalid URL etc.
// These can be categorized in temporary and permanent errors.
response = util::make_unique<Response>();
response->status = Response::Error;
response->message = [[error localizedDescription] UTF8String];
switch ([error code]) {
case NSURLErrorBadServerResponse: // 5xx errors
status = ResponseStatus::TemporaryError;
break;
case NSURLErrorTimedOut:
case NSURLErrorUserCancelledAuthentication:
status = ResponseStatus::SingularError; // retry immediately
break;
case NSURLErrorNetworkConnectionLost:
case NSURLErrorCannotFindHost:
case NSURLErrorCannotConnectToHost:
case NSURLErrorDNSLookupFailed:
case NSURLErrorNotConnectedToInternet:
case NSURLErrorInternationalRoamingOff:
case NSURLErrorCallIsActive:
case NSURLErrorDataNotAllowed:
status = ResponseStatus::ConnectionError;
break;
default:
status = ResponseStatus::PermanentError;
}
}
} else if ([res isKindOfClass:[NSHTTPURLResponse class]]) {
const long responseCode = [(NSHTTPURLResponse *)res statusCode];
response = util::make_unique<Response>();
response->data = {(const char *)[data bytes], [data length]};
NSDictionary *headers = [(NSHTTPURLResponse *)res allHeaderFields];
NSString *cache_control = [headers objectForKey:@"Cache-Control"];
if (cache_control) {
response->expires = parseCacheControl([cache_control UTF8String]);
}
NSString *expires = [headers objectForKey:@"Expires"];
if (expires) {
response->expires = parse_date([expires UTF8String]);
}
NSString *last_modified = [headers objectForKey:@"Last-Modified"];
if (last_modified) {
response->modified = parse_date([last_modified UTF8String]);
}
NSString *etag = [headers objectForKey:@"ETag"];
if (etag) {
response->etag = [etag UTF8String];
}
if (responseCode == 304) {
if (existingResponse) {
// We're going to reuse the old response object, but need to copy over the new
// expires value (if possible).
std::swap(response, existingResponse);
if (existingResponse->expires) {
response->expires = existingResponse->expires;
}
status = ResponseStatus::NotModified;
} else {
// This is an unsolicited 304 response and should only happen on malfunctioning
// HTTP servers. It likely doesn't include any data, but we don't have much options.
response->status = Response::Successful;
status = ResponseStatus::Successful;
}
} else if (responseCode == 200) {
response->status = Response::Successful;
status = ResponseStatus::Successful;
} else if (responseCode >= 500 && responseCode < 600) {
// Server errors may be temporary, so back off exponentially.
response->status = Response::Error;
response->message = "HTTP status code " + std::to_string(responseCode);
status = ResponseStatus::TemporaryError;
} else {
// We don't know how to handle any other errors, so declare them as permanently failing.
response->status = Response::Error;
response->message = "HTTP status code " + std::to_string(responseCode);
status = ResponseStatus::PermanentError;
}
} else {
// This should never happen.
status = ResponseStatus::PermanentError;
response = util::make_unique<Response>();
response->status = Response::Error;
response->message = "response class is not NSHTTPURLResponse";
}
uv_async_send(async);
}
void HTTPRequestImpl::retry(uint64_t timeout) {
response.reset();
assert(!timer);
timer = new uv_timer_t;
timer->data = this;
uv_timer_init(async->loop, timer);
uv_timer_start(timer, restart, timeout, 0);
}
void HTTPRequestImpl::retryImmediately() {
// All batons get notified when the network status changed, but some of them
// might not actually wait for the network to become available again.
if (timer && strategy == PreemptImmediately) {
// Triggers the timer upon the next event loop iteration.
uv_timer_stop(timer);
uv_timer_start(timer, restart, 0, 0);
}
}
void HTTPRequestImpl::restart(uv_timer_t *timer, int) {
// Restart the request.
auto impl = reinterpret_cast<HTTPRequestImpl *>(timer->data);
// Get rid of the timer.
impl->timer = nullptr;
uv::close(timer);
impl->start();
}
// -------------------------------------------------------------------------------------------------
HTTPRequest::HTTPRequest(DefaultFileSource *source, const Resource &resource)
: SharedRequestBase(source, resource) {
}
HTTPRequest::~HTTPRequest() {
MBGL_VERIFY_THREAD(tid);
if (ptr) {
reinterpret_cast<HTTPRequestImpl *>(ptr)->cancel();
}
}
void HTTPRequest::start(uv_loop_t *loop, std::unique_ptr<Response> response) {
MBGL_VERIFY_THREAD(tid);
assert(!ptr);
ptr = new HTTPRequestImpl(this, loop, std::move(response));
}
void HTTPRequest::retryImmediately() {
MBGL_VERIFY_THREAD(tid);
if (ptr) {
reinterpret_cast<HTTPRequestImpl *>(ptr)->retryImmediately();
}
}
void HTTPRequest::cancel() {
MBGL_VERIFY_THREAD(tid);
delete this;
}
}

View File

@@ -7,14 +7,13 @@
namespace mbgl {
void NSLogBackend::record(EventSeverity severity, Event event, const std::string &msg) {
NSLog(@"[%s] %s: %@", EventSeverityClass(severity).c_str(), EventClass(event).c_str(),
[[NSString alloc] initWithBytes:msg.data()
length:msg.size()
encoding:NSUTF8StringEncoding]);
NSString *message =
[[NSString alloc] initWithBytes:msg.data() length:msg.size() encoding:NSUTF8StringEncoding];
NSLog(@"[%s] %s: %@", EventSeverityClass(severity).c_str(), EventClass(event).c_str(), message);
[message release];
}
void NSLogBackend::record(EventSeverity severity, Event event, const char* format, ...) {
void NSLogBackend::record(EventSeverity severity, Event event, const char *format, ...) {
va_list args;
va_start(args, format);
const size_t len = vsnprintf(NULL, 0, format, args);
@@ -23,17 +22,22 @@ void NSLogBackend::record(EventSeverity severity, Event event, const char* forma
va_start(args, format);
vsnprintf(buffer.get(), len + 1, format, args);
va_end(args);
NSLog(@"[%s] %s: %s", EventSeverityClass(severity).c_str(), EventClass(event).c_str(), buffer.get());
NSLog(@"[%s] %s: %s", EventSeverityClass(severity).c_str(), EventClass(event).c_str(),
buffer.get());
}
void NSLogBackend::record(EventSeverity severity, Event event, int64_t code) {
NSLog(@"[%s] %s: (%lld)", EventSeverityClass(severity).c_str(), EventClass(event).c_str(), code);
NSLog(@"[%s] %s: (%lld)", EventSeverityClass(severity).c_str(), EventClass(event).c_str(),
code);
}
void NSLogBackend::record(EventSeverity severity, Event event, int64_t code, const std::string &msg) {
NSLog(@"[%s] %s: (%lld) %@", EventSeverityClass(severity).c_str(), EventClass(event).c_str(), code,
[[NSString alloc] initWithBytes:msg.data()
length:msg.size()
encoding:NSUTF8StringEncoding]);
void NSLogBackend::record(EventSeverity severity, Event event, int64_t code,
const std::string &msg) {
NSString *message =
[[NSString alloc] initWithBytes:msg.data() length:msg.size() encoding:NSUTF8StringEncoding];
NSLog(@"[%s] %s: (%lld) %@", EventSeverityClass(severity).c_str(), EventClass(event).c_str(),
code, message);
[message release];
}
}

View File

@@ -6,15 +6,27 @@ namespace mbgl {
namespace platform {
std::string uppercase(const std::string &string) {
NSString *nsstring = [[NSString alloc] initWithBytesNoCopy:const_cast<char *>(string.data()) length:string.size() encoding:NSUTF8StringEncoding freeWhenDone:NO];
nsstring = [nsstring uppercaseString];
return { [nsstring cStringUsingEncoding:NSUTF8StringEncoding], [nsstring lengthOfBytesUsingEncoding:NSUTF8StringEncoding] };
NSString *original = [[NSString alloc] initWithBytesNoCopy:const_cast<char *>(string.data())
length:string.size()
encoding:NSUTF8StringEncoding
freeWhenDone:NO];
NSString *uppercase = [original uppercaseString];
const std::string result{[uppercase cStringUsingEncoding : NSUTF8StringEncoding],
[uppercase lengthOfBytesUsingEncoding:NSUTF8StringEncoding]};
[original release];
return result;
}
std::string lowercase(const std::string &string) {
NSString *nsstring = [[NSString alloc] initWithBytesNoCopy:const_cast<char *>(string.data()) length:string.size() encoding:NSUTF8StringEncoding freeWhenDone:NO];
nsstring = [nsstring lowercaseString];
return { [nsstring cStringUsingEncoding:NSUTF8StringEncoding], [nsstring lengthOfBytesUsingEncoding:NSUTF8StringEncoding] };
NSString *original = [[NSString alloc] initWithBytesNoCopy:const_cast<char *>(string.data())
length:string.size()
encoding:NSUTF8StringEncoding
freeWhenDone:NO];
NSString *lowercase = [original lowercaseString];
const std::string result{[lowercase cStringUsingEncoding : NSUTF8StringEncoding],
[lowercase lengthOfBytesUsingEncoding:NSUTF8StringEncoding]};
[original release];
return result;
}
}

View File

@@ -1,13 +1,26 @@
#include <mbgl/platform/platform.hpp>
#include <mbgl/util/uv.hpp>
#include <uv.h>
#include <libgen.h>
namespace mbgl {
namespace platform {
// Returns the path the application root.
std::string applicationRoot() {
static const std::string root = uv::cwd();
// Returns the path to the root folder of the application.
const std::string &applicationRoot() {
static const std::string root = []() -> std::string {
size_t max = 0;
std::string dir;
do {
// Gradually increase the length of the string in case the path was truncated.
max += 256;
dir.resize(max);
uv_exepath(const_cast<char *>(dir.data()), &max);
} while (max == dir.size());
dir.resize(max - 1);
dir = dirname(const_cast<char *>(dir.c_str()));
return dir;
}();
return root;
}

View File

@@ -0,0 +1,252 @@
#include <mbgl/storage/default/asset_request.hpp>
#include <mbgl/storage/response.hpp>
#include <mbgl/util/std.hpp>
#include <mbgl/util/util.hpp>
#include <mbgl/util/uv.hpp>
#include <mbgl/platform/platform.hpp>
#include <uv.h>
#pragma GCC diagnostic push
#ifndef __clang__
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wshadow"
#endif
#include <boost/algorithm/string.hpp>
#pragma GCC diagnostic pop
#include <cassert>
namespace algo = boost::algorithm;
namespace mbgl {
class AssetRequestImpl {
MBGL_STORE_THREAD(tid)
public:
AssetRequestImpl(AssetRequest *request, uv_loop_t *loop);
~AssetRequestImpl();
static void fileOpened(uv_fs_t *req);
static void fileStated(uv_fs_t *req);
static void fileRead(uv_fs_t *req);
static void fileClosed(uv_fs_t *req);
static void notifyError(uv_fs_t *req);
static void cleanup(uv_fs_t *req);
AssetRequest *request = nullptr;
bool canceled = false;
uv_fs_t req;
uv_file fd = -1;
uv_buf_t buffer;
std::unique_ptr<Response> response;
};
AssetRequestImpl::~AssetRequestImpl() {
MBGL_VERIFY_THREAD(tid);
if (request) {
request->ptr = nullptr;
}
}
AssetRequestImpl::AssetRequestImpl(AssetRequest *request_, uv_loop_t *loop) : request(request_) {
req.data = this;
const auto &url = request->resource.url;
std::string path;
if (url.size() <= 8 || url[8] == '/') {
// This is an empty or absolute path.
path = url.substr(8);
} else {
// This is a relative path. Prefix with the application root.
path = platform::assetRoot() + "/" + url.substr(8);
}
uv_fs_open(loop, &req, path.c_str(), O_RDONLY, S_IRUSR, fileOpened);
}
void AssetRequestImpl::fileOpened(uv_fs_t *req) {
assert(req->data);
auto self = reinterpret_cast<AssetRequestImpl *>(req->data);
MBGL_VERIFY_THREAD(self->tid);
if (req->result < 0) {
// Opening failed or was canceled. There isn't much left we can do.
notifyError(req);
cleanup(req);
} else {
const uv_file fd = uv_file(req->result);
// We're going to reuse this handle, so we need to cleanup first.
uv_fs_req_cleanup(req);
if (self->canceled) {
// The request was canceled.
uv_fs_close(req->loop, req, fd, fileClosed);
} else {
self->fd = fd;
uv_fs_fstat(req->loop, req, fd, fileStated);
}
}
}
void AssetRequestImpl::fileStated(uv_fs_t *req) {
assert(req->data);
auto self = reinterpret_cast<AssetRequestImpl *>(req->data);
MBGL_VERIFY_THREAD(self->tid);
if (req->result != 0 || self->canceled) {
// Stating failed or was canceled. We already have an open file handle
// though, which we'll have to close.
notifyError(req);
uv_fs_req_cleanup(req);
uv_fs_close(req->loop, req, self->fd, fileClosed);
} else {
#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
auto stat = static_cast<const uv_statbuf_t *>(req->ptr);
#else
auto stat = static_cast<const uv_stat_t *>(req->ptr);
#endif
if (stat->st_size > std::numeric_limits<int>::max()) {
// File is too large for us to open this way because uv_buf's only support unsigned
// ints as maximum size.
auto response = util::make_unique<Response>();
response->status = Response::Error;
#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
response->message = uv_strerror(uv_err_t {UV_EFBIG, 0});
#else
response->message = uv_strerror(UV_EFBIG);
#endif
assert(self->request);
self->request->notify(std::move(response), FileCache::Hint::No);
delete self->request;
uv_fs_req_cleanup(req);
uv_fs_close(req->loop, req, self->fd, fileClosed);
} else {
self->response = util::make_unique<Response>();
#ifdef __APPLE__
self->response->modified = stat->st_mtimespec.tv_sec;
#else
self->response->modified = stat->st_mtime;
#endif
self->response->etag = std::to_string(stat->st_ino);
const auto size = (unsigned int)(stat->st_size);
self->response->data.resize(size);
self->buffer = uv_buf_init(const_cast<char *>(self->response->data.data()), size);
uv_fs_req_cleanup(req);
#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
uv_fs_read(req->loop, req, self->fd, self->buffer.base, self->buffer.len, -1, fileRead);
#else
uv_fs_read(req->loop, req, self->fd, &self->buffer, 1, 0, fileRead);
#endif
}
}
}
void AssetRequestImpl::fileRead(uv_fs_t *req) {
assert(req->data);
auto self = reinterpret_cast<AssetRequestImpl *>(req->data);
MBGL_VERIFY_THREAD(self->tid);
if (req->result < 0 || self->canceled) {
// Stating failed or was canceled. We already have an open file handle
// though, which we'll have to close.
notifyError(req);
} else {
// File was successfully read.
self->response->status = Response::Successful;
assert(self->request);
self->request->notify(std::move(self->response), FileCache::Hint::No);
delete self->request;
}
uv_fs_req_cleanup(req);
uv_fs_close(req->loop, req, self->fd, fileClosed);
}
void AssetRequestImpl::fileClosed(uv_fs_t *req) {
assert(req->data);
auto self = reinterpret_cast<AssetRequestImpl *>(req->data);
MBGL_VERIFY_THREAD(self->tid);
(void(self)); // Silence unused variable error in Release mode
if (req->result < 0) {
// Closing the file failed. But there isn't anything we can do.
}
cleanup(req);
}
void AssetRequestImpl::notifyError(uv_fs_t *req) {
assert(req->data);
auto self = reinterpret_cast<AssetRequestImpl *>(req->data);
MBGL_VERIFY_THREAD(self->tid);
if (req->result < 0 && !self->canceled && req->result != UV_ECANCELED) {
auto response = util::make_unique<Response>();
response->status = Response::Error;
response->message = uv::getFileRequestError(req);
assert(self->request);
self->request->notify(std::move(response), FileCache::Hint::No);
delete self->request;
}
}
void AssetRequestImpl::cleanup(uv_fs_t *req) {
assert(req->data);
auto self = reinterpret_cast<AssetRequestImpl *>(req->data);
MBGL_VERIFY_THREAD(self->tid);
uv_fs_req_cleanup(req);
delete self;
}
// -------------------------------------------------------------------------------------------------
AssetRequest::AssetRequest(DefaultFileSource *source_, const Resource &resource_)
: SharedRequestBase(source_, resource_) {
assert(algo::starts_with(resource.url, "asset://"));
}
AssetRequest::~AssetRequest() {
MBGL_VERIFY_THREAD(tid);
if (ptr) {
reinterpret_cast<AssetRequestImpl *>(ptr)->request = nullptr;
}
}
void AssetRequest::start(uv_loop_t *loop, std::unique_ptr<Response> response) {
MBGL_VERIFY_THREAD(tid);
// We're ignoring the existing response if any.
(void(response));
assert(!ptr);
ptr = new AssetRequestImpl(this, loop);
// Note: the AssetRequestImpl deletes itself.
}
void AssetRequest::cancel() {
MBGL_VERIFY_THREAD(tid);
if (ptr) {
reinterpret_cast<AssetRequestImpl *>(ptr)->canceled = true;
// uv_cancel fails frequently when the request has already been started.
// In that case, we have to let it complete and check the canceled bool
// instead. The cancelation callback will delete the AssetRequest object.
uv_cancel((uv_req_t *)&reinterpret_cast<AssetRequestImpl *>(ptr)->req);
} else {
// This request is canceled before we called start. We're safe to delete
// ourselves now.
delete this;
}
}
}

View File

@@ -1,223 +0,0 @@
#include <mbgl/storage/asset_request.hpp>
#include <mbgl/storage/response.hpp>
#include <mbgl/platform/platform.hpp>
#include <mbgl/util/std.hpp>
#include <uv.h>
#include <limits>
namespace mbgl {
struct AssetRequestBaton {
AssetRequestBaton(AssetRequest *request_, const std::string &path, uv_loop_t *loop);
~AssetRequestBaton();
void cancel();
static void fileOpened(uv_fs_t *req);
static void fileStated(uv_fs_t *req);
static void fileRead(uv_fs_t *req);
static void fileClosed(uv_fs_t *req);
static void notifyError(uv_fs_t *req);
static void cleanup(uv_fs_t *req);
const std::thread::id threadId;
AssetRequest *request = nullptr;
uv_fs_t req;
uv_file fd = -1;
bool canceled = false;
std::string body;
uv_buf_t buffer;
};
AssetRequestBaton::AssetRequestBaton(AssetRequest *request_, const std::string &path, uv_loop_t *loop)
: threadId(std::this_thread::get_id()), request(request_) {
req.data = this;
uv_fs_open(loop, &req, path.c_str(), O_RDONLY, S_IRUSR, fileOpened);
}
AssetRequestBaton::~AssetRequestBaton() {
}
void AssetRequestBaton::cancel() {
canceled = true;
// uv_cancel fails frequently when the request has already been started.
// In that case, we have to let it complete and check the canceled bool
// instead.
uv_cancel((uv_req_t *)&req);
}
void AssetRequestBaton::notifyError(uv_fs_t *req) {
AssetRequestBaton *ptr = reinterpret_cast<AssetRequestBaton *>(req->data);
assert(std::this_thread::get_id() == ptr->threadId);
if (ptr->request && req->result < 0 && !ptr->canceled && req->result != UV_ECANCELED) {
ptr->request->response = util::make_unique<Response>();
ptr->request->response->code = req->result == UV_ENOENT ? 404 : 500;
#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
ptr->request->response->message = uv_strerror(uv_last_error(req->loop));
#else
ptr->request->response->message = uv_strerror(int(req->result));
#endif
ptr->request->notify();
}
}
void AssetRequestBaton::fileOpened(uv_fs_t *req) {
AssetRequestBaton *ptr = reinterpret_cast<AssetRequestBaton *>(req->data);
assert(std::this_thread::get_id() == ptr->threadId);
if (req->result < 0) {
// Opening failed or was canceled. There isn't much left we can do.
notifyError(req);
cleanup(req);
} else {
const uv_file fd = uv_file(req->result);
// We're going to reuse this handle, so we need to cleanup first.
uv_fs_req_cleanup(req);
if (ptr->canceled || !ptr->request) {
// Either the AssetRequest object has been destructed, or the
// request was canceled.
uv_fs_close(req->loop, req, fd, fileClosed);
} else {
ptr->fd = fd;
uv_fs_fstat(req->loop, req, fd, fileStated);
}
}
}
void AssetRequestBaton::fileStated(uv_fs_t *req) {
AssetRequestBaton *ptr = reinterpret_cast<AssetRequestBaton *>(req->data);
assert(std::this_thread::get_id() == ptr->threadId);
if (req->result != 0 || ptr->canceled || !ptr->request) {
// Stating failed or was canceled. We already have an open file handle
// though, which we'll have to close.
notifyError(req);
uv_fs_req_cleanup(req);
uv_fs_close(req->loop, req, ptr->fd, fileClosed);
} else {
#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
const uv_statbuf_t *stat = static_cast<const uv_statbuf_t *>(req->ptr);
#else
const uv_stat_t *stat = static_cast<const uv_stat_t *>(req->ptr);
#endif
if (stat->st_size > std::numeric_limits<int>::max()) {
// File is too large for us to open this way because uv_buf's only support unsigned
// ints as maximum size.
if (ptr->request) {
ptr->request->response = util::make_unique<Response>();
ptr->request->response->code = UV_EFBIG;
#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
ptr->request->response->message = uv_strerror(uv_err_t {UV_EFBIG, 0});
#else
ptr->request->response->message = uv_strerror(UV_EFBIG);
#endif
ptr->request->notify();
}
uv_fs_req_cleanup(req);
uv_fs_close(req->loop, req, ptr->fd, fileClosed);
} else {
const unsigned int size = (unsigned int)(stat->st_size);
ptr->body.resize(size);
ptr->buffer = uv_buf_init(const_cast<char *>(ptr->body.data()), size);
uv_fs_req_cleanup(req);
#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
uv_fs_read(req->loop, req, ptr->fd, ptr->buffer.base, ptr->buffer.len, -1, fileRead);
#else
uv_fs_read(req->loop, req, ptr->fd, &ptr->buffer, 1, 0, fileRead);
#endif
}
}
}
void AssetRequestBaton::fileRead(uv_fs_t *req) {
AssetRequestBaton *ptr = reinterpret_cast<AssetRequestBaton *>(req->data);
assert(std::this_thread::get_id() == ptr->threadId);
if (req->result < 0 || ptr->canceled || !ptr->request) {
// Reading failed or was canceled. We already have an open file handle
// though, which we'll have to close.
notifyError(req);
} else {
// File was successfully read.
if (ptr->request) {
ptr->request->response = util::make_unique<Response>();
ptr->request->response->code = 200;
ptr->request->response->data = std::move(ptr->body);
ptr->request->notify();
}
}
uv_fs_req_cleanup(req);
uv_fs_close(req->loop, req, ptr->fd, fileClosed);
}
void AssetRequestBaton::fileClosed(uv_fs_t *req) {
assert(std::this_thread::get_id() == (reinterpret_cast<AssetRequestBaton *>(req->data))->threadId);
if (req->result < 0) {
// Closing the file failed. But there isn't anything we can do.
}
cleanup(req);
}
void AssetRequestBaton::cleanup(uv_fs_t *req) {
AssetRequestBaton *ptr = reinterpret_cast<AssetRequestBaton *>(req->data);
assert(std::this_thread::get_id() == ptr->threadId);
if (ptr->request) {
ptr->request->ptr = nullptr;
}
uv_fs_req_cleanup(req);
delete ptr;
ptr = nullptr;
}
AssetRequest::AssetRequest(const std::string &path_, uv_loop_t *loop)
: BaseRequest(path_) {
if (!path.empty() && path[0] == '/') {
// This is an absolute path. We don't allow this. Note that this is not a way to absolutely
// prevent access to resources outside the application bundle; e.g. there could be symlinks
// in the application bundle that link to outside. We don't care about these.
response = util::make_unique<Response>();
response->code = 403;
response->message = "Path is outside the application bundle";
notify();
} else {
// Note: The AssetRequestBaton object is deleted in AssetRequestBaton::cleanup().
ptr = new AssetRequestBaton(this, platform::applicationRoot() + "/" + path, loop);
}
}
void AssetRequest::cancel() {
assert(std::this_thread::get_id() == threadId);
if (ptr) {
ptr->cancel();
// When deleting a AssetRequest object with a uv_fs_* call is in progress, we are making sure
// that the callback doesn't accidentally reference this object again.
ptr->request = nullptr;
ptr = nullptr;
}
notify();
}
AssetRequest::~AssetRequest() {
assert(std::this_thread::get_id() == threadId);
cancel();
// Note: The AssetRequestBaton object is deleted in AssetRequestBaton::cleanup().
}
}

View File

@@ -0,0 +1,301 @@
#include <mbgl/storage/default/asset_request.hpp>
#include <mbgl/storage/default/thread_context.hpp>
#include <mbgl/android/jni.hpp>
#include <mbgl/storage/response.hpp>
#include <mbgl/util/std.hpp>
#include <mbgl/platform/platform.hpp>
#include "uv_zip.h"
#pragma GCC diagnostic push
#ifndef __clang__
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wshadow"
#endif
#include <boost/algorithm/string.hpp>
#pragma GCC diagnostic pop
#include <forward_list>
namespace algo = boost::algorithm;
namespace mbgl {
class AssetZipContext : public ThreadContext<AssetZipContext> {
public:
AssetZipContext(uv_loop_t *loop);
~AssetZipContext();
uv_zip_t *getHandle();
void returnHandle(uv_zip_t *zip);
private:
// A list of resuable uv_zip handles to avoid creating and destroying them all the time.
std::forward_list<uv_zip_t *> handles;
};
// -------------------------------------------------------------------------------------------------
template<> pthread_key_t ThreadContext<AssetZipContext>::key{};
template<> pthread_once_t ThreadContext<AssetZipContext>::once = PTHREAD_ONCE_INIT;
AssetZipContext::AssetZipContext(uv_loop_t *loop_) : ThreadContext(loop_) {
}
uv_zip_t *AssetZipContext::getHandle() {
if (!handles.empty()) {
auto zip = handles.front();
handles.pop_front();
return zip;
} else {
return nullptr;
}
}
void AssetZipContext::returnHandle(uv_zip_t *zip) {
uv_zip_cleanup(zip);
handles.push_front(zip);
}
AssetZipContext::~AssetZipContext() {
// Close all zip handles
for (auto zip : handles) {
uv_zip_discard(loop, zip, [](uv_zip_t *zip_) {
uv_zip_cleanup(zip_);
delete zip_;
});
}
handles.clear();
}
// -------------------------------------------------------------------------------------------------
class AssetRequestImpl {
MBGL_STORE_THREAD(tid)
public:
AssetRequestImpl(AssetRequest *request, uv_loop_t *loop);
~AssetRequestImpl();
void cancel();
private:
AssetZipContext &context;
AssetRequest *request = nullptr;
const std::string path;
std::unique_ptr<Response> response;
uv_buf_t buffer;
private:
void openZipArchive();
void archiveOpened(uv_zip_t *zip);
void fileStated(uv_zip_t *zip);
void fileOpened(uv_zip_t *zip);
void fileRead(uv_zip_t *zip);
void fileClosed(uv_zip_t *zip);
void cleanup(uv_zip_t *zip);
void notifyError(const char *message);
};
// -------------------------------------------------------------------------------------------------
AssetRequestImpl::~AssetRequestImpl() {
MBGL_VERIFY_THREAD(tid);
if (request) {
request->ptr = nullptr;
}
}
AssetRequestImpl::AssetRequestImpl(AssetRequest *request_, uv_loop_t *loop)
: context(*AssetZipContext::Get(loop)),
request(request_),
path(request->resource.url.substr(8)) {
auto zip = context.getHandle();
if (zip) {
archiveOpened(zip);
} else {
openZipArchive();
}
}
void AssetRequestImpl::openZipArchive() {
uv_fs_t *req = new uv_fs_t();
req->data = this;
// We're using uv_fs_open first to obtain a file descriptor. Then, uv_zip_fdopen will operate
// on a read-only file.
uv_fs_open(context.loop, req, platform::assetRoot().c_str(), O_RDONLY, S_IRUSR, [](uv_fs_t *fsReq) {
if (fsReq->result < 0) {
auto impl = reinterpret_cast<AssetRequestImpl *>(fsReq->data);
impl->notifyError(uv::getFileRequestError(fsReq));
delete impl;
} else {
uv_zip_t *zip = new uv_zip_t();
uv_zip_init(zip);
zip->data = fsReq->data;
uv_zip_fdopen(fsReq->loop, zip, uv_file(fsReq->result), 0, [](uv_zip_t *openZip) {
auto impl = reinterpret_cast<AssetRequestImpl *>(openZip->data);
if (openZip->result < 0) {
impl->notifyError(openZip->message);
delete openZip;
delete impl;
} else {
impl->archiveOpened(openZip);
}
});
}
uv_fs_req_cleanup(fsReq);
delete fsReq;
fsReq = nullptr;
});
}
#define INVOKE_MEMBER(name) \
[](uv_zip_t *zip_) { \
assert(zip_->data); \
reinterpret_cast<AssetRequestImpl *>(zip_->data)->name(zip_); \
}
void AssetRequestImpl::archiveOpened(uv_zip_t *zip) {
MBGL_VERIFY_THREAD(tid);
zip->data = this;
uv_zip_stat(context.loop, zip, path.c_str(), 0, INVOKE_MEMBER(fileStated));
}
void AssetRequestImpl::fileStated(uv_zip_t *zip) {
MBGL_VERIFY_THREAD(tid);
if (!request || zip->result < 0) {
// Stat failed, probably because the file doesn't exist.
if (zip->result < 0) {
notifyError(zip->message);
}
cleanup(zip);
} else if (!(zip->stat->valid & ZIP_STAT_SIZE)) {
// We couldn't obtain the size of the file.
notifyError("Could not determine file size in zip file");
cleanup(zip);
} else {
response = util::make_unique<Response>();
// Allocate the space for reading the data.
response->data.resize(zip->stat->size);
buffer = uv_buf_init(const_cast<char *>(response->data.data()), zip->stat->size);
// Get the modification time in case we have one.
if (zip->stat->valid & ZIP_STAT_MTIME) {
response->modified = zip->stat->mtime;
}
uv_zip_fopen(context.loop, zip, path.c_str(), 0, INVOKE_MEMBER(fileOpened));
}
}
void AssetRequestImpl::fileOpened(uv_zip_t *zip) {
MBGL_VERIFY_THREAD(tid);
if (zip->result < 0) {
// Opening failed.
notifyError(zip->message);
cleanup(zip);
} else if (!request) {
// The request was canceled. Close the file again.
uv_zip_fclose(context.loop, zip, zip->file, INVOKE_MEMBER(fileClosed));
} else {
uv_zip_fread(context.loop, zip, zip->file, &buffer, INVOKE_MEMBER(fileRead));
}
}
void AssetRequestImpl::fileRead(uv_zip_t *zip) {
MBGL_VERIFY_THREAD(tid);
if (zip->result < 0) {
// Reading failed. We still have an open file handle though.
notifyError(zip->message);
} else if (request) {
response->status = Response::Successful;
request->notify(std::move(response), FileCache::Hint::No);
delete request;
assert(request == nullptr);
}
uv_zip_fclose(context.loop, zip, zip->file, INVOKE_MEMBER(fileClosed));
}
void AssetRequestImpl::fileClosed(uv_zip_t *zip) {
MBGL_VERIFY_THREAD(tid);
if (zip->result < 0) {
// Closing the file failed. But there isn't anything we can do.
}
cleanup(zip);
}
void AssetRequestImpl::cleanup(uv_zip_t *zip) {
MBGL_VERIFY_THREAD(tid);
context.returnHandle(zip);
delete this;
}
void AssetRequestImpl::notifyError(const char *message) {
MBGL_VERIFY_THREAD(tid);
if (request) {
response = util::make_unique<Response>();
response->status = Response::Error;
response->message = message;
request->notify(std::move(response), FileCache::Hint::No);
delete request;
assert(request == nullptr);
} else {
// The request was already canceled and deleted.
}
}
void AssetRequestImpl::cancel() {
request = nullptr;
}
// -------------------------------------------------------------------------------------------------
AssetRequest::AssetRequest(DefaultFileSource *source_, const Resource &resource_)
: SharedRequestBase(source_, resource_) {
assert(algo::starts_with(resource.url, "asset://"));
}
AssetRequest::~AssetRequest() {
MBGL_VERIFY_THREAD(tid);
if (ptr) {
reinterpret_cast<AssetRequestImpl *>(ptr)->cancel();
}
}
void AssetRequest::start(uv_loop_t *loop, std::unique_ptr<Response> response) {
MBGL_VERIFY_THREAD(tid);
// We're ignoring the existing response if any.
(void(response));
assert(!ptr);
ptr = new AssetRequestImpl(this, loop);
// Note: the AssetRequestImpl deletes itself.
}
void AssetRequest::cancel() {
MBGL_VERIFY_THREAD(tid);
if (ptr) {
reinterpret_cast<AssetRequestImpl *>(ptr)->cancel();
}
delete this;
}
}

View File

@@ -0,0 +1,28 @@
#include <mbgl/platform/platform.hpp>
#include <uv.h>
#include <libgen.h>
namespace mbgl {
namespace platform {
// Returns the path to the root folder of the application.
const std::string &assetRoot() {
static const std::string root = []() -> std::string {
size_t max = 0;
std::string dir;
do {
// Gradually increase the length of the string in case the path was truncated.
max += 256;
dir.resize(max);
uv_exepath(const_cast<char *>(dir.data()), &max);
} while (max == dir.size());
dir.resize(max - 1);
dir = dirname(const_cast<char *>(dir.c_str()));
return dir;
}();
return root;
}
}
}

View File

@@ -1,12 +0,0 @@
#include <mbgl/platform/platform.hpp>
namespace mbgl {
namespace platform {
// Returns the path to the default cache database on this system.
std::string defaultCacheDatabase() {
return "/tmp/mbgl-cache.db";
}
}
}

View File

@@ -1,10 +1,25 @@
#include <mbgl/util/compression.hpp>
#include "compression.hpp"
#include <zlib.h>
#include <cstring>
#include <stdexcept>
// Check zlib library version.
const static bool zlibVersionCheck = []() {
const char *const version = zlibVersion();
if (version[0] != ZLIB_VERSION[0]) {
char message[96];
snprintf(message, 96, "zlib version mismatch: headers report %s, but library reports %s",
ZLIB_VERSION, version);
throw std::runtime_error(message);
}
return true;
}();
namespace mbgl {
namespace util {

View File

@@ -174,7 +174,7 @@ void GLFWView::key(GLFWwindow *window, int key, int /*scancode*/, int action, in
break;
case GLFW_KEY_R:
if (!mods) {
view->map->setDefaultTransitionDuration(300);
view->map->setDefaultTransitionDuration(std::chrono::milliseconds(300));
if (view->map->hasClass("night")) {
view->map->removeClass("night");
} else {
@@ -239,9 +239,9 @@ void GLFWView::mouseClick(GLFWwindow *window, int button, int action, int modifi
double now = glfwGetTime();
if (now - view->lastClick < 0.4 /* ms */) {
if (modifiers & GLFW_MOD_SHIFT) {
view->map->scaleBy(0.5, view->lastX, view->lastY, 0.5);
view->map->scaleBy(0.5, view->lastX, view->lastY, std::chrono::milliseconds(500));
} else {
view->map->scaleBy(2.0, view->lastX, view->lastY, 0.5);
view->map->scaleBy(2.0, view->lastX, view->lastY, std::chrono::milliseconds(500));
}
}
view->lastClick = now;
@@ -301,7 +301,7 @@ void GLFWView::swap() {
fps();
}
void GLFWView::notifyMapChange(mbgl::MapChange /*change*/, mbgl::timestamp /*delay*/) {
void GLFWView::notifyMapChange(mbgl::MapChange /*change*/, std::chrono::steady_clock::duration /*delay*/) {
// no-op
}

View File

@@ -244,7 +244,7 @@ void HeadlessView::notify() {
// no-op
}
void HeadlessView::notifyMapChange(mbgl::MapChange /*change*/, mbgl::timestamp /*delay*/) {
void HeadlessView::notifyMapChange(mbgl::MapChange /*change*/, std::chrono::steady_clock::duration /*delay*/) {
// no-op
}

Some files were not shown because too many files have changed in this diff Show More