Updating from master

This commit is contained in:
Brad Leege
2015-05-04 17:04:46 -05:00
230 changed files with 4374 additions and 4572 deletions

1
.gitignore vendored
View File

@@ -16,6 +16,7 @@
/test/build
/test/node_modules
/test/fixtures/*/*_actual.*
/test/fixtures/database/*.db
/include/mbgl/shader/shaders.hpp
/src/shader/shaders_gl.cpp
/src/shader/shaders_gles2.cpp

2
.gitmodules vendored
View File

@@ -12,7 +12,7 @@
[submodule "test/ios/KIF"]
path = test/ios/KIF
url = https://github.com/mapbox/KIF.git
url = https://github.com/kif-framework/KIF.git
[submodule "platform/ios/vendor/SMCalloutView"]
path = platform/ios/vendor/SMCalloutView

2
.mason

Submodule .mason updated: 03869fd11e...c43967404c

View File

@@ -1,95 +1,99 @@
language: cpp
language: android
sudo: false
matrix:
exclude:
- os: linux
include:
- os: linux
env: CONFIG=release MASON_PLATFORM=android MASON_ANDROID_ABI=arm-v7 TESTMUNK=yes
compiler: clang
env: FLAVOR=linux CXX=g++-4.8 BUILDTYPE=Release
addons:
apt:
sources: [ 'ubuntu-toolchain-r-test' ]
packages: [ 'gdb', 'g++-4.8', 'gcc-4.8', 'libllvm3.4', 'xutils-dev', 'libxxf86vm-dev', 'x11proto-xf86vidmode-dev', 'mesa-utils' ]
- os: linux
env: CONFIG=debug MASON_PLATFORM=android MASON_ANDROID_ABI=arm-v7 TESTMUNK=no
compiler: clang
env: FLAVOR=linux CXX=clang++ BUILDTYPE=Debug
addons:
apt:
sources: [ 'ubuntu-toolchain-r-test' ]
packages: [ 'gdb', 'libgcc-4.8-dev', 'libstdc++-4.8-dev', 'libstdc++6', 'libllvm3.4', 'xutils-dev', 'libxxf86vm-dev', 'x11proto-xf86vidmode-dev', 'mesa-utils' ]
- os: linux
env: CONFIG=release MASON_PLATFORM=android MASON_ANDROID_ABI=arm-v5 TESTMUNK=no
compiler: clang
- os: linux
env: CONFIG=release MASON_PLATFORM=android MASON_ANDROID_ABI=arm-v8 TESTMUNK=no
compiler: clang
- os: linux
env: CONFIG=release MASON_PLATFORM=android MASON_ANDROID_ABI=x86 TESTMUNK=no
compiler: clang
- os: linux
env: CONFIG=release MASON_PLATFORM=android MASON_ANDROID_ABI=mips TESTMUNK=no
compiler: clang
- os: linux
env: CONFIG=release MASON_PLATFORM=android MASON_ANDROID_ABI=mips-64 TESTMUNK=no
compiler: clang
- os: linux
env: BUILDTYPE=Release JOBS=16
compiler: clang
- os: linux
env: BUILDTYPE=Debug JOBS=16
compiler: clang
- os: linux
env: BUILDTYPE=Release JOBS=8
compiler: gcc
env: FLAVOR=linux CXX=clang++ BUILDTYPE=Release
addons:
apt:
sources: [ 'ubuntu-toolchain-r-test' ]
packages: [ 'gdb', 'libgcc-4.8-dev', 'libstdc++-4.8-dev', 'libstdc++6', 'libllvm3.4', 'xutils-dev', 'libxxf86vm-dev', 'x11proto-xf86vidmode-dev', 'mesa-utils' ]
- os: osx
env: BUILDTYPE=Debug JOBS=8 MASON_PLATFORM=osx
compiler: clang
env: FLAVOR=osx BUILDTYPE=Debug
- os: osx
env: BUILDTYPE=Release JOBS=8 MASON_PLATFORM=ios
compiler: clang
env: FLAVOR=ios BUILDTYPE=Release
- os: linux
env: FLAVOR=android ANDROID_ABI=arm-v7 BUILDTYPE=Release
android:
components: [ 'build-tools-22.0.0', 'android-22', 'extra' ]
addons:
apt:
packages: [ 'lib32stdc++6' ]
- os: linux
env: FLAVOR=android ANDROID_ABI=arm-v7 BUILDTYPE=Debug
android:
components: [ 'build-tools-22.0.0', 'android-22', 'extra' ]
addons:
apt:
packages: [ 'lib32stdc++6' ]
- os: linux
env: FLAVOR=android ANDROID_ABI=arm-v8 BUILDTYPE=Release
android:
components: [ 'build-tools-22.0.0', 'android-22', 'extra' ]
addons:
apt:
packages: [ 'lib32stdc++6' ]
- os: linux
env: FLAVOR=android ANDROID_ABI=x86 BUILDTYPE=Release
android:
components: [ 'build-tools-22.0.0', 'android-22', 'extra' ]
addons:
apt:
packages: [ 'lib32stdc++6' ]
- os: linux
env: FLAVOR=android ANDROID_ABI=mips BUILDTYPE=Release
android:
components: [ 'build-tools-22.0.0', 'android-22', 'extra' ]
addons:
apt:
packages: [ 'lib32stdc++6' ]
env:
global:
- secure: "MZHblLZXG/jWf2w0ZFlxCLDwx2qtGgRDODQyg1BR7JIuMz6AtWv8XR/sUczWLbiABCL0a/NzJF1g4v2pI7X69IntcjOdIABBgTh7++6+1TJ0Kp8viEltb55nQG3lHy/R6fOaI7Pj9tuCX0PCRtGA5C/fGnodLGEjy3RVOJ09ln0="
- secure: "KaSQbhgjtV7ZCkesHmvrNsbQVjk5SPfGKB1VkWenRGYhLF45HpSRNwSxMQddZ566Pg7qIFgF1iWl/B0QW3B6AWL5WmzQ5AOJgwS876pNIc/UT7ubMPtgAtjpvw1bQvQP3B8MrB+3OE5c6tD+a3LhR9krV//dOsfErR5Yy+3Mbkc="
- ANDROID_BUILD_INSTANCE_PROFILE: arn:aws:iam::234858372212:instance-profile/android-gl-build/travis/instance-profile/travis-mapbox-gl-native-AndroidInstanceProfile-13EA815DD8IQ9
- secure: "RiBIBfVhhaMjU5ksuwJO3shdvG9FpinBjdSv4co9jg9171SR8edNriedHjVKSIeBhSGNmZmX+twS3dJS/By6tl/LKh9sTynA+ZAYYljkE7jn881B/gMrlYvdAA6og5KvkhV1/0iJWlhuZrMTkhpDR200iLgg3EWBhWjltzmDW/I="
- secure: "CHBiUM60TolDbQnn+4IRA/tvOKwKs3g9EDvv8YHSJMg3FuHmjKQkprBasvxf3hnTXg4WLZEubmeDcyJ6RRzPP5mMSr/hksYl0pSjj/6TUecE5fHPVVeN7txVqkpOBf9i45Y+iBUQMjBb1NnDK3pHXxpnAs1Q/pe7vReErj4GF1U="
- LD_LIBRARY_PATH: '/usr/local/lib'
- TERM: dumb
# begin iOS code signing
- secure: "I6Iu75X1E+js5tzijtKi1EGtIuBcA4/25nDYe0svV4HAtujY71ZJZ4eB6355CKhFXpLXrF3i7eKVX3v+zWS0QROPEWacgsqsvNg+Ba9cnznW/faUSOYekCfhzWd/6reYDM7KzKAQwSUHLk9JIWK/kkmi4r+vVJK7h+tjPllK5YA="
- IOS_APP_NAME="Mapbox GL"
- 'IOS_DEVELOPER_NAME="iPhone Distribution: Mapbox, Inc."'
- IOS_PROFILE_NAME="ios-in-house"
- secure: "nQqSM8rd7OHtV4MqmNqVnkrVHqxKqQsaWRYk4/nPdhbeVWtTtkk0df711LrF1TUtbEPEewHxYUvTZ/UXmwJNeoKdzTHavI8hnatRkgjyxGERPn1il1Otelht9I+LQQHf+plrpRjVWBrNIW0Zox1B3cqn6d3NglpbXrEQ2EjYGNA="
# end iOS code signing
before_install:
- if [[ ${TRAVIS_OS_NAME} == "linux" ]]; then sudo service mysql stop; fi
- 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
- TERM: dumb
# AWS
- secure: "MZHblLZXG/jWf2w0ZFlxCLDwx2qtGgRDODQyg1BR7JIuMz6AtWv8XR/sUczWLbiABCL0a/NzJF1g4v2pI7X69IntcjOdIABBgTh7++6+1TJ0Kp8viEltb55nQG3lHy/R6fOaI7Pj9tuCX0PCRtGA5C/fGnodLGEjy3RVOJ09ln0="
- secure: "KaSQbhgjtV7ZCkesHmvrNsbQVjk5SPfGKB1VkWenRGYhLF45HpSRNwSxMQddZ566Pg7qIFgF1iWl/B0QW3B6AWL5WmzQ5AOJgwS876pNIc/UT7ubMPtgAtjpvw1bQvQP3B8MrB+3OE5c6tD+a3LhR9krV//dOsfErR5Yy+3Mbkc="
# Access Token
- secure: "RiBIBfVhhaMjU5ksuwJO3shdvG9FpinBjdSv4co9jg9171SR8edNriedHjVKSIeBhSGNmZmX+twS3dJS/By6tl/LKh9sTynA+ZAYYljkE7jn881B/gMrlYvdAA6og5KvkhV1/0iJWlhuZrMTkhpDR200iLgg3EWBhWjltzmDW/I="
# Testmunk
- secure: "CHBiUM60TolDbQnn+4IRA/tvOKwKs3g9EDvv8YHSJMg3FuHmjKQkprBasvxf3hnTXg4WLZEubmeDcyJ6RRzPP5mMSr/hksYl0pSjj/6TUecE5fHPVVeN7txVqkpOBf9i45Y+iBUQMjBb1NnDK3pHXxpnAs1Q/pe7vReErj4GF1U="
# iOS code signing
- secure: "I6Iu75X1E+js5tzijtKi1EGtIuBcA4/25nDYe0svV4HAtujY71ZJZ4eB6355CKhFXpLXrF3i7eKVX3v+zWS0QROPEWacgsqsvNg+Ba9cnznW/faUSOYekCfhzWd/6reYDM7KzKAQwSUHLk9JIWK/kkmi4r+vVJK7h+tjPllK5YA="
- IOS_APP_NAME="Mapbox GL"
- 'IOS_DEVELOPER_NAME="iPhone Distribution: Mapbox, Inc."'
- IOS_PROFILE_NAME="ios-in-house"
- secure: "nQqSM8rd7OHtV4MqmNqVnkrVHqxKqQsaWRYk4/nPdhbeVWtTtkk0df711LrF1TUtbEPEewHxYUvTZ/UXmwJNeoKdzTHavI8hnatRkgjyxGERPn1il1Otelht9I+LQQHf+plrpRjVWBrNIW0Zox1B3cqn6d3NglpbXrEQ2EjYGNA="
- KIF_SCREENSHOTS="${TRAVIS_BUILD_DIR}/screenshots"
install:
- ulimit -c
before_script:
# Set the core file limit to unlimited so a core file is generated upon crash
- ulimit -c unlimited -S
# begin iOS code signing
- openssl aes-256-cbc -k "$IOS_ENCRYPTION_SECRET" -in scripts/ios_travis/ios-in-house.mobileprovision.enc -d -a -out scripts/ios_travis/ios-in-house.mobileprovision
- openssl aes-256-cbc -k "$IOS_ENCRYPTION_SECRET" -in scripts/ios_travis/ios-dist.cer.enc -d -a -out scripts/ios_travis/ios-dist.cer
- openssl aes-256-cbc -k "$IOS_ENCRYPTION_SECRET" -in scripts/ios_travis/ios-dist.p12.enc -d -a -out scripts/ios_travis/ios-dist.p12
- ./scripts/ios_travis/add-key.sh
# end iOS code signing
- ./scripts/${FLAVOR}/install.sh
script:
- ./scripts/travis_script.sh
- ./scripts/${FLAVOR}/run.sh
after_script:
- ./scripts/ios_travis/remove-key.sh
after_failure:
- "[ -f scripts/${FLAVOR}/run.sh ] && scripts/${FLAVOR}/run.sh"
notifications:
slack:
secure: HHQYr7sF8M1SzoWSqgKVYtwAgGdLLCyTMsQjFhEEQNYO92ZwURE5s03qWTGH5k8+4Yqn26yrXt3NztLC4JIOpcGervN2mSZyq4dZgFTcWEd61igw0qwSenlwvFfbE1ASK/KYCzfyn9MIfHN+ovwLoRxXZkPwinKDvl3DXjBaFNg=
git:
submodules: false

149
Makefile
View File

@@ -4,11 +4,16 @@ PREFIX ?= /usr/local
ANDROID_ABI ?= arm-v7
ifeq ($(shell uname -s), Darwin)
HOST ?= osx
HEADLESS ?= cgl
HOST = osx
HEADLESS = cgl
JOBS ?= $(shell sysctl -n hw.ncpu)
endif
HOST ?= linux
ifeq ($(shell uname -s), Linux)
HOST = linux
JOBS ?= $(shell grep --count processor /proc/cpuinfo)
endif
JOBS ?= 1
all: mbgl
@@ -26,52 +31,53 @@ config/%.gypi: configure
styles/styles:
git submodule update --init styles
ifeq ($(shell uname -s), Darwin)
SMCalloutView:
git submodule update --init platform/ios/vendor/SMCalloutView
else
SMCalloutView:
endif
KIF:
git submodule update --init test/ios/KIF
#### Build files ###############################################################
.PRECIOUS: Makefile/project
Makefile/project: config/$(HOST).gypi styles/styles SMCalloutView
deps/run_gyp gyp/$(HOST).gyp $(CONFIG_$(HOST)) $(LIBS_$(HOST)) --generator-output=./build/$(HOST) -f make
.PRECIOUS: Xcode/project
Xcode/project: config/$(HOST).gypi styles/styles SMCalloutView
deps/run_gyp gyp/$(HOST).gyp $(CONFIG_$(HOST)) $(LIBS_$(HOST)) --generator-output=./build/$(HOST) -f xcode
#### Library builds ############################################################
.PRECIOUS: Makefile/mbgl
Makefile/mbgl: config/$(HOST).gypi styles/styles SMCalloutView
deps/run_gyp mbgl.gyp $(CONFIG_$(HOST)) $(LIBS_$(HOST)) --generator-output=./build/$(HOST) -f make
mbgl: Makefile/mbgl
mbgl: Makefile/project
$(MAKE) -C build/$(HOST) BUILDTYPE=$(BUILDTYPE) everything
standalone: Makefile/mbgl
standalone: Makefile/project
LINK=`pwd`/gyp/link.py $(MAKE) -C build/$(HOST) BUILDTYPE=$(BUILDTYPE) standalone
install: Makefile/mbgl
install: Makefile/project
LINK=`pwd`/gyp/link.py $(MAKE) -C build/$(HOST) BUILDTYPE=$(BUILDTYPE) install
.PRECIOUS: Xcode/mbgl
Xcode/mbgl: config/$(HOST).gypi styles/styles SMCalloutView
deps/run_gyp mbgl.gyp $(CONFIG_$(HOST)) $(LIBS_$(HOST)) --generator-output=./build/$(HOST) -f xcode
##### Test builds ##############################################################
.PRECIOUS: Makefile/test
Makefile/test: test/test.gyp config/$(HOST).gypi styles/styles SMCalloutView
deps/run_gyp test/test.gyp $(CONFIG_$(HOST)) $(LIBS_$(HOST)) --generator-output=./build/$(HOST) -f make
.PHONY: test
test: Makefile/test
test: Makefile/project
$(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 styles/styles SMCalloutView
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 $(JOBS)
.PHONY: xtest
xtest: XCPRETTY := $(shell ./scripts/xcpretty.sh)
xtest: Xcode/project
xcodebuild -project ./build/osx/gyp/osx.xcodeproj -configuration $(BUILDTYPE) -target test -jobs $(JOBS) $(XCPRETTY)
xtest-%: xtest
./scripts/run_tests.sh "build/osx/Build/Products/$(BUILDTYPE)/test" --gtest_filter=$*
@@ -79,31 +85,23 @@ xtest-%: xtest
#### Mac OS X application builds ###############################################
.PRECIOUS: Makefile/osx
Makefile/osx: macosx/mapboxgl-app.gyp config/osx.gypi styles/styles
deps/run_gyp macosx/mapboxgl-app.gyp $(CONFIG_osx) $(LIBS_osx) --generator-output=./build/osx -f make
.PHONY: osx run-osx
osx: Makefile/osx
osx: Makefile/project
$(MAKE) -C build/osx BUILDTYPE=$(BUILDTYPE) osxapp
run-osx: osx
"build/osx/$(BUILDTYPE)/Mapbox GL.app/Contents/MacOS/Mapbox GL"
.PRECIOUS: Xcode/osx
Xcode/osx: macosx/mapboxgl-app.gyp config/osx.gypi styles/styles
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-proj: Xcode/project
open ./build/osx/gyp/osx.xcodeproj
xosx: Xcode/osx
xcodebuild -project ./build/osx/macosx/mapboxgl-app.xcodeproj -configuration $(BUILDTYPE) -target osxapp -jobs $(JOBS)
xosx: XCPRETTY := $(shell ./scripts/xcpretty.sh)
xosx: Xcode/project
xcodebuild -project ./build/osx/gyp/osx.xcodeproj -configuration $(BUILDTYPE) -target osxapp -jobs $(JOBS) $(XCPRETTY)
run-xosx: xosx
"build/osx/Build/Products/$(BUILDTYPE)/Mapbox GL.app/Contents/MacOS/Mapbox GL"
"gyp/build/$(BUILDTYPE)/Mapbox GL.app/Contents/MacOS/Mapbox GL"
# Legacy name
xproj: xosx-proj
@@ -113,21 +111,29 @@ xproj: xosx-proj
#### iOS application builds ####################################################
.PRECIOUS: Xcode/ios
Xcode/ios: ios/app/mapboxgl-app.gyp config/ios.gypi styles/styles SMCalloutView
deps/run_gyp ios/app/mapboxgl-app.gyp $(CONFIG_ios) $(LIBS_ios) --generator-output=./build/ios -f xcode
Xcode/ios: gyp/ios.gyp config/ios.gypi styles/styles SMCalloutView
deps/run_gyp gyp/ios.gyp $(CONFIG_ios) $(LIBS_ios) --generator-output=./build/ios -f xcode
.PHONY: ios-proj ios isim ipackage
ios-proj: Xcode/ios
open ./build/ios/ios/app/mapboxgl-app.xcodeproj
open ./build/ios/gyp/ios.xcodeproj
ios: XCPRETTY := $(shell ./scripts/xcpretty.sh)
ios: Xcode/ios
xcodebuild -sdk iphoneos ARCHS="arm64 armv7 armv7s" PROVISIONING_PROFILE="2b532944-bf3d-4bf4-aa6c-a81676984ae8" -project ./build/ios/ios/app/mapboxgl-app.xcodeproj -configuration Release -target iosapp -jobs $(JOBS)
xcodebuild -sdk iphoneos ARCHS="arm64 armv7 armv7s" PROVISIONING_PROFILE="2b532944-bf3d-4bf4-aa6c-a81676984ae8" -project ./build/ios/gyp/ios.xcodeproj -configuration Release -target iosapp -jobs $(JOBS) $(XCPRETTY)
isim: XCPRETTY := $(shell ./scripts/xcpretty.sh)
isim: Xcode/ios
xcodebuild -sdk iphonesimulator ARCHS="x86_64 i386" -project ./build/ios/ios/app/mapboxgl-app.xcodeproj -configuration Debug -target iosapp -jobs $(JOBS)
xcodebuild -sdk iphonesimulator ARCHS="x86_64 i386" -project ./build/ios/gyp/ios.xcodeproj -configuration Debug -target iosapp -jobs $(JOBS) $(XCPRETTY)
ipackage: clean Xcode/ios
./scripts/package_ios.sh
./scripts/ios/package.sh
ipackage-sim: clean Xcode/ios
./scripts/ios/package.sh sim
itest: ipackage-sim KIF
./scripts/ios/test.sh
# Legacy name
iproj: ios-proj
@@ -135,34 +141,20 @@ iproj: ios-proj
#### Linux application builds ##################################################
.PRECIOUS: Makefile/linux
Makefile/linux: linux/mapboxgl-app.gyp config/$(HOST).gypi styles/styles
deps/run_gyp linux/mapboxgl-app.gyp $(CONFIG_$(HOST)) $(LIBS_linux) --generator-output=./build/$(HOST) -f make
.PHONY: linux run-linux
linux: Makefile/linux
linux: Makefile/project
$(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 styles/styles
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
.PHONY: xlinux run-xlinux
xlinux: XCPRETTY := $(shell ./scripts/xcpretty.sh)
xlinux: Xcode/project
xcodebuild -project ./build/osx/gyp/osx.xcodeproj -configuration $(BUILDTYPE) -target linuxapp -jobs $(JOBS) $(XCPRETTY)
run-xlinux: xlinux
"build/osx/Build/Products/$(BUILDTYPE)/mapbox-gl"
# Legacy name
lproj: xlinux-proj
"gyp/build/$(BUILDTYPE)/mapbox-gl"
#### Android libaries #########################################################
@@ -194,22 +186,15 @@ android-deploy: $(ANDROID_ABIS)
android-project: android-lib
##### Render builds ############################################################
.PRECIOUS: Makefile/render
Makefile/render: bin/render.gyp config/$(HOST).gypi
deps/run_gyp bin/render.gyp $(CONFIG_$(HOST)) $(LIBS_$(HOST)) --generator-output=./build/$(HOST) -f make
render: Makefile/render
render: Makefile/project
$(MAKE) -C build/$(HOST) BUILDTYPE=$(BUILDTYPE) mbgl-render
.PRECIOUS: Xcode/render
Xcode/render: bin/render.gyp config/osx.gypi styles/styles
deps/run_gyp bin/render.gyp $(CONFIG_osx) $(LIBS_osx) --generator-output=./build/osx -f xcode
.PHONY: xrender-proj
xrender-proj: Xcode/render
open ./build/osx/bin/render.xcodeproj
.PHONY: xrender run-xrender
xrender: Xcode/project
xcodebuild -project ./build/osx/gyp/osx.xcodeproj -configuration $(BUILDTYPE) -target mbgl-render -jobs $(JOBS)
##### Maintenace operations ####################################################

View File

@@ -49,7 +49,7 @@ Target OS X: 10.9+
If you merely want to install the library for iOS and try it out as an Objective-C consumer:
0. Use [Homebrew](http://brew.sh/) to install Boost headers: `brew install boost`.
1. Run `./scripts/package_ios.sh`. The packaging script will produce the statically-linked `libMapboxGL.a`, `MapboxGL.bundle` for resources, and a `Headers` folder.
1. Run `make ipackage`. The packaging script will produce the statically-linked `libMapboxGL.a`, `MapboxGL.bundle` for resources, and a `Headers` folder.
2. Copy the contents of `build/ios/pkg/static` into your project. It should happen automatically, but ensure that:
- `Headers` is in your *Header Search Paths* (`HEADER_SEARCH_PATHS`) build setting.
- `MapboxGL.bundle` is in your target's *Copy Bundle Resources* build phase.
@@ -68,11 +68,13 @@ If you merely want to install the library for iOS and try it out as an Objective
5. [Set the Mapbox API access token](#mapbox-api-access-tokens).
6. `#import "MapboxGL.h"`
If you want to build from source and/or contribute to development of the project, run `make iproj`, which will create and open an Xcode project which can build the entire library from source as well as an Objective-C test app.
If you want to build from source and/or contribute to development of the project, run `make iproj`, which will create and open an Xcode project which can build the entire library from source as well as an Objective-C test app. If you don't have an Apple Developer account, change the destination from "My Mac" to a simulator such as "iPhone 6" before you run and build the app.
You can run `make itest` to run the included integration tests. Requires `gem install xcpretty`. If you want to run the tests in Xcode instead, first `make ipackage` to create a local static library version, then open `test/ios/ios-tests.xcodeproj`, and lastly `Command + U` on the `Mapbox GL Tests` application target.
Target devices: iPhone 4S and above (5, 5c, 5s, 6, 6 Plus) and iPad 2 and above (3, 4, Mini, Air, Mini 2, Air 2).
Target iOS: 7.0 through 8.1
Target iOS: 7.0 through latest 8.x.
## Linux
@@ -84,6 +86,7 @@ Install GCC 4.8+ if you are running Ubuntu 13.10 or older. Alternatively, you ca
sudo add-apt-repository --yes ppa:ubuntu-toolchain-r/test
sudo apt-get update
sudo apt-get install gcc-4.8 g++-4.8
export CXX=g++-4.8
Ensure you have git and other build essentials:
@@ -108,10 +111,6 @@ Otherwise, you can just install
sudo apt-get install libboost-dev libboost-program-options-dev
Once you're done installing the build dependencies, you can get started by running
./configure
Then, you can then proceed to build the library:
git submodule update --init

View File

@@ -1,5 +1,6 @@
#include <cstdint>
#include <cinttypes>
#include <cassert>
#include <string>
#include <locale>
@@ -255,20 +256,6 @@ void JNICALL nativeDestroySurface(JNIEnv *env, jobject obj, jlong nativeMapViewP
nativeMapView->destroySurface();
}
void JNICALL nativeStart(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeStart");
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
nativeMapView->start();
}
void JNICALL nativeStop(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeStop");
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
nativeMapView->stop();
}
void JNICALL nativePause(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativePause");
assert(nativeMapViewPtr != 0);
@@ -287,14 +274,7 @@ void JNICALL nativeUpdate(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeUpdate");
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
nativeMapView->getMap().triggerUpdate();
}
void JNICALL nativeTerminate(JNIEnv *env, jobject obj, jlong nativeMapViewPtr) {
mbgl::Log::Debug(mbgl::Event::JNI, "nativeTerminate");
assert(nativeMapViewPtr != 0);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
nativeMapView->getMap().terminate();
nativeMapView->getMap().update();
}
void JNICALL nativeResize(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jint width, jint height,
@@ -310,7 +290,7 @@ void JNICALL nativeResize(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jint
assert(fbWidth <= UINT16_MAX);
assert(fbHeight <= UINT16_MAX);
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
nativeMapView->resize(width, height, ratio, fbWidth, fbHeight);
nativeMapView->getMap().resize(width, height, ratio);
}
void JNICALL nativeRemoveClass(JNIEnv *env, jobject obj, jlong nativeMapViewPtr, jstring clazz) {
@@ -938,12 +918,9 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
{"nativeCreateSurface", "(JLandroid/view/Surface;)V",
reinterpret_cast<void *>(&nativeCreateSurface)},
{"nativeDestroySurface", "(J)V", reinterpret_cast<void *>(&nativeDestroySurface)},
{"nativeStart", "(J)V", reinterpret_cast<void *>(&nativeStart)},
{"nativeStop", "(J)V", reinterpret_cast<void *>(&nativeStop)},
{"nativePause", "(J)V", reinterpret_cast<void *>(&nativePause)},
{"nativeResume", "(J)V", reinterpret_cast<void *>(&nativeResume)},
{"nativeUpdate", "(J)V", reinterpret_cast<void *>(&nativeUpdate)},
{"nativeTerminate", "(J)V", reinterpret_cast<void *>(&nativeTerminate)},
{"nativeResize", "(JIIFII)V",
reinterpret_cast<void *>(static_cast<void JNICALL (
*)(JNIEnv *, jobject, jlong, jint, jint, jfloat, jint, jint)>(&nativeResize))},

View File

@@ -1,5 +1,6 @@
#include <cstdlib>
#include <ctime>
#include <cassert>
#include <memory>
#include <list>
#include <tuple>
@@ -16,6 +17,7 @@
#include <mbgl/platform/gl.hpp>
#include <mbgl/util/std.hpp>
#include <pthread.h>
pthread_once_t loadGLExtensions = PTHREAD_ONCE_INIT;
@@ -59,7 +61,7 @@ NativeMapView::NativeMapView(JNIEnv *env, jobject obj_)
: mbgl::View(*this),
fileCache(mbgl::android::cachePath + "/mbgl-cache.db"),
fileSource(&fileCache),
map(*this, fileSource) {
map(*this, fileSource, MapMode::Continuous, true) {
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::NativeMapView");
assert(env != nullptr);
@@ -121,11 +123,11 @@ void NativeMapView::deactivate() {
}
}
void NativeMapView::invalidate() {
void NativeMapView::invalidate(std::function<void()> render) {
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::invalidate");
if ((display != EGL_NO_DISPLAY) && (surface != EGL_NO_SURFACE)) {
map.render();
render();
if (!eglSwapBuffers(display, surface)) {
mbgl::Log::Error(mbgl::Event::OpenGL, "eglSwapBuffers() returned error %d",
@@ -576,23 +578,6 @@ EGLConfig NativeMapView::chooseConfig(const EGLConfig configs[], EGLint numConfi
return configId;
}
void NativeMapView::start() {
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::start");
if (display == EGL_NO_DISPLAY) {
initializeDisplay();
}
if (context == EGL_NO_CONTEXT) {
initializeContext();
}
assert(display != EGL_NO_DISPLAY);
assert(context != EGL_NO_CONTEXT);
map.start(true);
}
void loadExtensions() {
const GLubyte *str = glGetString(GL_EXTENSIONS);
if (str == nullptr) {
@@ -689,14 +674,6 @@ void loadExtensions() {
}
}
void NativeMapView::stop() {
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::stop");
if ((display != EGL_NO_DISPLAY) && (context != EGL_NO_CONTEXT)) {
map.stop();
}
}
void NativeMapView::pause(bool waitForPause) {
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::pause %s",
(waitForPause) ? "true" : "false");
@@ -824,9 +801,5 @@ void NativeMapView::updateFps() {
env = nullptr;
}
void NativeMapView::resize(uint16_t width, uint16_t height, float ratio, uint16_t fbWidth, uint16_t fbHeight) {
View::resize(width, height, ratio, fbWidth, fbHeight);
}
}
}

View File

@@ -419,7 +419,6 @@ public class MapView extends SurfaceView {
mNativeMapView.initializeDisplay();
mNativeMapView.initializeContext();
mNativeMapView.start();
}
// Called when we need to save instance state
@@ -441,7 +440,6 @@ public class MapView extends SurfaceView {
// Called when we need to clean up
// Must be called from Activity onDestroy
public void onDestroy() {
mNativeMapView.stop();
mNativeMapView.terminateContext();
mNativeMapView.terminateDisplay();
}

View File

@@ -73,14 +73,6 @@ class NativeMapView {
nativeDestroySurface(mNativeMapViewPtr);
}
public void start() {
nativeStart(mNativeMapViewPtr);
}
public void stop() {
nativeStop(mNativeMapViewPtr);
}
public void pause() {
nativePause(mNativeMapViewPtr);
}
@@ -386,18 +378,12 @@ class NativeMapView {
private native void nativeDestroySurface(long nativeMapViewPtr);
private native void nativeStart(long nativeMapViewPtr);
private native void nativeStop(long nativeMapViewPtr);
private native void nativePause(long nativeMapViewPtr);
private native void nativeResume(long nativeMapViewPtr);
private native void nativeUpdate(long nativeMapViewPtr);
private native void nativeTerminate(long nativeMapViewPtr);
private native void nativeResize(long nativeMapViewPtr, int width,
int height, float ratio, int fbWidth, int fbHeight);

View File

@@ -1,8 +0,0 @@
#!/usr/bin/env bash
set -e
set -o pipefail
export BUILDTYPE=Debug
./android/scripts/common.sh $1

View File

@@ -1,8 +0,0 @@
#!/usr/bin/env bash
set -e
set -o pipefail
export BUILDTYPE=Release
./android/scripts/common.sh $1

View File

@@ -1,40 +0,0 @@
#!/usr/bin/env bash
set -e
set -o pipefail
NAME=$1
case `uname -s` in
'Darwin') export JOBS=`sysctl -n hw.ncpu` ;;
'Linux') export JOBS=`nproc` ;;
*) export JOBS=1 ;;
esac
export CC=clang CXX=clang++
export MASON_PLATFORM=android
mkdir -p ./android/java/MapboxGLAndroidSDKTestApp/src/main/res/raw/
echo "${MAPBOX_ACCESS_TOKEN}" >> ./android/java/MapboxGLAndroidSDKTestApp/src/main/res/raw/token.txt
make android -j$JOBS BUILDTYPE=$BUILDTYPE JOBS=$JOBS
S3_PREFIX=s3://mapbox/mapbox-gl-native/android/build/${NAME}
APK_OUTPUTS=./android/java/MapboxGLAndroidSDKTestApp/build/outputs/apk
# Upload the shared object.
aws s3 cp \
./build/android-${ANDROID_ABI}/${BUILDTYPE}/lib.target/libmapbox-gl.so \
${S3_PREFIX}/libmapbox-gl.so
# Upload either the debug or the release build
if [ ${BUILDTYPE} == "Debug" ] ; then
aws s3 cp \
${APK_OUTPUTS}/MapboxGLAndroidSDKTestApp-debug.apk \
${S3_PREFIX}/MapboxGLAndroidSDKTestApp-debug.apk
elif [ ${BUILDTYPE} == "Release" ] ; then
aws s3 cp \
${APK_OUTPUTS}/MapboxGLAndroidSDKTestApp-release-unsigned.apk \
${S3_PREFIX}/MapboxGLAndroidSDKTestApp-release-unsigned.apk
fi

View File

@@ -1,85 +0,0 @@
#!/usr/bin/env bash
set -e
set -o pipefail
cwd=$(pwd)
region="us-east-1"
region_ami="ami-022e0c6a"
sleep=10
instance_name="android-gl-build-$TRAVIS_REPO_SLUG-$TRAVIS_JOB_NUMBER"
echo $ami_name
NAME=$TRAVIS_JOB_ID
user_data="#!/bin/bash
cd /android
git clone git://github.com/mapbox/mapbox-gl-native.git
pushd mapbox-gl-native
if [[ $TRAVIS_PULL_REQUEST == 'false' ]]; then
git checkout $TRAVIS_COMMIT
else
git fetch origin +refs/pull/$TRAVIS_PULL_REQUEST/merge:
git checkout FETCH_HEAD
fi
git submodule update --init --recursive
export ANDROID_NDK_PATH=/android/android-ndk-r10d
export JAVA_HOME=/android/jdk1.7.0_71
export ANDROID_HOME=/android/android-sdk-linux
export PATH=\$PATH:/android/jdk1.7.0_71/bin
export MAPBOX_ACCESS_TOKEN=$MAPBOX_ACCESS_TOKEN
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'
else
echo 'ANDROID BUILD FAILED'
fi
popd
aws s3 cp --region us-east-1 build.log s3://mapbox/mapbox-gl-native/android/build/${NAME}/build-log.txt
shutdown -P now"
id=$(aws ec2 run-instances \
--region $region \
--image-id $region_ami \
--count 1 \
--instance-type m3.large \
--iam-instance-profile Arn="$ANDROID_BUILD_INSTANCE_PROFILE" \
--instance-initiated-shutdown-behavior terminate \
--user-data "$user_data" | jq -r '.Instances[0].InstanceId')
echo "Instance: $region $id"
sleep 10
result=$(aws ec2 create-tags --region $region --resources $id --tags "Key=Name,Value=$instance_name")
instance_status_terminated=$(aws ec2 describe-instances --region $region --instance-id $id | jq -r '.Reservations[0].Instances[0].State.Name')
until [ "$instance_status_terminated" = "terminated" ]; do
instance_status_terminated=$(aws ec2 describe-instances --region $region --instance-id $id | jq -r '.Reservations[0].Instances[0].State.Name')
echo "Instance terminating status $region $id: $instance_status_terminated"
sleep $sleep
done
echo "Build finished"
output=$(aws ec2 get-console-output --region $region --instance-id $id | jq -r '.Output')
aws s3 cp --region $region s3://mapbox/mapbox-gl-native/android/build/${NAME}/build-log.txt build.log
cat build.log
if [[ $output == *"ANDROID BUILD PASSED"* ]]; then
echo "ANDROID BUILD PASSED"
exit 0
else
echo "ANDROID BUILD FAILED"
exit 1
fi

View File

@@ -31,32 +31,32 @@ 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)
ENV_android-arm-v8 = $(shell MASON_ANDROID_ABI=arm-v8 ./scripts/android/toolchain.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)
ENV_android-arm-v7 = $(shell MASON_ANDROID_ABI=arm-v7 ./scripts/android/toolchain.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)
ENV_android-arm-v5 = $(shell MASON_ANDROID_ABI=arm-v5 ./scripts/android/toolchain.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)
ENV_android-x86 = $(shell MASON_ANDROID_ABI=x86 ./scripts/android/toolchain.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)
# ENV_android-x86-64 = $(shell MASON_ANDROID_ABI=x86-64 ./scripts/android/toolchain.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)
ENV_android-mips = $(shell MASON_ANDROID_ABI=mips ./scripts/android/toolchain.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)
ENV_android-mips-64 = $(shell MASON_ANDROID_ABI=mips-64 ./scripts/android/toolchain.sh)
CONFIG_android-mips-64 = -Dhost=android -Iconfig/android-mips-64.gypi
LIBS_android = -Dheadless_lib=none

5
configure vendored
View File

@@ -15,7 +15,8 @@ function finish {
trap finish EXIT
# Install mason
. ./scripts/local_mason.sh
git submodule update --init .mason
export PATH="`pwd`/.mason:${PATH}" MASON_DIR="`pwd`/.mason"
case ${MASON_PLATFORM} in
'ios')
@@ -44,7 +45,7 @@ case ${MASON_PLATFORM} in
LIBCURL_VERSION=system
LIBUV_VERSION=0.10.28
ZLIB_VERSION=system
BOOST_VERSION=system
BOOST_VERSION=1.57.0
NUNICODE_VERSION=1.5.1
LIBZIP_VERSION=0.11.2
;;

View File

@@ -1,26 +0,0 @@
#!/usr/bin/env bash
set -e
set -o pipefail
export TRAVIS_OS_NAME=linux
cd build
source ./scripts/local_mason.sh
mason install mesa 10.4.3
export LD_LIBRARY_PATH=`mason prefix mesa 10.4.3`/lib
export DISPLAY=:99.0
Xvfb :99 -ac -screen 0 1024x768x24 &
if [[ ${CXX} == "g++" ]]; then
export CXX="g++-4.8"
export CC="gcc-4.8"
fi
source ./scripts/install_node.sh
make linux -j`nproc`
make test-* -j`nproc`
./scripts/compare_images.sh

5
gyp/ios.gyp Normal file
View File

@@ -0,0 +1,5 @@
{
'includes': [
'../ios/app/mapboxgl-app.gypi',
],
}

7
gyp/linux.gyp Normal file
View File

@@ -0,0 +1,7 @@
{
'includes': [
'../linux/mapboxgl-app.gypi',
'../test/test.gypi',
'../bin/render.gypi',
],
}

8
gyp/osx.gyp Normal file
View File

@@ -0,0 +1,8 @@
{
'includes': [
'../macosx/mapboxgl-app.gypi',
'../linux/mapboxgl-app.gypi',
'../test/test.gypi',
'../bin/render.gypi',
],
}

View File

@@ -12,6 +12,7 @@
'sources': [
'../platform/android/log_android.cpp',
'../platform/android/asset_root.cpp',
'../platform/default/thread.cpp',
'../platform/default/string_stdlib.cpp',
'../platform/default/image.cpp',
'../platform/default/image_reader.cpp',

View File

@@ -15,6 +15,7 @@
'../platform/darwin/application_root.mm',
'../platform/darwin/asset_root.mm',
'../platform/darwin/image.mm',
'../platform/darwin/nsthread.mm',
'../platform/darwin/reachability.m',
'../include/mbgl/ios/MapboxGL.h',
'../include/mbgl/ios/MGLMapboxEvents.h',
@@ -22,6 +23,8 @@
'../include/mbgl/ios/MGLMapView.h',
'../include/mbgl/ios/MGLMapView+IBAdditions.h',
'../platform/ios/MGLMapView.mm',
'../platform/ios/MGLFileCache.h',
'../platform/ios/MGLFileCache.mm',
'../include/mbgl/ios/MGLAccountManager.h',
'../platform/ios/MGLAccountManager.m',
'../include/mbgl/ios/MGLAnnotation.h',
@@ -33,6 +36,9 @@
'../include/mbgl/ios/MGLMetricsLocationManager.h',
'../platform/ios/MGLMetricsLocationManager.m',
'../include/mbgl/ios/MGLTypes.h',
'../platform/ios/NSBundle+MGLAdditions.h',
'../platform/ios/NSBundle+MGLAdditions.m',
'../platform/ios/NSException+MGLAdditions.h',
'../platform/ios/NSProcessInfo+MGLAdditions.h',
'../platform/ios/NSProcessInfo+MGLAdditions.m',
'../platform/ios/NSString+MGLAdditions.h',

View File

@@ -14,6 +14,7 @@
'../platform/default/string_stdlib.cpp',
'../platform/default/application_root.cpp',
'../platform/default/asset_root.cpp',
'../platform/default/thread.cpp',
'../platform/default/image.cpp',
'../platform/default/image_reader.cpp',
'../platform/default/png_reader.cpp',

View File

@@ -15,6 +15,7 @@
'../platform/darwin/application_root.mm',
'../platform/darwin/asset_root.mm',
'../platform/darwin/image.mm',
'../platform/darwin/nsthread.mm',
],
'variables': {

View File

@@ -23,7 +23,7 @@ public:
void activate() override;
void deactivate() override;
void notify() override;
void invalidate() override;
void invalidate(std::function<void()> render) override;
void notifyMapChange(mbgl::MapChange change, Duration delay = Duration::zero()) override;
@@ -39,17 +39,12 @@ public:
void createSurface(ANativeWindow *window);
void destroySurface();
void start();
void stop();
void resume();
void pause(bool waitForPause = false);
void enableFps(bool enable);
void updateFps();
void resize(uint16_t width, uint16_t height, float ratio, uint16_t fbWidth, uint16_t fbHeight);
private:
EGLConfig chooseConfig(const EGLConfig configs[], EGLint numConfigs);

View File

@@ -49,11 +49,6 @@ IB_DESIGNABLE
/** @name Managing Constraints */
/** A view controller whose top and bottom layout guides to use for proper setup of constraints in the map view internals.
*
* Certain components of the map view, such as the heading compass and the data attribution button, need to be aware of the view controller layout in order to avoid positioning content under a top navigation bar or a bottom toolbar. */
@property (nonatomic, weak) IBOutlet UIViewController *viewControllerForLayoutGuides;
#pragma mark - Accessing Map Properties
/** @name Accessing Map Properties */

View File

@@ -4,6 +4,7 @@ extern NSString *const MGLEventTypeMapLoad;
extern NSString *const MGLEventTypeMapTap;
extern NSString *const MGLEventTypeMapDragEnd;
extern NSString *const MGLEventTypeLocation;
extern NSString *const MGLEventTypeVisit;
extern NSString *const MGLEventKeyLatitude;
extern NSString *const MGLEventKeyLongitude;
@@ -16,6 +17,8 @@ extern NSString *const MGLEventKeyVerticalAccuracy;
extern NSString *const MGLEventKeyPushEnabled;
extern NSString *const MGLEventKeyEmailEnabled;
extern NSString *const MGLEventKeyGestureID;
extern NSString *const MGLEventKeyArrivalDate;
extern NSString *const MGLEventKeyDepartureDate;
extern NSString *const MGLEventGestureSingleTap;
extern NSString *const MGLEventGestureDoubleTap;
@@ -32,6 +35,7 @@ extern NSString *const MGLEventGestureRotateStart;
+ (void) setToken:(NSString *)token;
+ (void) setAppName:(NSString *)appName;
+ (void) setAppVersion:(NSString *)appVersion;
+ (void) setAppBuildNumber:(NSString *)appBuildNumber;
+ (void) pauseMetricsCollection;
+ (void) resumeMetricsCollection;

View File

@@ -5,7 +5,9 @@
// These methods can be called from any thread.
//
+ (instancetype)sharedManager;
+ (void) startUpdatingLocation;
+ (void) stopUpdatingLocation;
- (void) startUpdatingLocation;
- (void) stopUpdatingLocation;
- (void) startMonitoringVisits;
- (void) stopMonitoringVisits;
@end

View File

@@ -54,11 +54,6 @@ public:
// Only call this while the OpenGL context is exclusive to this thread.
void performCleanup();
// #############################################################################################
// Request to terminate the environment.
void terminate();
private:
unsigned id;
FileSource& fileSource;
@@ -67,9 +62,6 @@ private:
std::vector<uint32_t> abandonedVAOs;
std::vector<uint32_t> abandonedBuffers;
std::vector<uint32_t> abandonedTextures;
public:
uv_loop_t* const loop;
};
class EnvironmentScope final {

View File

@@ -1,96 +1,57 @@
#ifndef MBGL_MAP_MAP
#define MBGL_MAP_MAP
#include <mbgl/map/transform.hpp>
#include <mbgl/util/chrono.hpp>
#include <mbgl/map/update.hpp>
#include <mbgl/map/mode.hpp>
#include <mbgl/util/geo.hpp>
#include <mbgl/util/projection.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/ptr.hpp>
#include <mbgl/util/vec.hpp>
#include <cstdint>
#include <atomic>
#include <thread>
#include <iosfwd>
#include <set>
#include <vector>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <string>
#include <functional>
namespace uv { class async; }
#include <vector>
#include <memory>
namespace mbgl {
class Painter;
class GlyphStore;
class LayerDescription;
class Sprite;
class Style;
class StyleLayer;
class TexturePool;
class FileSource;
class View;
class GlyphAtlas;
class SpriteAtlas;
class LineAtlas;
class Environment;
class EnvironmentScope;
class AnnotationManager;
class MapData;
class Worker;
class MapContext;
class StillImage;
namespace util {
template <class T> class Thread;
}
class Map : private util::noncopyable {
friend class View;
public:
enum class Mode : uint8_t {
None, // we're not doing any processing
Continuous, // continually updating map
Still, // a once-off still image.
};
explicit Map(View&, FileSource&);
explicit Map(View&, FileSource&,
MapMode mode = MapMode::Continuous,
bool startPaused = false);
~Map();
// Start the map render thread. It is asynchronous.
void start(bool startPaused = false, Mode mode = Mode::Continuous);
inline void start(Mode renderMode) { start(false, renderMode); }
// Stop the map render thread. This call will block until the map rendering thread stopped.
// The optional callback function will be invoked repeatedly until the map thread is stopped.
// The callback function should wait until it is woken up again by view.notify(), otherwise
// this will be a busy waiting loop.
void stop(std::function<void ()> callback = std::function<void ()>());
// Pauses the render thread. The render thread will stop running but will not be terminated and will not lose state until resumed.
void pause(bool waitForPause = false);
// Resumes a paused render thread
void resume();
// Register a callback that will get called (on the render thread) when all resources have
// been loaded and a complete render occurs.
using StillImageCallback = std::function<void(std::unique_ptr<const StillImage>)>;
void renderStill(StillImageCallback callback);
// Triggers a synchronous or asynchronous render.
void renderSync();
// Unconditionally performs a render with the current map state. May only be called from the Map
// thread.
void render();
void renderAsync();
// Notifies the Map thread that the state has changed and an update might be necessary.
void triggerUpdate(Update = Update::Nothing);
// Triggers a render. Can be called from any thread.
void triggerRender();
// Releases resources immediately
void terminate();
void update(Update update = Update::Nothing);
// Styling
void addClass(const std::string&);
@@ -134,18 +95,23 @@ public:
double getBearing() const;
void resetNorth();
// Size
void resize(uint16_t width, uint16_t height, float ratio = 1);
uint16_t getWidth() const;
uint16_t getHeight() const;
// API
void setAccessToken(const std::string &token);
std::string getAccessToken() const;
// Projection
inline void getWorldBoundsMeters(ProjectedMeters &sw, ProjectedMeters &ne) const { Projection::getWorldBoundsMeters(sw, ne); }
inline void getWorldBoundsLatLng(LatLng &sw, LatLng &ne) const { Projection::getWorldBoundsLatLng(sw, ne); }
inline double getMetersPerPixelAtLatitude(const double lat, const double zoom) const { return Projection::getMetersPerPixelAtLatitude(lat, zoom); }
inline const ProjectedMeters projectedMetersForLatLng(const LatLng latLng) const { return Projection::projectedMetersForLatLng(latLng); }
inline const LatLng latLngForProjectedMeters(const ProjectedMeters projectedMeters) const { return Projection::latLngForProjectedMeters(projectedMeters); }
inline const vec2<double> pixelForLatLng(const LatLng latLng) const { return state.pixelForLatLng(latLng); }
inline const LatLng latLngForPixel(const vec2<double> pixel) const { return state.latLngForPixel(pixel); }
void getWorldBoundsMeters(ProjectedMeters &sw, ProjectedMeters &ne) const;
void getWorldBoundsLatLng(LatLng &sw, LatLng &ne) const;
double getMetersPerPixelAtLatitude(const double lat, const double zoom) const;
const ProjectedMeters projectedMetersForLatLng(const LatLng latLng) const;
const LatLng latLngForProjectedMeters(const ProjectedMeters projectedMeters) const;
const vec2<double> pixelForLatLng(const LatLng latLng) const;
const LatLng latLngForPixel(const vec2<double> pixel) const;
// Annotations
void setDefaultPointAnnotationSymbol(const std::string&);
@@ -160,7 +126,6 @@ public:
// Memory
void setSourceTileCacheSize(size_t);
size_t getSourceTileCacheSize() const { return sourceCacheSize; }
void onLowMemory();
// Debug
@@ -168,104 +133,9 @@ public:
void toggleDebug();
bool getDebug() const;
inline const TransformState &getState() const { return state; }
TimePoint getTime() const;
inline AnnotationManager& getAnnotationManager() const { return *annotationManager; }
private:
// Runs the map event loop. ONLY run this function when you want to get render a single frame
// with this map object. It will *not* spawn a separate thread and instead block until the
// frame is completely rendered.
void run();
// This may only be called by the View object.
void resize(uint16_t width, uint16_t height, float ratio = 1);
void resize(uint16_t width, uint16_t height, float ratio, uint16_t fbWidth, uint16_t fbHeight);
util::ptr<Sprite> getSprite();
Worker& getWorker();
// Checks if render thread needs to pause
void checkForPause();
// Setup
void setup();
void updateTiles();
// Triggered by triggerUpdate();
void update();
// Loads the style set in the data object. Called by Update::StyleInfo
void reloadStyle();
void loadStyleJSON(const std::string& json, const std::string& base);
// Prepares a map render by updating the tiles we need for the current view, as well as updating
// the stylesheet.
void prepare();
// Runs the function in the map thread.
void invokeTask(std::function<void()>&&);
template <typename Fn> auto invokeSyncTask(const Fn& fn) -> decltype(fn());
void processTasks();
void updateAnnotationTiles(const std::vector<TileID>&);
size_t sourceCacheSize;
Mode mode = Mode::None;
const std::unique_ptr<Environment> env;
std::unique_ptr<EnvironmentScope> scope;
View &view;
private:
std::unique_ptr<Worker> workers;
std::thread thread;
std::unique_ptr<uv::async> asyncTerminate;
std::unique_ptr<uv::async> asyncUpdate;
std::unique_ptr<uv::async> asyncInvoke;
std::unique_ptr<uv::async> asyncRender;
bool terminating = false;
bool pausing = false;
bool isPaused = false;
std::mutex mutexRun;
std::condition_variable condRun;
std::mutex mutexPause;
std::condition_variable condPause;
// Used to signal that rendering completed.
bool rendered = false;
std::condition_variable condRendered;
std::mutex mutexRendered;
// Stores whether the map thread has been stopped already.
std::atomic_bool isStopped;
Transform transform;
TransformState state;
FileSource& fileSource;
util::ptr<Style> style;
std::unique_ptr<GlyphAtlas> glyphAtlas;
util::ptr<GlyphStore> glyphStore;
std::unique_ptr<SpriteAtlas> spriteAtlas;
util::ptr<Sprite> sprite;
std::unique_ptr<LineAtlas> lineAtlas;
util::ptr<TexturePool> texturePool;
std::unique_ptr<Painter> painter;
std::unique_ptr<AnnotationManager> annotationManager;
const std::unique_ptr<MapData> data;
std::atomic<UpdateType> updated;
std::mutex mutexTask;
std::queue<std::function<void()>> tasks;
StillImageCallback callback;
const std::unique_ptr<util::Thread<MapContext>> context;
};
}

15
include/mbgl/map/mode.hpp Normal file
View File

@@ -0,0 +1,15 @@
#ifndef MBGL_MAP_MODE
#define MBGL_MAP_MODE
#include <cstdint>
namespace mbgl {
enum class MapMode : uint8_t {
Continuous, // continually updating map
Still, // a once-off still image
};
}
#endif

View File

@@ -9,7 +9,6 @@ using UpdateType = uint32_t;
enum class Update : UpdateType {
Nothing = 0,
StyleInfo = 1 << 0,
Debug = 1 << 1,
DefaultTransitionDuration = 1 << 2,
Classes = 1 << 3,

View File

@@ -2,6 +2,7 @@
#define MBGL_MAP_VIEW
#include <mbgl/util/chrono.hpp>
#include <functional>
#include <memory>
@@ -39,13 +40,13 @@ public:
virtual void notify() = 0;
// Called from the render thread. The implementation must trigger a rerender.
// (i.e. map->renderSync() or map->renderAsync() must be called as a result of this)
virtual void invalidate() = 0;
// Called from the render thread. The implementation should resize the framebuffer.
virtual void resize(uint16_t width, uint16_t height, float pixelRatio);
// Called from the render (=GL) thread. Signals that the contents of the contents
// may be discarded. The default is a no-op.
virtual void discard();
// Called from the render thread. The implementation must trigger a rerender.
// (i.e. either the passed render() function for rendering immediately on the map thread,
// or map->renderSync() from the main thread must be called as a result of this)
virtual void invalidate(std::function<void()> render) = 0;
// Reads the pixel data from the current framebuffer. If your View implementation
// doesn't support reading from the framebuffer, return a null pointer.
@@ -58,10 +59,6 @@ public:
MapChange change,
Duration delay = Duration::zero());
protected:
// Resizes the view
void resize(uint16_t width, uint16_t height, float ratio, uint16_t fbWidth, uint16_t fbHeight);
protected:
mbgl::Map *map = nullptr;
};

View File

@@ -17,7 +17,7 @@ public:
void activate() override;
void deactivate() override;
void notify() override;
void invalidate() override;
void invalidate(std::function<void()> render) override;
static void onKey(GLFWwindow *window, int key, int scancode, int action, int mods);
static void onScroll(GLFWwindow *window, double xoffset, double yoffset);
@@ -25,7 +25,7 @@ public:
static void onMouseClick(GLFWwindow *window, int button, int action, int modifiers);
static void onMouseMove(GLFWwindow *window, double x, double y);
int run();
void run();
void fps();
public:

View File

@@ -17,6 +17,7 @@ typedef XID GLXPbuffer;
#include <mbgl/platform/gl.hpp>
#include <memory>
#include <thread>
namespace mbgl {
@@ -28,13 +29,11 @@ public:
HeadlessView(std::shared_ptr<HeadlessDisplay> display, uint16_t width = 256, uint16_t height = 256, float pixelRatio = 1);
~HeadlessView();
void resize(uint16_t width, uint16_t height, float pixelRatio);
void activate() override;
void deactivate() override;
void notify() override;
void invalidate() override;
void discard() override;
void resize(uint16_t width, uint16_t height, float pixelRatio) override;
void invalidate(std::function<void()> render) override;
std::unique_ptr<StillImage> readStillImage() override;
private:
@@ -56,12 +55,7 @@ private:
float pixelRatio = 0;
};
// These are the values that represent the state of the current framebuffer.
Dimensions current;
// These are the values that will be used after the next discard() event.
std::mutex prospectiveMutex;
Dimensions prospective;
Dimensions dimensions;
#if MBGL_USE_CGL
CGLContextObj glContext = nullptr;

View File

@@ -10,10 +10,9 @@ extern "C"
}
#pragma GCC diagnostic push
#ifndef __clang__
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wshadow"
#endif
#include <boost/iostreams/stream.hpp>
#pragma GCC diagnostic pop

View File

@@ -12,10 +12,9 @@ extern "C"
#include <memory>
#pragma GCC diagnostic push
#ifndef __clang__
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wshadow"
#endif
#include <boost/iostreams/stream.hpp>
#pragma GCC diagnostic pop

View File

@@ -159,7 +159,7 @@ inline void start_group(const std::string &str) {
if (gl::PushDebugGroup != nullptr) {
MBGL_CHECK_ERROR(gl::PushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, GLsizei(str.size()), str.c_str()));
} else if (gl::PushGroupMarkerEXT != nullptr) {
MBGL_CHECK_ERROR(gl::PushGroupMarkerEXT(GLsizei(str.size()), str.c_str()));
MBGL_CHECK_ERROR(gl::PushGroupMarkerEXT(GLsizei(str.size() + 1), str.c_str()));
}
// fprintf(stderr, "%s%s\n", std::string(indent * 4, ' ').c_str(), str.c_str());
// indent++;

View File

@@ -21,6 +21,9 @@ const std::string &applicationRoot();
// Returns the path to the asset location.
const std::string &assetRoot();
// Makes the current thread low priority.
void makeThreadLowPriority();
// Shows an alpha image with the specified dimensions in a named window.
void showDebugImage(std::string name, const char *data, size_t width, size_t height);

View File

@@ -16,12 +16,9 @@ public:
~DefaultFileSource() override;
// FileSource API
Request *request(const Resource &resource, uv_loop_t *loop, const Environment &env,
Callback callback) override;
void cancel(Request *request) override;
void request(const Resource &resource, const Environment &env, Callback callback) override;
void abort(const Environment &env) override;
Request* request(const Resource&, uv_loop_t*, Callback) override;
void cancel(Request*) override;
void request(const Resource&, Callback) override;
public:
class Impl;

View File

@@ -15,7 +15,6 @@ typedef struct uv_loop_s uv_loop_t;
namespace mbgl {
class Request;
class Environment;
class FileSource : private util::noncopyable {
protected:
@@ -28,19 +27,12 @@ public:
// 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, const Environment &env,
Callback callback) = 0;
virtual void cancel(Request *request) = 0;
virtual Request* request(const Resource&, uv_loop_t*, Callback) = 0;
virtual void cancel(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, const Environment &env, Callback callback) = 0;
// This can be called from any thread. All requests with the environment pointer env should be
// notified as errored. Note that this is /different/ from canceling requests; a canceled
// request's callback is never called, while an aborted request's callback is called with
// a error message.
virtual void abort(const Environment &env) = 0;
virtual void request(const Resource&, Callback) = 0;
};
}

View File

@@ -17,14 +17,13 @@ typedef struct uv_loop_s uv_loop_t;
namespace mbgl {
class Response;
class Environment;
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, const Environment &env, Callback callback);
Request(const Resource &resource, uv_loop_t *loop, Callback callback);
public:
// May be called from any thread.
@@ -48,11 +47,6 @@ private:
public:
const Resource resource;
// The environment ref is used to associate requests with a particular environment. This allows
// us to only terminate requests associated with that environment, e.g. when the map the env
// belongs to is discarded.
const Environment &env;
};
}

View File

@@ -20,8 +20,9 @@ public:
void get(const Resource &resource, Callback callback) override;
void put(const Resource &resource, std::shared_ptr<const Response> response, Hint hint) override;
private:
class Impl;
private:
const std::unique_ptr<util::Thread<Impl>> thread;
};

View File

@@ -1,95 +0,0 @@
#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

@@ -0,0 +1,87 @@
#ifndef MBGL_UTIL_GL_HELPER
#define MBGL_UTIL_GL_HELPER
#include <mbgl/platform/gl.hpp>
#include <array>
namespace {
template <typename T, T (*Create)(), void (*Destroy)(const T&)>
class Preserve {
public:
Preserve() : data(Create()) {}
~Preserve() { Destroy(data); }
private:
const T data;
};
inline bool getBlend() {
return glIsEnabled(GL_BLEND);
}
inline void setBlend(const bool& enabled) {
enabled ? MBGL_CHECK_ERROR(glEnable(GL_BLEND)) : MBGL_CHECK_ERROR(glDisable(GL_BLEND));
}
inline std::array<double, 4> getClearColor() {
std::array<double, 4> color;
MBGL_CHECK_ERROR(glGetDoublev(GL_COLOR_CLEAR_VALUE, color.data()));
return color;
}
inline void setClearColor(const std::array<double, 4>& color) {
MBGL_CHECK_ERROR(glClearColor(color[0], color[1], color[2], color[3]));
}
inline std::array<GLenum, 2> getBlendFunc() {
GLint func[2];
glGetIntegerv(GL_BLEND_SRC, &func[0]);
glGetIntegerv(GL_BLEND_DST, &func[1]);
return {{ static_cast<GLenum>(func[0]), static_cast<GLenum>(func[1]) }};
}
inline void setBlendFunc(const std::array<GLenum, 2>& func) {
MBGL_CHECK_ERROR(glBlendFunc(func[0], func[1]));
}
inline std::array<double, 2> getPixelZoom() {
std::array<double, 2> zoom;
glGetDoublev(GL_ZOOM_X, &zoom[0]);
glGetDoublev(GL_ZOOM_Y, &zoom[1]);
return zoom;
}
inline void setPixelZoom(const std::array<double, 2>& func) {
MBGL_CHECK_ERROR(glPixelZoom(func[0], func[1]));
}
inline std::array<double, 4> getRasterPos() {
std::array<double, 4> pos;
MBGL_CHECK_ERROR(glGetDoublev(GL_CURRENT_RASTER_POSITION, pos.data()));
return pos;
}
inline void setRasterPos(const std::array<double, 4>& pos) {
MBGL_CHECK_ERROR(glRasterPos4d(pos[0], pos[1], pos[2], pos[3]));
}
} // end anonymous namespace
namespace mbgl {
namespace gl {
using PreserveBlend = Preserve<bool, getBlend, setBlend>;
using PreserveClearColor = Preserve<std::array<double, 4>, getClearColor, setClearColor>;
using PreserveBlendFunc = Preserve<std::array<GLenum, 2>, getBlendFunc, setBlendFunc>;
using PreservePixelZoom = Preserve<std::array<double, 2>, getPixelZoom, setPixelZoom>;
using PreserveRasterPos = Preserve<std::array<double, 4>, getRasterPos, setRasterPos>;
}
}
#endif

View File

@@ -74,6 +74,11 @@ inline vec2<T> normal(const S1& a, const S2& b) {
return { dx / c, dy / c };
}
template <typename T>
inline T perp(const T& a) {
return T(-a.y, a.x);
}
template <typename T, typename S1, typename S2>
inline T dist(const S1& a, const S2& b) {
T dx = b.x - a.x;
@@ -93,6 +98,11 @@ inline T mag(const S& a) {
return std::sqrt(a.x * a.x + a.y * a.y);
}
template <typename S>
inline S unit(const S& a) {
return a * (1 / mag(a));
}
template <typename T>
T clamp(T value, T min, T max) {
return value < min ? min : (value > max ? max : value);

View File

@@ -4,9 +4,8 @@
#include <string>
#pragma GCC diagnostic push
#ifndef __clang__
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#endif
#include <boost/lexical_cast.hpp>
#pragma GCC diagnostic pop

View File

@@ -61,7 +61,13 @@ struct vec2 {
template <typename O>
inline typename std::enable_if<!std::is_arithmetic<O>::value, vec2>::type
operator-(const O &o) const {
return {x - o.x, y - o.y};
return vec2<T>(x - o.x, y - o.y);
}
template <typename O>
inline typename std::enable_if<!std::is_arithmetic<O>::value, vec2>::type
operator+(const O &o) const {
return vec2<T>(x + o.x, y + o.y);
}
template <typename M>

View File

@@ -1,7 +1,7 @@
Pod::Spec.new do |m|
m.name = 'MapboxGL'
m.version = '0.2.15'
m.version = '0.2.19'
m.summary = 'Open source vector map solution for iOS with full styling capabilities.'
m.description = 'Open source OpenGL-based vector map solution for iOS with full styling capabilities and Cocoa bindings.'

View File

@@ -54,7 +54,6 @@ mbgl::Settings_NSUserDefaults *settings = nullptr;
self.mapView = [[MGLMapView alloc] initWithFrame:self.view.bounds];
self.mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.mapView.viewControllerForLayoutGuides = self;
self.mapView.showsUserLocation = YES;
self.mapView.delegate = self;
[self.view addSubview:self.mapView];

View File

@@ -21,7 +21,7 @@
<key>CFBundleSignature</key>
<string>MBGL</string>
<key>CFBundleVersion</key>
<string>0.0.2</string>
<string>0.0.3</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSHumanReadableCopyright</key>

View File

@@ -9,18 +9,18 @@
'product_extension': 'app',
'mac_bundle': 1,
'mac_bundle_resources': [
'<!@(find ./img -type f)',
'<!@(find ../ios/app/img -type f)',
'./features.geojson',
'./Settings.bundle/'
],
'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)',
'../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': [
@@ -38,7 +38,7 @@
'SDKROOT': 'iphoneos',
'SUPPORTED_PLATFORMS': 'iphonesimulator iphoneos',
'IPHONEOS_DEPLOYMENT_TARGET': '7.0',
'INFOPLIST_FILE': 'app-info.plist',
'INFOPLIST_FILE': '../ios/app/app-info.plist',
'TARGETED_DEVICE_FAMILY': '1,2',
'COMBINE_HIDPI_IMAGES': 'NO', # don't merge @2x.png images into .tiff files
'CLANG_ENABLE_OBJC_ARC': 'YES',

View File

@@ -90,7 +90,7 @@ int main(int argc, char *argv[]) {
map.setStyleURL(style);
int ret = view->run();
view->run();
// Save settings
mbgl::LatLng latLng = map.getLatLng();
@@ -101,5 +101,5 @@ int main(int argc, char *argv[]) {
settings.debug = map.getDebug();
settings.save();
return ret;
return 0;
}

View File

@@ -133,7 +133,7 @@ int main() {
// Load style
map.setStyleURL("asset://styles/bright-v7.json");
int ret = view.run();
view.run();
[reachability stopNotifier];
@@ -146,5 +146,5 @@ int main() {
settings.debug = map.getDebug();
settings.save();
return ret;
return 0;
}

View File

@@ -53,7 +53,7 @@
'OTHER_CPLUSPLUSFLAGS': [ '<@(cflags_cc)' ],
'OTHER_LDFLAGS': [ '<@(ldflags)' ],
'SDKROOT': 'macosx',
'INFOPLIST_FILE': 'Info.plist',
'INFOPLIST_FILE': '../macosx/Info.plist',
'CLANG_ENABLE_OBJC_ARC': 'YES'
},
}

View File

@@ -1,8 +1,8 @@
#include <mbgl/storage/http_request.hpp>
#include <mbgl/storage/http_context.hpp>
#include <mbgl/storage/resource.hpp>
#include <mbgl/storage/response.hpp>
#include <mbgl/util/uv.hpp>
#include <mbgl/util/std.hpp>
#include <mbgl/util/time.hpp>
#include <mbgl/util/parsedate.h>
@@ -45,32 +45,33 @@ enum class ResponseStatus : uint8_t {
class HTTPNSURLContext;
class HTTPRequestImpl {
class HTTPRequest : public RequestBase {
public:
HTTPRequestImpl(HTTPRequest *request, uv_loop_t *loop, std::shared_ptr<const Response> response);
~HTTPRequestImpl();
HTTPRequest(HTTPNSURLContext*,
const Resource&,
Callback,
uv_loop_t*,
std::shared_ptr<const Response>);
~HTTPRequest();
void cancel();
void cancelTimer();
void cancel() override;
void retry() override;
private:
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;
bool cancelled = false;
NSURLSessionDataTask *task = nullptr;
std::unique_ptr<Response> response;
const std::shared_ptr<const Response> existingResponse;
ResponseStatus status = ResponseStatus::PermanentError;
uv_async_t *async = nullptr;
uv::async async;
uv::timer timer;
int attempts = 0;
uv_timer_t *timer = nullptr;
enum : bool { PreemptImmediately, ExponentialBackoff } strategy = PreemptImmediately;
static const int maxAttempts = 4;
@@ -78,18 +79,20 @@ private:
// -------------------------------------------------------------------------------------------------
class HTTPNSURLContext : public HTTPContext<HTTPNSURLContext> {
class HTTPNSURLContext : public HTTPContext {
public:
HTTPNSURLContext(uv_loop_t *loop);
~HTTPNSURLContext();
RequestBase* createRequest(const Resource&,
RequestBase::Callback,
uv_loop_t*,
std::shared_ptr<const Response>) override;
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 =
@@ -115,34 +118,42 @@ HTTPNSURLContext::~HTTPNSURLContext() {
userAgent = nullptr;
}
RequestBase* HTTPNSURLContext::createRequest(const Resource& resource,
RequestBase::Callback callback,
uv_loop_t* loop,
std::shared_ptr<const Response> response) {
return new HTTPRequest(this, resource, callback, loop, response);
}
// -------------------------------------------------------------------------------------------------
HTTPRequestImpl::HTTPRequestImpl(HTTPRequest *request_, uv_loop_t *loop,
std::shared_ptr<const Response> existingResponse_)
: context(HTTPNSURLContext::Get(loop)),
request(request_),
HTTPRequest::HTTPRequest(HTTPNSURLContext* context_, const Resource& resource_, Callback callback_, uv_loop_t *loop, std::shared_ptr<const Response> existingResponse_)
: RequestBase(resource_, callback_),
context(context_),
existingResponse(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();
});
async(loop, [this] { handleResponse(); }),
timer(loop) {
context->addRequest(this);
start();
}
void HTTPRequestImpl::start() {
HTTPRequest::~HTTPRequest() {
assert(!task);
// Stop the backoff timer to avoid re-triggering this request.
timer.stop();
context->removeRequest(this);
}
void HTTPRequest::start() {
assert(!task);
attempts++;
@autoreleasepool {
NSMutableString *url = [[NSMutableString alloc] initWithString:@(request->resource.url.c_str())];
NSMutableString *url = [[NSMutableString alloc] initWithString:@(resource.url.c_str())];
if ([[NSUserDefaults standardUserDefaults] objectForKey:@"mapbox_metrics_disabled"] == nil) {
if ([url rangeOfString:@"?"].location == NSNotFound) {
[url appendString:@"?"];
@@ -174,13 +185,13 @@ void HTTPRequestImpl::start() {
}
}
void HTTPRequestImpl::handleResponse() {
void HTTPRequest::handleResponse() {
if (task) {
[task release];
task = nullptr;
}
if (request) {
if (!cancelled) {
if (status == ResponseStatus::TemporaryError && attempts < maxAttempts) {
strategy = ExponentialBackoff;
return retry((1 << (attempts - 1)) * 1000);
@@ -193,26 +204,21 @@ void HTTPRequestImpl::handleResponse() {
// Actually return the response.
if (status == ResponseStatus::NotModified) {
request->notify(std::move(response), FileCache::Hint::Refresh);
notify(std::move(response), FileCache::Hint::Refresh);
} else {
request->notify(std::move(response), FileCache::Hint::Full);
notify(std::move(response), FileCache::Hint::Full);
}
context->removeRequest(request);
request->ptr = nullptr;
delete request;
request = nullptr;
}
delete this;
}
void HTTPRequestImpl::cancel() {
context->removeRequest(request);
request = nullptr;
void HTTPRequest::cancel() {
context->removeRequest(this);
cancelled = true;
// Stop the backoff timer to avoid re-triggering this request.
cancelTimer();
timer.stop();
if (task) {
[task cancel];
@@ -223,29 +229,6 @@ void HTTPRequestImpl::cancel() {
}
}
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;
@@ -261,7 +244,7 @@ int64_t parseCacheControl(const char *value) {
return 0;
}
void HTTPRequestImpl::handleResult(NSData *data, NSURLResponse *res, NSError *error) {
void HTTPRequest::handleResult(NSData *data, NSURLResponse *res, NSError *error) {
if (error) {
if ([error code] == NSURLErrorCancelled) {
status = ResponseStatus::Canceled;
@@ -361,73 +344,28 @@ void HTTPRequestImpl::handleResult(NSData *data, NSURLResponse *res, NSError *er
response->message = "response class is not NSHTTPURLResponse";
}
uv_async_send(async);
async.send();
}
void HTTPRequestImpl::retry(uint64_t timeout) {
void HTTPRequest::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);
timer.stop();
timer.start(timeout, 0, [this] { start(); });
}
void HTTPRequestImpl::retryImmediately() {
void HTTPRequest::retry() {
// 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) {
if (strategy == PreemptImmediately) {
// Triggers the timer upon the next event loop iteration.
uv_timer_stop(timer);
uv_timer_start(timer, restart, 0, 0);
timer.stop();
timer.start(0, 0, [this] { start(); });
}
}
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::Impl *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::shared_ptr<const Response> response) {
MBGL_VERIFY_THREAD(tid);
assert(!ptr);
ptr = new HTTPRequestImpl(this, loop, response);
}
void HTTPRequest::retryImmediately() {
MBGL_VERIFY_THREAD(tid);
if (ptr) {
reinterpret_cast<HTTPRequestImpl *>(ptr)->retryImmediately();
}
}
void HTTPRequest::cancel() {
MBGL_VERIFY_THREAD(tid);
delete this;
std::unique_ptr<HTTPContext> HTTPContext::createContext(uv_loop_t* loop) {
return util::make_unique<HTTPNSURLContext>(loop);
}
}

View File

@@ -0,0 +1,13 @@
#import <Foundation/Foundation.h>
#include <mbgl/platform/platform.hpp>
namespace mbgl {
namespace platform {
void makeThreadLowPriority() {
[[NSThread currentThread] setThreadPriority:0.0];
}
}
}

View File

@@ -1,4 +1,5 @@
#include <mbgl/storage/asset_request.hpp>
#include <mbgl/storage/asset_context.hpp>
#include <mbgl/storage/resource.hpp>
#include <mbgl/storage/response.hpp>
#include <mbgl/util/std.hpp>
#include <mbgl/util/util.hpp>
@@ -6,27 +7,19 @@
#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;
#include <limits>
namespace mbgl {
class AssetRequestImpl {
class AssetRequest : public RequestBase {
MBGL_STORE_THREAD(tid)
public:
AssetRequestImpl(AssetRequest *request, uv_loop_t *loop);
~AssetRequestImpl();
AssetRequest(const Resource&, Callback, uv_loop_t*, const std::string& assetRoot);
~AssetRequest();
void cancel() override;
static void fileOpened(uv_fs_t *req);
static void fileStated(uv_fs_t *req);
@@ -35,8 +28,7 @@ public:
static void notifyError(uv_fs_t *req);
static void cleanup(uv_fs_t *req);
AssetRequest *request = nullptr;
std::string assetRoot;
bool canceled = false;
uv_fs_t req;
uv_file fd = -1;
@@ -44,33 +36,40 @@ public:
std::unique_ptr<Response> response;
};
AssetRequestImpl::~AssetRequestImpl() {
MBGL_VERIFY_THREAD(tid);
if (request) {
request->ptr = nullptr;
class AssetFSContext : public AssetContext {
RequestBase* createRequest(const Resource& resource,
RequestBase::Callback callback,
uv_loop_t* loop,
const std::string& assetRoot) override {
return new AssetRequest(resource, callback, loop, assetRoot);
}
};
AssetRequest::~AssetRequest() {
MBGL_VERIFY_THREAD(tid);
}
AssetRequestImpl::AssetRequestImpl(AssetRequest *request_, uv_loop_t *loop) : request(request_) {
AssetRequest::AssetRequest(const Resource& resource_, Callback callback_, uv_loop_t* loop, const std::string& assetRoot_)
: RequestBase(resource_, callback_),
assetRoot(assetRoot_) {
req.data = this;
const auto &url = request->resource.url;
const auto &url = 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 = request->source->assetRoot + "/" + url.substr(8);
path = assetRoot + "/" + url.substr(8);
}
uv_fs_open(loop, &req, path.c_str(), O_RDONLY, S_IRUSR, fileOpened);
}
void AssetRequestImpl::fileOpened(uv_fs_t *req) {
void AssetRequest::fileOpened(uv_fs_t *req) {
assert(req->data);
auto self = reinterpret_cast<AssetRequestImpl *>(req->data);
auto self = reinterpret_cast<AssetRequest *>(req->data);
MBGL_VERIFY_THREAD(self->tid);
if (req->result < 0) {
@@ -93,9 +92,9 @@ void AssetRequestImpl::fileOpened(uv_fs_t *req) {
}
}
void AssetRequestImpl::fileStated(uv_fs_t *req) {
void AssetRequest::fileStated(uv_fs_t *req) {
assert(req->data);
auto self = reinterpret_cast<AssetRequestImpl *>(req->data);
auto self = reinterpret_cast<AssetRequest *>(req->data);
MBGL_VERIFY_THREAD(self->tid);
if (req->result != 0 || self->canceled) {
@@ -121,9 +120,7 @@ void AssetRequestImpl::fileStated(uv_fs_t *req) {
#else
response->message = uv_strerror(UV_EFBIG);
#endif
assert(self->request);
self->request->notify(std::move(response), FileCache::Hint::No);
delete self->request;
self->notify(std::move(response), FileCache::Hint::No);
uv_fs_req_cleanup(req);
uv_fs_close(req->loop, req, self->fd, fileClosed);
@@ -148,9 +145,9 @@ void AssetRequestImpl::fileStated(uv_fs_t *req) {
}
}
void AssetRequestImpl::fileRead(uv_fs_t *req) {
void AssetRequest::fileRead(uv_fs_t *req) {
assert(req->data);
auto self = reinterpret_cast<AssetRequestImpl *>(req->data);
auto self = reinterpret_cast<AssetRequest *>(req->data);
MBGL_VERIFY_THREAD(self->tid);
if (req->result < 0 || self->canceled) {
@@ -160,18 +157,16 @@ void AssetRequestImpl::fileRead(uv_fs_t *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;
self->notify(std::move(self->response), FileCache::Hint::No);
}
uv_fs_req_cleanup(req);
uv_fs_close(req->loop, req, self->fd, fileClosed);
}
void AssetRequestImpl::fileClosed(uv_fs_t *req) {
void AssetRequest::fileClosed(uv_fs_t *req) {
assert(req->data);
auto self = reinterpret_cast<AssetRequestImpl *>(req->data);
auto self = reinterpret_cast<AssetRequest *>(req->data);
MBGL_VERIFY_THREAD(self->tid);
(void(self)); // Silence unused variable error in Release mode
@@ -182,70 +177,37 @@ void AssetRequestImpl::fileClosed(uv_fs_t *req) {
cleanup(req);
}
void AssetRequestImpl::notifyError(uv_fs_t *req) {
void AssetRequest::notifyError(uv_fs_t *req) {
assert(req->data);
auto self = reinterpret_cast<AssetRequestImpl *>(req->data);
auto self = reinterpret_cast<AssetRequest *>(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;
self->notify(std::move(response), FileCache::Hint::No);
}
}
void AssetRequestImpl::cleanup(uv_fs_t *req) {
void AssetRequest::cleanup(uv_fs_t *req) {
assert(req->data);
auto self = reinterpret_cast<AssetRequestImpl *>(req->data);
auto self = reinterpret_cast<AssetRequest *>(req->data);
MBGL_VERIFY_THREAD(self->tid);
uv_fs_req_cleanup(req);
delete self;
}
// -------------------------------------------------------------------------------------------------
AssetRequest::AssetRequest(DefaultFileSource::Impl *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::shared_ptr<const 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);
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 *)&req);
}
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;
}
std::unique_ptr<AssetContext> AssetContext::createContext(uv_loop_t*) {
return util::make_unique<AssetFSContext>();
}
}

View File

@@ -1,45 +1,40 @@
#include <mbgl/storage/asset_request.hpp>
#include <mbgl/storage/thread_context.hpp>
#include <mbgl/storage/asset_context.hpp>
#include <mbgl/android/jni.hpp>
#include <mbgl/storage/resource.hpp>
#include <mbgl/storage/response.hpp>
#include <mbgl/platform/log.hpp>
#include <mbgl/util/std.hpp>
#include <mbgl/util/util.hpp>
#include <mbgl/util/uv.hpp>
#include <uv.h>
#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 <map>
#include <cassert>
#include <forward_list>
namespace algo = boost::algorithm;
namespace mbgl {
class AssetZipContext : public ThreadContext<AssetZipContext> {
class AssetZipContext : public AssetContext {
public:
AssetZipContext(uv_loop_t *loop);
~AssetZipContext();
RequestBase* createRequest(const Resource& resource,
RequestBase::Callback callback,
uv_loop_t* loop,
const std::string& assetRoot) override;
uv_zip_t *getHandle(const std::string &path);
void returnHandle(const std::string &path, uv_zip_t *zip);
private:
// A list of resuable uv_zip handles to avoid creating and destroying them all the time.
std::map<std::string, std::forward_list<uv_zip_t *>> handles;
uv_loop_t *loop;
};
// -------------------------------------------------------------------------------------------------
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_) {
AssetZipContext::AssetZipContext(uv_loop_t *loop_) : loop(loop_) {
}
uv_zip_t *AssetZipContext::getHandle(const std::string &path) {
@@ -70,20 +65,18 @@ AssetZipContext::~AssetZipContext() {
handles.clear();
}
// -------------------------------------------------------------------------------------------------
class AssetRequestImpl {
class AssetRequest : public RequestBase {
MBGL_STORE_THREAD(tid)
public:
AssetRequestImpl(AssetRequest *request, uv_loop_t *loop);
~AssetRequestImpl();
AssetRequest(AssetZipContext&, const Resource&, Callback, const std::string& assetRoot);
~AssetRequest();
void cancel();
void cancel() override;
private:
AssetZipContext &context;
AssetRequest *request = nullptr;
bool cancelled = false;
const std::string root;
const std::string path;
std::unique_ptr<Response> response;
@@ -101,21 +94,18 @@ private:
void notifyError(const char *message);
};
// -------------------------------------------------------------------------------------------------
AssetRequestImpl::~AssetRequestImpl() {
MBGL_VERIFY_THREAD(tid);
if (request) {
request->ptr = nullptr;
}
RequestBase* AssetZipContext::createRequest(const Resource& resource,
RequestBase::Callback callback,
uv_loop_t*,
const std::string& assetRoot) {
return new AssetRequest(*this, resource, callback, assetRoot);
}
AssetRequestImpl::AssetRequestImpl(AssetRequest *request_, uv_loop_t *loop)
: context(*AssetZipContext::Get(loop)),
request(request_),
root(request->source->assetRoot),
path(std::string { "assets/" } + request->resource.url.substr(8)) {
AssetRequest::AssetRequest(AssetZipContext& context_, const Resource& resource_, Callback callback_, const std::string& assetRoot_)
: RequestBase(resource_, callback_),
context(context_),
root(assetRoot_),
path(std::string { "assets/" } + resource.url.substr(8)) {
auto zip = context.getHandle(root);
if (zip) {
archiveOpened(zip);
@@ -124,18 +114,19 @@ AssetRequestImpl::AssetRequestImpl(AssetRequest *request_, uv_loop_t *loop)
}
}
void AssetRequestImpl::openZipArchive() {
AssetRequest::~AssetRequest() {
MBGL_VERIFY_THREAD(tid);
}
void AssetRequest::openZipArchive() {
uv_fs_t *req = new uv_fs_t();
req->data = this;
assert(request);
assert(request->source);
// 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, root.c_str(), O_RDONLY, S_IRUSR, [](uv_fs_t *fsReq) {
if (fsReq->result < 0) {
auto impl = reinterpret_cast<AssetRequestImpl *>(fsReq->data);
auto impl = reinterpret_cast<AssetRequest *>(fsReq->data);
impl->notifyError(uv::getFileRequestError(fsReq));
delete impl;
} else {
@@ -143,7 +134,7 @@ void AssetRequestImpl::openZipArchive() {
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);
auto impl = reinterpret_cast<AssetRequest *>(openZip->data);
if (openZip->result < 0) {
impl->notifyError(openZip->message);
delete openZip;
@@ -163,20 +154,20 @@ void AssetRequestImpl::openZipArchive() {
#define INVOKE_MEMBER(name) \
[](uv_zip_t *zip_) { \
assert(zip_->data); \
reinterpret_cast<AssetRequestImpl *>(zip_->data)->name(zip_); \
reinterpret_cast<AssetRequest *>(zip_->data)->name(zip_); \
}
void AssetRequestImpl::archiveOpened(uv_zip_t *zip) {
void AssetRequest::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) {
void AssetRequest::fileStated(uv_zip_t *zip) {
MBGL_VERIFY_THREAD(tid);
if (!request || zip->result < 0) {
if (cancelled || zip->result < 0) {
// Stat failed, probably because the file doesn't exist.
if (zip->result < 0) {
notifyError(zip->message);
@@ -206,14 +197,14 @@ void AssetRequestImpl::fileStated(uv_zip_t *zip) {
}
}
void AssetRequestImpl::fileOpened(uv_zip_t *zip) {
void AssetRequest::fileOpened(uv_zip_t *zip) {
MBGL_VERIFY_THREAD(tid);
if (zip->result < 0) {
// Opening failed.
notifyError(zip->message);
cleanup(zip);
} else if (!request) {
} else if (cancelled) {
// The request was canceled. Close the file again.
uv_zip_fclose(context.loop, zip, zip->file, INVOKE_MEMBER(fileClosed));
} else {
@@ -221,23 +212,21 @@ void AssetRequestImpl::fileOpened(uv_zip_t *zip) {
}
}
void AssetRequestImpl::fileRead(uv_zip_t *zip) {
void AssetRequest::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) {
} else if (!cancelled) {
response->status = Response::Successful;
request->notify(std::move(response), FileCache::Hint::No);
delete request;
assert(request == nullptr);
notify(std::move(response), FileCache::Hint::No);
}
uv_zip_fclose(context.loop, zip, zip->file, INVOKE_MEMBER(fileClosed));
}
void AssetRequestImpl::fileClosed(uv_zip_t *zip) {
void AssetRequest::fileClosed(uv_zip_t *zip) {
MBGL_VERIFY_THREAD(tid);
if (zip->result < 0) {
@@ -247,66 +236,32 @@ void AssetRequestImpl::fileClosed(uv_zip_t *zip) {
cleanup(zip);
}
void AssetRequestImpl::cleanup(uv_zip_t *zip) {
void AssetRequest::cleanup(uv_zip_t *zip) {
MBGL_VERIFY_THREAD(tid);
context.returnHandle(root, zip);
delete this;
}
void AssetRequestImpl::notifyError(const char *message) {
void AssetRequest::notifyError(const char *message) {
MBGL_VERIFY_THREAD(tid);
if (request) {
if (!cancelled) {
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);
notify(std::move(response), FileCache::Hint::No);
} else {
// The request was already canceled and deleted.
}
}
void AssetRequestImpl::cancel() {
request = nullptr;
}
// -------------------------------------------------------------------------------------------------
AssetRequest::AssetRequest(DefaultFileSource::Impl *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::shared_ptr<const 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);
cancelled = true;
}
if (ptr) {
reinterpret_cast<AssetRequestImpl *>(ptr)->cancel();
}
delete this;
std::unique_ptr<AssetContext> AssetContext::createContext(uv_loop_t* loop) {
return util::make_unique<AssetZipContext>(loop);
}
}

View File

@@ -1,27 +1,22 @@
#include <mbgl/platform/default/glfw_view.hpp>
#include <mbgl/platform/gl.hpp>
#include <mbgl/platform/log.hpp>
#include <mbgl/util/gl_helper.hpp>
#include <cassert>
#include <pthread.h>
pthread_once_t loadGLExtensions = PTHREAD_ONCE_INIT;
GLFWView::GLFWView(bool fullscreen_) : fullscreen(fullscreen_) {
#ifdef NVIDIA
glDiscardFramebufferEXT = reinterpret_cast<PFNGLDISCARDFRAMEBUFFEREXTPROC>(glfwGetProcAddress("glDiscardFramebufferEXT"));
#endif
}
GLFWView::~GLFWView() {
glfwDestroyWindow(window);
glfwTerminate();
}
void glfwError(int error, const char *description) {
mbgl::Log::Error(mbgl::Event::OpenGL, "GLFW error (%i): %s", error, description);
assert(false);
}
void GLFWView::initialize(mbgl::Map *map_) {
View::initialize(map_);
GLFWView::GLFWView(bool fullscreen_) : fullscreen(fullscreen_) {
#ifdef NVIDIA
glDiscardFramebufferEXT = reinterpret_cast<PFNGLDISCARDFRAMEBUFFEREXTPROC>(glfwGetProcAddress("glDiscardFramebufferEXT"));
#endif
glfwSetErrorCallback(glfwError);
@@ -63,10 +58,6 @@ void GLFWView::initialize(mbgl::Map *map_) {
glfwMakeContextCurrent(window);
glfwSwapInterval(1);
int width, height;
glfwGetWindowSize(window, &width, &height);
onResize(window, width, height);
glfwSetCursorPosCallback(window, onMouseMove);
glfwSetMouseButtonCallback(window, onMouseClick);
glfwSetWindowSizeCallback(window, onResize);
@@ -160,6 +151,19 @@ void GLFWView::initialize(mbgl::Map *map_) {
glfwMakeContextCurrent(nullptr);
}
GLFWView::~GLFWView() {
glfwDestroyWindow(window);
glfwTerminate();
}
void GLFWView::initialize(mbgl::Map *map_) {
View::initialize(map_);
int width, height;
glfwGetWindowSize(window, &width, &height);
onResize(window, width, height);
}
void GLFWView::onKey(GLFWwindow *window, int key, int /*scancode*/, int action, int mods) {
GLFWView *view = reinterpret_cast<GLFWView *>(glfwGetWindowUserPointer(window));
@@ -221,7 +225,7 @@ void GLFWView::onResize(GLFWwindow *window, int width, int height ) {
int fbWidth, fbHeight;
glfwGetFramebufferSize(window, &fbWidth, &fbHeight);
view->resize(width, height, static_cast<float>(fbWidth) / static_cast<float>(width), fbWidth, fbHeight);
view->map->resize(width, height, static_cast<float>(fbWidth) / static_cast<float>(width));
}
void GLFWView::onMouseClick(GLFWwindow *window, int button, int action, int modifiers) {
@@ -264,21 +268,10 @@ void GLFWView::onMouseMove(GLFWwindow *window, double x, double y) {
view->lastY = y;
}
int GLFWView::run() {
map->start();
void GLFWView::run() {
while (!glfwWindowShouldClose(window)) {
glfwWaitEvents();
}
map->stop([]() {
glfwWaitEvents();
});
// Terminate here to save binary shaders
map->terminate();
return 0;
}
void GLFWView::activate() {
@@ -293,9 +286,8 @@ void GLFWView::notify() {
glfwPostEmptyEvent();
}
void GLFWView::invalidate() {
assert(map);
map->render();
void GLFWView::invalidate(std::function<void()> render) {
render();
glfwSwapBuffers(window);
fps();
}
@@ -342,15 +334,20 @@ void showDebugImage(std::string name, const char *data, size_t width, size_t hei
glfwGetFramebufferSize(debugWindow, &fbWidth, &fbHeight);
float scale = static_cast<float>(fbWidth) / static_cast<float>(width);
MBGL_CHECK_ERROR(glPixelZoom(scale, -scale));
MBGL_CHECK_ERROR(glRasterPos2f(-1.0f, 1.0f));
MBGL_CHECK_ERROR(glDrawPixels(width, height, GL_LUMINANCE, GL_UNSIGNED_BYTE, data));
{
gl::PreservePixelZoom pixelZoom;
gl::PreserveRasterPos rasterPos;
MBGL_CHECK_ERROR(glPixelZoom(scale, -scale));
MBGL_CHECK_ERROR(glRasterPos2f(-1.0f, 1.0f));
MBGL_CHECK_ERROR(glDrawPixels(width, height, GL_LUMINANCE, GL_UNSIGNED_BYTE, data));
}
glfwSwapBuffers(debugWindow);
glfwMakeContextCurrent(currentWindow);
}
void showColorDebugImage(std::string name, const char *data, size_t logicalWidth, size_t logicalHeight, size_t width, size_t height) {
glfwInit();
@@ -374,14 +371,22 @@ void showColorDebugImage(std::string name, const char *data, size_t logicalWidth
float xScale = static_cast<float>(fbWidth) / static_cast<float>(width);
float yScale = static_cast<float>(fbHeight) / static_cast<float>(height);
MBGL_CHECK_ERROR(glClearColor(0.8, 0.8, 0.8, 1));
MBGL_CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT));
MBGL_CHECK_ERROR(glEnable(GL_BLEND));
MBGL_CHECK_ERROR(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
{
gl::PreserveClearColor clearColor;
gl::PreserveBlend blend;
gl::PreserveBlendFunc blendFunc;
gl::PreservePixelZoom pixelZoom;
gl::PreserveRasterPos rasterPos;
MBGL_CHECK_ERROR(glClearColor(0.8, 0.8, 0.8, 1));
MBGL_CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT));
MBGL_CHECK_ERROR(glEnable(GL_BLEND));
MBGL_CHECK_ERROR(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
MBGL_CHECK_ERROR(glPixelZoom(xScale, -yScale));
MBGL_CHECK_ERROR(glRasterPos2f(-1.0f, 1.0f));
MBGL_CHECK_ERROR(glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, data));
}
MBGL_CHECK_ERROR(glPixelZoom(xScale, -yScale));
MBGL_CHECK_ERROR(glRasterPos2f(-1.0f, 1.0f));
MBGL_CHECK_ERROR(glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, data));
glfwSwapBuffers(debugWindow);
glfwMakeContextCurrent(currentWindow);

View File

@@ -41,7 +41,9 @@ namespace mbgl {
HeadlessView::HeadlessView(uint16_t width, uint16_t height, float pixelRatio)
: display(std::make_shared<HeadlessDisplay>()) {
activate();
resize(width, height, pixelRatio);
deactivate();
}
HeadlessView::HeadlessView(std::shared_ptr<HeadlessDisplay> display_,
@@ -49,7 +51,9 @@ HeadlessView::HeadlessView(std::shared_ptr<HeadlessDisplay> display_,
uint16_t height,
float pixelRatio)
: display(display_) {
activate();
resize(width, height, pixelRatio);
deactivate();
}
void HeadlessView::loadExtensions() {
@@ -150,30 +154,17 @@ bool HeadlessView::isActive() {
return std::this_thread::get_id() == thread;
}
void HeadlessView::resize(const uint16_t width, const uint16_t height, const float pixelRatio) {
std::lock_guard<std::mutex> lock(prospectiveMutex);
prospective = { width, height, pixelRatio };
}
HeadlessView::Dimensions::Dimensions(uint16_t width_, uint16_t height_, float pixelRatio_)
: width(width_), height(height_), pixelRatio(pixelRatio_) {
}
void HeadlessView::discard() {
assert(isActive());
{ // Obtain the new values.
std::lock_guard<std::mutex> lock(prospectiveMutex);
if (current.pixelWidth() == prospective.pixelWidth() && current.pixelHeight() == prospective.pixelHeight()) {
return;
}
current = prospective;
}
void HeadlessView::resize(const uint16_t width, const uint16_t height, const float pixelRatio) {
dimensions = { width, height, pixelRatio };
clearBuffers();
const unsigned int w = current.width * current.pixelRatio;
const unsigned int h = current.height * current.pixelRatio;
const unsigned int w = dimensions.width * dimensions.pixelRatio;
const unsigned int h = dimensions.height * dimensions.pixelRatio;
// Create depth/stencil buffer
MBGL_CHECK_ERROR(glGenRenderbuffersEXT(1, &fboDepthStencil));
@@ -208,15 +199,13 @@ void HeadlessView::discard() {
}
throw std::runtime_error(error.str());
}
View::resize(current.width, current.height, current.pixelRatio, w, h);
}
std::unique_ptr<StillImage> HeadlessView::readStillImage() {
assert(isActive());
const unsigned int w = current.pixelWidth();
const unsigned int h = current.pixelHeight();
const unsigned int w = dimensions.pixelWidth();
const unsigned int h = dimensions.pixelHeight();
auto image = util::make_unique<StillImage>();
image->width = w;
@@ -305,7 +294,6 @@ void HeadlessView::activate() {
#endif
loadExtensions();
discard();
}
void HeadlessView::deactivate() {
@@ -328,9 +316,8 @@ void HeadlessView::deactivate() {
#endif
}
void HeadlessView::invalidate() {
assert(map);
map->render();
void HeadlessView::invalidate(std::function<void()> render) {
render();
}
}

View File

@@ -1,10 +1,11 @@
#include <mbgl/storage/http_request.hpp>
#include <mbgl/storage/http_context.hpp>
#include <mbgl/storage/resource.hpp>
#include <mbgl/storage/response.hpp>
#include <mbgl/util/chrono.hpp>
#include <mbgl/platform/log.hpp>
#include <mbgl/util/time.hpp>
#include <mbgl/util/util.hpp>
#include <curl/curl.h>
@@ -53,14 +54,20 @@ enum class ResponseStatus : int8_t {
NotModified,
};
class HTTPRequestImpl;
class HTTPRequest;
class HTTPCURLContext : public HTTPContext<HTTPCURLContext> {
class HTTPCURLContext : public HTTPContext {
MBGL_STORE_THREAD(tid)
public:
HTTPCURLContext(uv_loop_t *loop);
~HTTPCURLContext();
RequestBase* createRequest(const Resource&,
RequestBase::Callback,
uv_loop_t*,
std::shared_ptr<const Response>) override;
static int handleSocket(CURL *handle, curl_socket_t s, int action, void *userp, void *socketp);
static void perform(uv_poll_t *req, int status, int events);
static int startTimeout(CURLM *multi, long timeout_ms, void *userp);
@@ -74,7 +81,8 @@ public:
void returnHandle(CURL *handle);
void checkMultiInfo();
public:
uv_loop_t *loop = nullptr;
// Used as the CURL timer function to periodically check for socket updates.
uv_timer_t *timeout = nullptr;
@@ -90,17 +98,21 @@ public:
std::queue<CURL *> handles;
};
class HTTPRequestImpl {
class HTTPRequest : public RequestBase {
MBGL_STORE_THREAD(tid)
public:
HTTPRequestImpl(HTTPRequest *request, uv_loop_t *loop, std::shared_ptr<const Response> response);
~HTTPRequestImpl();
HTTPRequest(HTTPCURLContext*,
const Resource&,
Callback,
uv_loop_t*,
std::shared_ptr<const Response>);
~HTTPRequest();
void cancel() override;
void retry() override;
void handleResult(CURLcode code);
void abandon();
void retryImmediately();
private:
static size_t headerCallback(char *const buffer, const size_t size, const size_t nmemb, void *userp);
@@ -115,9 +127,8 @@ private:
void finish(ResponseStatus status);
void start();
private:
HTTPCURLContext *context = nullptr;
HTTPRequest *request = nullptr;
bool cancelled = false;
// Will store the current response.
std::unique_ptr<Response> response;
@@ -175,10 +186,9 @@ private:
// -------------------------------------------------------------------------------------------------
template<> pthread_key_t ThreadContext<HTTPCURLContext>::key{};
template<> pthread_once_t ThreadContext<HTTPCURLContext>::once = PTHREAD_ONCE_INIT;
HTTPCURLContext::HTTPCURLContext(uv_loop_t *loop_) : HTTPContext(loop_) {
HTTPCURLContext::HTTPCURLContext(uv_loop_t *loop_)
: HTTPContext(loop_),
loop(loop_) {
if (curl_global_init(CURL_GLOBAL_ALL)) {
throw std::runtime_error("Could not init cURL");
}
@@ -197,6 +207,11 @@ HTTPCURLContext::HTTPCURLContext(uv_loop_t *loop_) : HTTPContext(loop_) {
}
HTTPCURLContext::~HTTPCURLContext() {
while (!handles.empty()) {
curl_easy_cleanup(handles.front());
handles.pop();
}
curl_multi_cleanup(multi);
multi = nullptr;
@@ -207,6 +222,13 @@ HTTPCURLContext::~HTTPCURLContext() {
uv::close(timeout);
}
RequestBase* HTTPCURLContext::createRequest(const Resource& resource,
RequestBase::Callback callback,
uv_loop_t* loop_,
std::shared_ptr<const Response> response) {
return new HTTPRequest(this, resource, callback, loop_, response);
}
CURL *HTTPCURLContext::getHandle() {
if (!handles.empty()) {
auto handle = handles.front();
@@ -230,7 +252,7 @@ void HTTPCURLContext::checkMultiInfo() {
while ((message = curl_multi_info_read(multi, &pending))) {
switch (message->msg) {
case CURLMSG_DONE: {
HTTPRequestImpl *baton = nullptr;
HTTPRequest *baton = nullptr;
curl_easy_getinfo(message->easy_handle, CURLINFO_PRIVATE, (char *)&baton);
assert(baton);
baton->handleResult(message->data.result);
@@ -425,13 +447,12 @@ static CURLcode sslctx_function(CURL * /* curl */, void *sslctx, void * /* parm
}
#endif
HTTPRequestImpl::HTTPRequestImpl(HTTPRequest *request_, uv_loop_t *loop, std::shared_ptr<const Response> response_)
: context(HTTPCURLContext::Get(loop)),
request(request_),
HTTPRequest::HTTPRequest(HTTPCURLContext* context_, const Resource& resource_, Callback callback_, uv_loop_t*, std::shared_ptr<const Response> response_)
: RequestBase(resource_, callback_),
context(context_),
existingResponse(response_),
handle(context->getHandle()) {
assert(request);
context->addRequest(request);
context->addRequest(this);
// Zero out the error buffer.
memset(error, 0, sizeof(error));
@@ -462,7 +483,7 @@ HTTPRequestImpl::HTTPRequestImpl(HTTPRequest *request_, uv_loop_t *loop, std::sh
handleError(curl_easy_setopt(handle, CURLOPT_CAINFO, "ca-bundle.crt"));
#endif
handleError(curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1));
handleError(curl_easy_setopt(handle, CURLOPT_URL, request->resource.url.c_str()));
handleError(curl_easy_setopt(handle, CURLOPT_URL, resource.url.c_str()));
handleError(curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, writeCallback));
handleError(curl_easy_setopt(handle, CURLOPT_WRITEDATA, this));
handleError(curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, headerCallback));
@@ -474,28 +495,10 @@ HTTPRequestImpl::HTTPRequestImpl(HTTPRequest *request_, uv_loop_t *loop, std::sh
start();
}
void HTTPRequestImpl::abandon() {
if (request) {
context->removeRequest(request);
request = nullptr;
}
}
void HTTPRequestImpl::start() {
// Count up the attempts.
attempts++;
// Start requesting the information.
handleError(curl_multi_add_handle(context->multi, handle));
}
HTTPRequestImpl::~HTTPRequestImpl() {
HTTPRequest::~HTTPRequest() {
MBGL_VERIFY_THREAD(tid);
if (request) {
context->removeRequest(request);
request->ptr = nullptr;
}
context->removeRequest(this);
handleError(curl_multi_remove_handle(context->multi, handle));
context->returnHandle(handle);
@@ -514,11 +517,23 @@ HTTPRequestImpl::~HTTPRequestImpl() {
}
}
void HTTPRequest::cancel() {
delete this;
}
void HTTPRequest::start() {
// Count up the attempts.
attempts++;
// Start requesting the information.
handleError(curl_multi_add_handle(context->multi, handle));
}
// This function is called when we have new data for a request. We just append it to the string
// containing the previous data.
size_t HTTPRequestImpl::writeCallback(void *const contents, const size_t size, const size_t nmemb, void *userp) {
size_t HTTPRequest::writeCallback(void *const contents, const size_t size, const size_t nmemb, void *userp) {
assert(userp);
auto impl = reinterpret_cast<HTTPRequestImpl *>(userp);
auto impl = reinterpret_cast<HTTPRequest *>(userp);
MBGL_VERIFY_THREAD(impl->tid);
if (!impl->response) {
@@ -560,9 +575,9 @@ int64_t parseCacheControl(const char *value) {
return 0;
}
size_t HTTPRequestImpl::headerCallback(char *const buffer, const size_t size, const size_t nmemb, void *userp) {
size_t HTTPRequest::headerCallback(char *const buffer, const size_t size, const size_t nmemb, void *userp) {
assert(userp);
auto baton = reinterpret_cast<HTTPRequestImpl *>(userp);
auto baton = reinterpret_cast<HTTPRequest *>(userp);
MBGL_VERIFY_THREAD(baton->tid);
if (!baton->response) {
@@ -589,8 +604,7 @@ size_t HTTPRequestImpl::headerCallback(char *const buffer, const size_t size, co
return length;
}
void HTTPRequestImpl::retry(uint64_t timeout) {
void HTTPRequest::retry(uint64_t timeout) {
handleError(curl_multi_remove_handle(context->multi, handle));
response.reset();
@@ -602,7 +616,7 @@ void HTTPRequestImpl::retry(uint64_t timeout) {
uv_timer_start(timer, restart, timeout, 0);
}
void HTTPRequestImpl::retryImmediately() {
void HTTPRequest::retry() {
// 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) {
@@ -613,12 +627,12 @@ void HTTPRequestImpl::retryImmediately() {
}
#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
void HTTPRequestImpl::restart(uv_timer_t *timer, int) {
void HTTPRequest::restart(uv_timer_t *timer, int) {
#else
void HTTPRequestImpl::restart(uv_timer_t *timer) {
void HTTPRequest::restart(uv_timer_t *timer) {
#endif
// Restart the request.
auto baton = reinterpret_cast<HTTPRequestImpl *>(timer->data);
auto baton = reinterpret_cast<HTTPRequest *>(timer->data);
// Get rid of the timer.
baton->timer = nullptr;
@@ -627,7 +641,7 @@ void HTTPRequestImpl::restart(uv_timer_t *timer) {
baton->start();
}
void HTTPRequestImpl::finish(ResponseStatus status) {
void HTTPRequest::finish(ResponseStatus status) {
if (status == ResponseStatus::TemporaryError && attempts < maxAttempts) {
strategy = ExponentialBackoff;
return retry((1 << (attempts - 1)) * 1000);
@@ -640,19 +654,18 @@ void HTTPRequestImpl::finish(ResponseStatus status) {
// Actually return the response.
if (status == ResponseStatus::NotModified) {
request->notify(std::move(response), FileCache::Hint::Refresh);
notify(std::move(response), FileCache::Hint::Refresh);
} else {
request->notify(std::move(response), FileCache::Hint::Full);
notify(std::move(response), FileCache::Hint::Full);
}
delete request;
delete this;
}
void HTTPRequestImpl::handleResult(CURLcode code) {
void HTTPRequest::handleResult(CURLcode code) {
MBGL_VERIFY_THREAD(tid);
if (!request) {
if (cancelled) {
// In this case, it doesn't make sense to even process the response even further since
// the request was canceled anyway.
delete this;
@@ -720,44 +733,8 @@ void HTTPRequestImpl::handleResult(CURLcode code) {
throw std::runtime_error("Response hasn't been handled");
}
// -------------------------------------------------------------------------------------------------
HTTPRequest::HTTPRequest(DefaultFileSource::Impl *source_, const Resource &resource_)
: SharedRequestBase(source_, resource_) {
}
HTTPRequest::~HTTPRequest() {
MBGL_VERIFY_THREAD(tid);
if (ptr) {
reinterpret_cast<HTTPRequestImpl *>(ptr)->abandon();
}
}
void HTTPRequest::start(uv_loop_t *loop, std::shared_ptr<const Response> response) {
MBGL_VERIFY_THREAD(tid);
assert(!ptr);
ptr = new HTTPRequestImpl(this, loop, response);
}
void HTTPRequest::retryImmediately() {
MBGL_VERIFY_THREAD(tid);
if (ptr) {
reinterpret_cast<HTTPRequestImpl *>(ptr)->retryImmediately();
}
}
void HTTPRequest::cancel() {
MBGL_VERIFY_THREAD(tid);
if (ptr) {
delete reinterpret_cast<HTTPRequestImpl *>(ptr);
ptr = nullptr;
}
delete this;
std::unique_ptr<HTTPContext> HTTPContext::createContext(uv_loop_t* loop) {
return util::make_unique<HTTPCURLContext>(loop);
}
}

View File

@@ -62,12 +62,12 @@ std::string unifyMapboxURLs(const std::string &url) {
using namespace mapbox::sqlite;
SQLiteCache::SQLiteCache(const std::string& path_)
: thread(util::make_unique<util::Thread<Impl>>("SQLite Cache", path_)) {
: thread(util::make_unique<util::Thread<Impl>>("SQLite Cache", util::ThreadPriority::Low, path_)) {
}
SQLiteCache::~SQLiteCache() = default;
SQLiteCache::Impl::Impl(const std::string& path_)
SQLiteCache::Impl::Impl(uv_loop_t*, const std::string& path_)
: path(path_) {
}
@@ -131,7 +131,7 @@ void SQLiteCache::get(const Resource &resource, Callback callback) {
// Will try to load the URL from the SQLite database and call the callback when done.
// Note that the callback is probably going to invoked from another thread, so the caller
// must make sure that it can run in that thread.
thread->invokeWithResult(&Impl::get, callback, resource);
thread->invokeWithResult(&Impl::get, std::move(callback), resource);
}
std::unique_ptr<Response> SQLiteCache::Impl::get(const Resource &resource) {
@@ -183,9 +183,9 @@ void SQLiteCache::put(const Resource &resource, std::shared_ptr<const Response>
// storing a new response or updating the currently stored response, potentially setting a new
// expiry date.
if (hint == Hint::Full) {
thread->invoke(&Impl::put, resource, std::move(response));
thread->invoke(&Impl::put, resource, response);
} else if (hint == Hint::Refresh) {
thread->invoke(&Impl::refresh, resource, int64_t(response->expires));
thread->invoke(&Impl::refresh, resource, response->expires);
}
}

View File

@@ -3,6 +3,8 @@
#include <mbgl/storage/sqlite_cache.hpp>
typedef struct uv_loop_s uv_loop_t;
namespace mapbox {
namespace sqlite {
class Database;
@@ -14,7 +16,7 @@ namespace mbgl {
class SQLiteCache::Impl {
public:
Impl(const std::string &path = ":memory:");
Impl(uv_loop_t*, const std::string &path = ":memory:");
~Impl();
std::unique_ptr<Response> get(const Resource&);

View File

@@ -0,0 +1,11 @@
#include <mbgl/platform/platform.hpp>
namespace mbgl {
namespace platform {
void makeThreadLowPriority() {
// no-op
}
}
}

View File

@@ -0,0 +1,10 @@
#import <Foundation/Foundation.h>
#include <mbgl/storage/sqlite_cache.hpp>
@interface MGLFileCache : NSObject
+ (mbgl::SQLiteCache *)obtainSharedCacheWithObject:(NSObject *)object;
+ (void)releaseSharedCacheForObject:(NSObject *)object;
@end

View File

@@ -0,0 +1,83 @@
#import "MGLFileCache.h"
@interface MGLFileCache ()
@property (nonatomic) MGLFileCache *sharedInstance;
@property (nonatomic) mbgl::SQLiteCache *sharedCache;
@property (nonatomic) NSHashTable *retainers;
@end
@implementation MGLFileCache
const std::string &defaultCacheDatabasePath() {
static const std::string path = []() -> std::string {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
if ([paths count] == 0) {
// Disable the cache if we don't have a location to write.
return "";
}
NSString *libraryDirectory = [paths objectAtIndex:0];
return [[libraryDirectory stringByAppendingPathComponent:@"cache.db"] UTF8String];
}();
return path;
}
- (instancetype)init {
self = [super init];
if (self) {
_retainers = [NSHashTable weakObjectsHashTable];
}
return self;
}
+ (instancetype)sharedInstance {
static dispatch_once_t onceToken;
static MGLFileCache *_sharedInstance;
dispatch_once(&onceToken, ^{
_sharedInstance = [[self alloc] init];
});
return _sharedInstance;
}
- (void)teardown {
if (self.sharedCache) {
delete self.sharedCache;
self.sharedCache = nullptr;
}
}
- (void)dealloc {
[self.retainers removeAllObjects];
[self teardown];
}
+ (mbgl::SQLiteCache *)obtainSharedCacheWithObject:(NSObject *)object {
return [[MGLFileCache sharedInstance] obtainSharedCacheWithObject:object];
}
- (mbgl::SQLiteCache *)obtainSharedCacheWithObject:(NSObject *)object {
assert([[NSThread currentThread] isMainThread]);
if (!self.sharedCache) {
self.sharedCache = new mbgl::SQLiteCache(defaultCacheDatabasePath());
}
[self.retainers addObject:object];
return self.sharedCache;
}
+ (void)releaseSharedCacheForObject:(NSObject *)object {
return [[MGLFileCache sharedInstance] releaseSharedCacheForObject:object];
}
- (void)releaseSharedCacheForObject:(NSObject *)object {
assert([[NSThread currentThread] isMainThread]);
if ([self.retainers containsObject:object]) {
[self.retainers removeObject:object];
}
if ([self.retainers count] == 0) {
[self teardown];
}
}
@end

File diff suppressed because it is too large Load Diff

View File

@@ -7,6 +7,8 @@
#import "MGLMetricsLocationManager.h"
#import "NSProcessInfo+MGLAdditions.h"
#import "NSBundle+MGLAdditions.h"
#import "NSException+MGLAdditions.h"
#include <sys/sysctl.h>
@@ -17,6 +19,7 @@ NSString *const MGLEventTypeMapLoad = @"map.load";
NSString *const MGLEventTypeMapTap = @"map.click";
NSString *const MGLEventTypeMapDragEnd = @"map.dragend";
NSString *const MGLEventTypeLocation = @"location";
NSString *const MGLEventTypeVisit = @"visit";
NSString *const MGLEventKeyLatitude = @"lat";
NSString *const MGLEventKeyLongitude = @"lng";
@@ -29,6 +32,8 @@ NSString *const MGLEventKeyVerticalAccuracy = @"verticalAccuracy";
NSString *const MGLEventKeyPushEnabled = @"enabled.push";
NSString *const MGLEventKeyEmailEnabled = @"enabled.email";
NSString *const MGLEventKeyGestureID = @"gesture";
NSString *const MGLEventKeyArrivalDate = @"arrivalDate";
NSString *const MGLEventKeyDepartureDate = @"departureDate";
NSString *const MGLEventGestureSingleTap = @"SingleTap";
NSString *const MGLEventGestureDoubleTap = @"DoubleTap";
@@ -62,6 +67,7 @@ NSString *const MGLEventGestureRotateStart = @"Rotation";
@property (atomic) NSString *token;
@property (atomic) NSString *appName;
@property (atomic) NSString *appVersion;
@property (atomic) NSString *appBuildNumber;
@property (atomic) NSString *instanceID;
@property (atomic) NSString *advertiserId;
@property (atomic) NSString *vendorId;
@@ -74,12 +80,13 @@ NSString *const MGLEventGestureRotateStart = @"Rotation";
@property (atomic) NSDateFormatter *rfc3339DateFormatter;
@property (atomic) CGFloat scale;
@property (atomic) NSURLSession *session;
@property (atomic) NSData *digicertCert;
@property (atomic) NSData *geoTrustCert;
// The isPaused state tracker is only ever accessed from the main thread.
// The paused state tracker is only ever accessed from the main thread.
//
@property (nonatomic) BOOL isPaused;
@property (nonatomic, getter=isPaused) BOOL paused;
// The timer is only ever accessed from the main thread.
//
@@ -105,19 +112,19 @@ NSString *const MGLEventGestureRotateStart = @"Rotation";
// Must be called from the main thread. Only called internally.
//
- (instancetype) init {
assert([[NSThread currentThread] isMainThread]);
MGLAssertIsMainThread();
self = [super init];
if (self) {
// Put Settings bundle into memory
NSString *settingsBundle = [[NSBundle mainBundle] pathForResource:@"Settings" ofType:@"bundle"];
if(!settingsBundle) {
NSString *appSettingsBundle = [[NSBundle mainBundle] pathForResource:@"Settings" ofType:@"bundle"];
if(!appSettingsBundle) {
NSLog(@"Could not find Settings.bundle");
} else {
// Dynamic Settings.bundle loading based on:
// http://stackoverflow.com/questions/510216/can-you-make-the-settings-in-settings-bundle-default-even-if-you-dont-open-the
NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[settingsBundle stringByAppendingPathComponent:@"Root.plist"]];
NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[appSettingsBundle stringByAppendingPathComponent:@"Root.plist"]];
NSArray *preferences = [settings objectForKey:@"PreferenceSpecifiers"];
NSMutableDictionary *defaultsToRegister = [[NSMutableDictionary alloc] initWithCapacity:[preferences count]];
for(NSDictionary *prefSpecification in preferences) {
@@ -136,22 +143,23 @@ NSString *const MGLEventGestureRotateStart = @"Rotation";
// Configure Events Infrastructure
// ===============================
_session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil];
_paused = YES;
[self resumeMetricsCollection];
NSBundle *resourceBundle = [NSBundle bundleWithPath:[NSBundle mgl_resourceBundlePath]];
// Load Local Copy of Server's Public Key
NSString *cerPath = nil;
NSArray *bundles = [NSBundle allFrameworks];
for (int lc = 0; lc < bundles.count; lc++) {
NSBundle *b = [bundles objectAtIndex:lc];
cerPath = [[NSBundle mainBundle] pathForResource:@"api_mapbox_com-geotrust" ofType:@"der"];
if (cerPath != nil) {
break;
}
}
cerPath = [resourceBundle pathForResource:@"api_mapbox_com-geotrust" ofType:@"der"];
if (cerPath != nil) {
_geoTrustCert = [NSData dataWithContentsOfFile:cerPath];
}
cerPath = nil;
cerPath = [resourceBundle pathForResource:@"api_mapbox_com-digicert" ofType:@"der"];
if (cerPath != nil) {
_digicertCert = [NSData dataWithContentsOfFile:cerPath];
}
// Events Control
_eventQueue = [[NSMutableArray alloc] init];
_flushAt = 20;
@@ -201,24 +209,21 @@ NSString *const MGLEventGestureRotateStart = @"Rotation";
// Enable Battery Monitoring
[UIDevice currentDevice].batteryMonitoringEnabled = YES;
_isPaused = NO;
}
return self;
}
// Can be called from any thread. Called implicitly from any
// public class convenience methods.
// public class convenience methods. May return nil if this feature is disabled.
//
+ (instancetype)sharedManager {
static dispatch_once_t onceToken;
static MGLMapboxEvents *_sharedManager;
dispatch_once(&onceToken, ^{
if ( ! NSProcessInfo.processInfo.mgl_isInterfaceBuilderDesignablesAgent) {
if ( ! NSProcessInfo.processInfo.mgl_isInterfaceBuilderDesignablesAgent &&
[[NSUserDefaults standardUserDefaults] objectForKey:@"mapbox_metrics_disabled"] == nil) {
void (^setupBlock)() = ^{
_sharedManager = [[self alloc] init];
// setup dedicated location manager on first use
[MGLMetricsLocationManager sharedManager];
};
if ( ! [[NSThread currentThread] isMainThread]) {
dispatch_sync(dispatch_get_main_queue(), ^{
@@ -233,47 +238,73 @@ NSString *const MGLEventGestureRotateStart = @"Rotation";
return _sharedManager;
}
- (void)dealloc {
[self pauseMetricsCollection];
}
// Must be called from the main thread.
//
+ (void) setToken:(NSString *)token {
assert([[NSThread currentThread] isMainThread]);
MGLAssertIsMainThread();
[MGLMapboxEvents sharedManager].token = token;
}
// Must be called from the main thread.
//
+ (void) setAppName:(NSString *)appName {
assert([[NSThread currentThread] isMainThread]);
MGLAssertIsMainThread();
[MGLMapboxEvents sharedManager].appName = appName;
}
// Must be called from the main thread.
//
+ (void) setAppVersion:(NSString *)appVersion {
assert([[NSThread currentThread] isMainThread]);
MGLAssertIsMainThread();
[MGLMapboxEvents sharedManager].appVersion = appVersion;
}
// Must be called from the main thread.
//
+ (void) pauseMetricsCollection {
assert([[NSThread currentThread] isMainThread]);
if ([MGLMapboxEvents sharedManager].isPaused) {
return;
}
[MGLMapboxEvents sharedManager].isPaused = YES;
[MGLMetricsLocationManager stopUpdatingLocation];
+ (void) setAppBuildNumber:(NSString *)appBuildNumber {
MGLAssertIsMainThread();
[MGLMapboxEvents sharedManager].appBuildNumber = appBuildNumber;
}
+ (void)pauseMetricsCollection {
[[MGLMapboxEvents sharedManager] pauseMetricsCollection];
}
// Must be called from the main thread.
//
+ (void) resumeMetricsCollection {
assert([[NSThread currentThread] isMainThread]);
if (![MGLMapboxEvents sharedManager].isPaused) {
- (void)pauseMetricsCollection {
MGLAssertIsMainThread();
if (self.paused) {
return;
}
[MGLMapboxEvents sharedManager].isPaused = NO;
[MGLMetricsLocationManager startUpdatingLocation];
self.paused = YES;
[_session invalidateAndCancel];
_session = nil;
MGLMetricsLocationManager *sharedLocationManager = [MGLMetricsLocationManager sharedManager];
[sharedLocationManager stopUpdatingLocation];
[sharedLocationManager stopMonitoringVisits];
}
+ (void)resumeMetricsCollection {
[[MGLMapboxEvents sharedManager] resumeMetricsCollection];
}
// Must be called from the main thread.
//
- (void)resumeMetricsCollection {
MGLAssertIsMainThread();
if (!self.isPaused) {
return;
}
self.paused = NO;
_session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil];
MGLMetricsLocationManager *sharedLocationManager = [MGLMetricsLocationManager sharedManager];
[sharedLocationManager startUpdatingLocation];
[sharedLocationManager startMonitoringVisits];
}
// Can be called from any thread. Can be called rapidly from
@@ -301,14 +332,8 @@ NSString *const MGLEventGestureRotateStart = @"Rotation";
return;
}
// Add Metrics Disabled App Wide Check
if ([[NSUserDefaults standardUserDefaults] objectForKey:@"mapbox_metrics_disabled"] != nil) {
[_eventQueue removeAllObjects];
return;
}
// Metrics Collection Has Been Paused
if (_isPaused) {
if (_paused) {
return;
}
@@ -462,8 +487,8 @@ NSString *const MGLEventGestureRotateStart = @"Rotation";
// Can be called from any thread.
//
- (NSString *) getUserAgent {
if (self.appName != nil && self.appVersion != nil && ([self.userAgent rangeOfString:self.appName].location == NSNotFound)) {
self.userAgent = [NSString stringWithFormat:@"%@/%@ %@", self.appName, self.appVersion, self.userAgent];
if (self.appName != nil && self.appVersion != nil && self.appBuildNumber != nil && ([self.userAgent rangeOfString:self.appName].location == NSNotFound)) {
self.userAgent = [NSString stringWithFormat:@"%@/%@/%@ %@", self.appName, self.appVersion, self.appBuildNumber, self.userAgent];
}
return self.userAgent;
}
@@ -686,6 +711,7 @@ NSString *const MGLEventGestureRotateStart = @"Rotation";
long numKeys = SecTrustGetCertificateCount(serverTrust);
BOOL found = false;
// Try GeoTrust Cert First
for (int lc = 0; lc < numKeys; lc++) {
SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, lc);
NSData *remoteCertificateData = CFBridgingRelease(SecCertificateCopyData(certificate));
@@ -700,8 +726,24 @@ NSString *const MGLEventGestureRotateStart = @"Rotation";
}
if (!found) {
// The certificate wasn't found in the certificate chain; cancel the connection
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
// Fallback to Digicert Cert
for (int lc = 0; lc < numKeys; lc++) {
SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, lc);
NSData *remoteCertificateData = CFBridgingRelease(SecCertificateCopyData(certificate));
// Compare Remote Key With Local Version
if ([remoteCertificateData isEqualToData:_digicertCert]) {
// Found the certificate; continue connecting
completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
found = true;
break;
}
}
if (!found) {
// The certificate wasn't found in GeoTrust nor Digicert. Cancel the connection.
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
}
}
}
else

View File

@@ -6,6 +6,7 @@
@interface MGLMetricsLocationManager() <CLLocationManagerDelegate>
@property (nonatomic) CLLocationManager *locationManager;
@property (atomic) NSDateFormatter *rfc3339DateFormatter;
@end
@@ -14,8 +15,18 @@
- (instancetype) init {
if (self = [super init]) {
_locationManager = [[CLLocationManager alloc] init];
_locationManager.desiredAccuracy = kCLLocationAccuracyKilometer;
_locationManager.distanceFilter = 10;
[_locationManager setDelegate:self];
_rfc3339DateFormatter = [[NSDateFormatter alloc] init];
NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
[_rfc3339DateFormatter setLocale:enUSPOSIXLocale];
[_rfc3339DateFormatter setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ssZ"];
// Clear Any System TimeZone Cache
[NSTimeZone resetSystemTimeZone];
[_rfc3339DateFormatter setTimeZone:[NSTimeZone systemTimeZone]];
}
return self;
}
@@ -29,12 +40,26 @@
return sharedManager;
}
+ (void) startUpdatingLocation {
[[MGLMetricsLocationManager sharedManager].locationManager startUpdatingLocation];
- (void)startUpdatingLocation {
[self.locationManager startUpdatingLocation];
}
+ (void) stopUpdatingLocation {
[[MGLMetricsLocationManager sharedManager].locationManager stopUpdatingLocation];
- (void)stopUpdatingLocation {
[self.locationManager stopUpdatingLocation];
}
- (void)startMonitoringVisits {
// -[CLLocationManager startMonitoringVisits] is only available in iOS 8+.
if ([self.locationManager respondsToSelector:@selector(startMonitoringVisits)]) {
[self.locationManager startMonitoringVisits];
}
}
- (void)stopMonitoringVisits {
// -[CLLocationManager stopMonitoringVisits] is only available in iOS 8+.
if ([self.locationManager respondsToSelector:@selector(stopMonitoringVisits)]) {
[self.locationManager stopMonitoringVisits];
}
}
#pragma mark CLLocationManagerDelegate
@@ -53,6 +78,16 @@
}
}
- (void)locationManager:(CLLocationManager *)manager didVisit:(CLVisit *)visit {
[MGLMapboxEvents pushEvent:MGLEventTypeVisit withAttributes:@{
MGLEventKeyLatitude: @(visit.coordinate.latitude),
MGLEventKeyLongitude: @(visit.coordinate.longitude),
MGLEventKeyHorizontalAccuracy: @(visit.horizontalAccuracy),
MGLEventKeyArrivalDate: [[NSDate distantPast] isEqualToDate:visit.arrivalDate] ? [NSNull null] : [_rfc3339DateFormatter stringFromDate:visit.arrivalDate],
MGLEventKeyDepartureDate: [[NSDate distantFuture] isEqualToDate:visit.departureDate] ? [NSNull null] : [_rfc3339DateFormatter stringFromDate:visit.departureDate]
}];
}
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
NSString *newStatus = nil;
switch (status) {
@@ -64,18 +99,21 @@
break;
case kCLAuthorizationStatusDenied:
newStatus = @"User Explcitly Denied";
[MGLMetricsLocationManager stopUpdatingLocation];
[self stopUpdatingLocation];
[self stopMonitoringVisits];
break;
case kCLAuthorizationStatusAuthorized:
newStatus = @"User Has Authorized / Authorized Always";
[MGLMetricsLocationManager startUpdatingLocation];
[self startUpdatingLocation];
[self startMonitoringVisits];
break;
// case kCLAuthorizationStatusAuthorizedAlways:
// newStatus = @"Not Determined";
// break;
// case kCLAuthorizationStatusAuthorizedAlways:
// newStatus = @"Not Determined";
// break;
case kCLAuthorizationStatusAuthorizedWhenInUse:
newStatus = @"User Has Authorized When In Use Only";
[MGLMetricsLocationManager startUpdatingLocation];
[self startUpdatingLocation];
[self startMonitoringVisits];
break;
default:
newStatus = @"Unknown";

View File

@@ -30,6 +30,7 @@ const CGFloat MGLTrackingDotRingWidth = 24.0;
self.annotation.mapView = mapView;
_mapView = mapView;
[self setupLayers];
self.accessibilityLabel = @"User location";
}
return self;
}

View File

@@ -0,0 +1,7 @@
#import <Foundation/Foundation.h>
@interface NSBundle (MGLAdditions)
+ (NSString *)mgl_resourceBundlePath;
@end

View File

@@ -0,0 +1,16 @@
#import "NSBundle+MGLAdditions.h"
#import "MGLMapView.h"
@implementation NSBundle (MGLAdditions)
+ (NSString *)mgl_resourceBundlePath
{
NSString *resourceBundlePath = [[NSBundle bundleForClass:[MGLMapView class]] pathForResource:@"MapboxGL" ofType:@"bundle"];
if ( ! resourceBundlePath) resourceBundlePath = [[NSBundle mainBundle] bundlePath];
return resourceBundlePath;
}
@end

View File

@@ -0,0 +1,3 @@
#import <Foundation/Foundation.h>
#define MGLAssertIsMainThread() NSAssert([[NSThread currentThread] isMainThread], @"-[%@ %@] must be accessed on the main thread, not %@", [self class], NSStringFromSelector(_cmd), [NSThread currentThread])

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

15
scripts/android/install.sh Executable file
View File

@@ -0,0 +1,15 @@
#!/usr/bin/env bash
set -e
set -o pipefail
source ./scripts/travis_helper.sh
mapbox_time "checkout_mason" \
git submodule update --init .mason
export MASON_PLATFORM=android
export MASON_ANDROID_ABI=${ANDROID_ABI}
mapbox_time "android_toolchain" \
./scripts/android/toolchain.sh

61
scripts/android/run.sh Executable file
View File

@@ -0,0 +1,61 @@
#!/usr/bin/env bash
set -e
set -o pipefail
BUILDTYPE=${BUILDTYPE:-Release}
TESTMUNK=${TESTMUNK:-no}
export HOST=android
export MASON_PLATFORM=android
export MASON_ANDROID_ABI=${ANDROID_ABI:-arm-v7}
source ./scripts/travis_helper.sh
# Add Mason to PATH
export PATH="`pwd`/.mason:${PATH}" MASON_DIR="`pwd`/.mason"
################################################################################
# Build
################################################################################
mapbox_time "checkout_styles" \
git submodule update --init styles
mkdir -p ./android/java/MapboxGLAndroidSDKTestApp/src/main/res/raw
echo "${MAPBOX_ACCESS_TOKEN}" > ./android/java/MapboxGLAndroidSDKTestApp/src/main/res/raw/token.txt
mapbox_time "compile_library" \
make android-lib -j${JOBS} BUILDTYPE=${BUILDTYPE}
mapbox_time "build_apk" \
make android -j${JOBS} BUILDTYPE=${BUILDTYPE}
################################################################################
# Deploy
################################################################################
if [ ! -z "${AWS_ACCESS_KEY_ID}" ] && [ ! -z "${AWS_SECRET_ACCESS_KEY}" ] ; then
# Install and add awscli to PATH for uploading the results
mapbox_time "install_awscli" \
pip install --user awscli
export PATH="`python -m site --user-base`/bin:${PATH}"
mapbox_time_start "deploy_results"
echo "Deploying results..."
S3_PREFIX=s3://mapbox/mapbox-gl-native/android/build/${TRAVIS_JOB_NUMBER}
APK_OUTPUTS=./android/java/MapboxGLAndroidSDKTestApp/build/outputs/apk
# Upload either the debug or the release build
if [ ${BUILDTYPE} == "Debug" ] ; then
aws s3 cp \
${APK_OUTPUTS}/MapboxGLAndroidSDKTestApp-debug.apk \
${S3_PREFIX}/MapboxGLAndroidSDKTestApp-debug.apk
elif [ ${BUILDTYPE} == "Release" ] ; then
aws s3 cp \
${APK_OUTPUTS}/MapboxGLAndroidSDKTestApp-release-unsigned.apk \
${S3_PREFIX}/MapboxGLAndroidSDKTestApp-release-unsigned.apk
fi
mapbox_time_finish
fi

26
scripts/android/toolchain.sh Executable file
View File

@@ -0,0 +1,26 @@
#!/usr/bin/env bash
set -e
set -o pipefail
export MASON_PLATFORM=android
export MASON_ANDROID_ABI=${MASON_ANDROID_ABI:-arm-v7}
export PATH="`pwd`/.mason:${PATH}"
export MASON_DIR="`pwd`/.mason"
export PATH=`mason env PATH`
echo MASON_PLATFORM=\"${MASON_PLATFORM}\"
echo MASON_ANDROID_ABI=\"${MASON_ANDROID_ABI}\"
echo CXX=\"`which $(mason env CXX)`\"
echo CC=\"`which $(mason env CC)`\"
echo LD=\"`which $(mason env LD)`\"
echo LINK=\"`which $(mason env CXX)`\"
echo AR=\"`which $(mason env AR)`\"
echo RANLIB=\"`which $(mason env RANLIB)`\"
echo STRIP=\"`which $(mason env STRIP)`\"
echo LDFLAGS=\"`mason env LDFLAGS` \${LDFLAGS:-}\"
echo CFLAGS=\"`mason env CFLAGS` \${CFLAGS:-}\"
echo CXXFLAGS=\"`mason env CXXFLAGS` \${CXXFLAGS:-}\"
echo CPPFLAGS=\"`mason env CPPFLAGS` \${CPPFLAGS:-}\"
echo JNIDIR=\"`mason env JNIDIR`\"

View File

@@ -1,25 +0,0 @@
#!/usr/bin/env bash
set -e
set -o pipefail
./scripts/local_mason.sh
export MASON_PLATFORM=android
export PATH=`.mason/mason env PATH`
echo MASON_PLATFORM=\"android\"
echo MASON_ANDROID_ABI=\"${MASON_ANDROID_ABI}\"
echo CXX=\"`which $(.mason/mason env CXX)`\"
echo CC=\"`which $(.mason/mason env CC)`\"
echo LD=\"`which $(.mason/mason env LD)`\"
echo LINK=\"`which $(.mason/mason env CXX)`\"
echo AR=\"`which $(.mason/mason env AR)`\"
echo RANLIB=\"`which $(.mason/mason env RANLIB)`\"
echo STRIP=\"`which $(.mason/mason env STRIP)`\"
echo LDFLAGS=\"`.mason/mason env LDFLAGS` ${LDFLAGS}\"
echo CFLAGS=\"`.mason/mason env CFLAGS` ${CFLAGS}\"
echo CPPFLAGS=\"`.mason/mason env CPPFLAGS` ${CPPFLAGS}\"
echo JNIDIR=\"`.mason/mason env JNIDIR`\"

View File

@@ -1,32 +0,0 @@
#!/usr/bin/env bash
if [[ ${TRAVIS_OS_NAME} == "linux" ]]; then
export DISPLAY=:99.0
if [[ ${MASON_PLATFORM} != "android" ]]; then
sh -e /etc/init.d/xvfb start
fi
# use g++ that supports c++11
if [[ ${CXX} == "g++" ]]; then
export CXX="g++-4.8"
export CC="gcc-4.8"
fi
# If building in debug then turn on sanitizers.
# They should both work with latest g++/clang++
# but it's not worth a standalone matrix so here
# we just test address->gcc and thread->clang for
# some limited coverage
# if [[ ${BUILDTYPE} == "Debug" ]]; then
# if [[ ${CXX} == "g++" ]]; then
# export CXXFLAGS="-fsanitize=address -g ${CXXFLAGS}"
# export CFLAGS="-fsanitize=address -g ${CFLAGS}"
# export LDFLAGS="-fsanitize=address ${LDFLAGS}"
# elif [[ ${CXX} == "clang++" ]]; then
# export CXXFLAGS="-fsanitize=thread -g -fPIC ${CXXFLAGS}"
# export CFLAGS="-fsanitize=thread -g ${CFLAGS}"
# export LDFLAGS="-fsanitize=thread -pie ${LDFLAGS}"
# fi
# fi
fi

View File

@@ -1,4 +0,0 @@
#!/usr/bin/env bash
mason install node 0.10.35
export PATH="`mason prefix node 0.10.35`/bin":"$PATH"

View File

@@ -16,10 +16,10 @@ security unlock-keychain -p travis ios-build.keychain
security set-keychain-settings -t 3600 -l ~/Library/Keychains/ios-build.keychain
# Add certificates to keychain and allow codesign to access them
security import ./scripts/ios_travis/apple.crt -k ~/Library/Keychains/ios-build.keychain -T /usr/bin/codesign
security import ./scripts/ios_travis/ios-dist.cer -k ~/Library/Keychains/ios-build.keychain -T /usr/bin/codesign
security import ./scripts/ios_travis/ios-dist.p12 -k ~/Library/Keychains/ios-build.keychain -P $IOS_KEY_PASSWORD -T /usr/bin/codesign
security import ./scripts/ios/apple.crt -k ~/Library/Keychains/ios-build.keychain -T /usr/bin/codesign
security import ./scripts/ios/ios-dist.cer -k ~/Library/Keychains/ios-build.keychain -T /usr/bin/codesign
security import ./scripts/ios/ios-dist.p12 -k ~/Library/Keychains/ios-build.keychain -P $IOS_KEY_PASSWORD -T /usr/bin/codesign
# Put the provisioning profile in place
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
cp "./scripts/ios_travis/$IOS_PROFILE_NAME.mobileprovision" ~/Library/MobileDevice/Provisioning\ Profiles/
cp "./scripts/ios/$IOS_PROFILE_NAME.mobileprovision" ~/Library/MobileDevice/Provisioning\ Profiles/

13
scripts/ios/after_failure.sh Executable file
View File

@@ -0,0 +1,13 @@
#!/usr/bin/env bash
set -e
set -o pipefail
set -u
ls $KIF_SCREENSHOTS/
REPO_NAME=$(basename $TRAVIS_REPO_SLUG)
aws s3 cp $KIF_SCREENSHOTS/ s3://mapbox/$REPO_NAME/ios/tests/$TRAVIS_JOB_NUMBER/ --acl public-read --recursive > /dev/null
echo http://mapbox.s3.amazonaws.com/$REPO_NAME/ios/tests/$TRAVIS_JOB_NUMBER/index.html

15
scripts/ios/install.sh Executable file
View File

@@ -0,0 +1,15 @@
#!/usr/bin/env bash
set -e
set -o pipefail
source ./scripts/travis_helper.sh
mapbox_time "checkout_mason" \
git submodule update --init .mason
export PATH="`pwd`/.mason:${PATH}" MASON_DIR="`pwd`/.mason"
mapbox_time "install_xcpretty" \
gem install xcpretty --no-rdoc --no-ri --no-document --quiet
mkdir -p ${KIF_SCREENSHOTS}

View File

@@ -4,11 +4,19 @@ set -e
set -o pipefail
set -u
source ./scripts/travis_helper.sh
NAME=MapboxGL
OUTPUT=build/ios/pkg
IOS_SDK_VERSION=`xcrun --sdk iphoneos --show-sdk-version`
LIBUV_VERSION=0.10.28
if [[ ${#} -eq 0 ]]; then
BUILD_FOR_DEVICE=true
else
BUILD_FOR_DEVICE=false
fi
function step { >&2 echo -e "\033[1m\033[36m* $@\033[0m"; }
function finish { >&2 echo -en "\033[0m"; }
trap finish EXIT
@@ -31,33 +39,43 @@ step "Creating build files..."
export MASON_PLATFORM=ios
export BUILDTYPE=${BUILDTYPE:-Release}
export HOST=ios
make Xcode/mbgl
step "Building iOS targets..."
xcodebuild -sdk iphoneos${IOS_SDK_VERSION} \
ARCHS="arm64 armv7 armv7s" \
-project ./build/ios/mbgl.xcodeproj \
-configuration ${BUILDTYPE} \
-target everything \
-jobs `sysctl -n hw.ncpu` | xcpretty -c
make Xcode/ios
if [[ "${BUILD_FOR_DEVICE}" == true ]]; then
step "Building iOS device targets..."
xcodebuild -sdk iphoneos${IOS_SDK_VERSION} \
ARCHS="arm64 armv7 armv7s" \
ONLY_ACTIVE_ARCH=NO \
-project ./build/ios/mbgl.xcodeproj \
-configuration ${BUILDTYPE} \
-target everything \
-jobs ${JOBS} | xcpretty -c
fi
step "Building iOS Simulator targets..."
xcodebuild -sdk iphonesimulator${IOS_SDK_VERSION} \
ARCHS="x86_64 i386" \
ONLY_ACTIVE_ARCH=NO \
-project ./build/ios/mbgl.xcodeproj \
-configuration ${BUILDTYPE} \
-target everything \
-jobs `sysctl -n hw.ncpu` | xcpretty -c
-jobs ${JOBS} | xcpretty -c
step "Building static library..."
LIBS=(core.a platform-ios.a asset-fs.a cache-sqlite.a http-nsurl.a)
libtool -static -no_warning_for_no_symbols \
-o ${OUTPUT}/static/lib${NAME}.a \
${LIBS[@]/#/build/${BUILDTYPE}-iphoneos/libmbgl-} \
${LIBS[@]/#/build/${BUILDTYPE}-iphonesimulator/libmbgl-} \
`find mason_packages/ios-${IOS_SDK_VERSION} -type f -name libuv.a`
if [[ "${BUILD_FOR_DEVICE}" == true ]]; then
libtool -static -no_warning_for_no_symbols \
-o ${OUTPUT}/static/lib${NAME}.a \
${LIBS[@]/#/build/${BUILDTYPE}-iphoneos/libmbgl-} \
${LIBS[@]/#/build/${BUILDTYPE}-iphonesimulator/libmbgl-} \
`find mason_packages/ios-${IOS_SDK_VERSION} -type f -name libuv.a`
else
libtool -static -no_warning_for_no_symbols \
-o ${OUTPUT}/static/lib${NAME}.a \
${LIBS[@]/#/build/${BUILDTYPE}-iphonesimulator/libmbgl-} \
`find mason_packages/ios-${IOS_SDK_VERSION} -type f -name libuv.a`
fi
echo "Created ${OUTPUT}/static/lib${NAME}.a"

35
scripts/ios/run.sh Executable file
View File

@@ -0,0 +1,35 @@
#!/usr/bin/env bash
set -e
set -o pipefail
set -u
BUILDTYPE=${BUILDTYPE:-Release}
source ./scripts/travis_helper.sh
# Add Mason to PATH
export PATH="`pwd`/.mason:${PATH}" MASON_DIR="`pwd`/.mason"
PUBLISH_TAG=($(git show -s --format=%B | sed -n 's/.*\[publish \([a-z]\{1,\}\)-v\([0-9.]\{1,\}\)\].*/\1 \2/p'))
PUBLISH_PLATFORM=${PUBLISH_TAG[0],-}
PUBLISH_VERSION=${PUBLISH_TAG[1],-}
################################################################################
# Build
################################################################################
if [[ ${PUBLISH_PLATFORM} = 'ios' ]]; then
# build & package iOS
mapbox_time "package_ios" \
make ipackage
# publish iOS build
mapbox_time "deploy_ios" \
./scripts/ios/publish.sh "${PUBLISH_VERSION}"
else
# build & test iOS
mapbox_time "run_ios_tests" \
make itest
fi

16
scripts/ios/test.sh Executable file
View File

@@ -0,0 +1,16 @@
#!/usr/bin/env bash
set -e
set -o pipefail
set -u
xcodebuild \
-project ./test/ios/ios-tests.xcodeproj \
-scheme 'Mapbox GL Tests' \
-sdk iphonesimulator \
-destination 'platform=iOS Simulator,name=iPhone 5s,OS=7.1' \
-destination 'platform=iOS Simulator,name=iPhone 5s,OS=latest' \
-destination 'platform=iOS Simulator,name=iPad 2,OS=7.1' \
-destination 'platform=iOS Simulator,name=iPad 2,OS=latest' \
test \
| xcpretty

13
scripts/linux/install.sh Executable file
View File

@@ -0,0 +1,13 @@
#!/usr/bin/env bash
set -e
set -o pipefail
source ./scripts/travis_helper.sh
mapbox_time "checkout_mason" \
git submodule update --init .mason
export PATH="`pwd`/.mason:${PATH}" MASON_DIR="`pwd`/.mason"
mapbox_time "install_mesa" \
mason install mesa 10.4.3

75
scripts/linux/run.sh Executable file
View File

@@ -0,0 +1,75 @@
#!/usr/bin/env bash
set -e
set -o pipefail
BUILDTYPE=${BUILDTYPE:-Release}
source ./scripts/travis_helper.sh
# Add Mason to PATH
export PATH="`pwd`/.mason:${PATH}" MASON_DIR="`pwd`/.mason"
# Set the core file limit to unlimited so a core file is generated upon crash
ulimit -c unlimited -S
################################################################################
# X Server setup
################################################################################
# Start the mock X server
if [ -f /etc/init.d/xvfb ] ; then
mapbox_time "start_xvfb" \
sh -e /etc/init.d/xvfb start
sleep 2 # sometimes, xvfb takes some time to start up
fi
# Make sure we're connecting to xvfb
export DISPLAY=:99.0
# Make sure we're loading the 10.4.3 libs we installed manually
export LD_LIBRARY_PATH="`mason prefix mesa 10.4.3`/lib:${LD_LIBRARY_PATH:-}"
mapbox_time "glxinfo" \
glxinfo
################################################################################
# Build
################################################################################
mapbox_time "checkout_styles" \
git submodule update --init styles
mapbox_time "compile_program" \
make linux -j${JOBS} BUILDTYPE=${BUILDTYPE}
mapbox_time "compile_tests" \
make test -j${JOBS} BUILDTYPE=${BUILDTYPE}
################################################################################
# Test
################################################################################
mapbox_time "checkout_test_suite" \
git submodule update --init test/suite
mapbox_time "run_tests" \
make test-* BUILDTYPE=${BUILDTYPE}
mapbox_time "compare_results" \
./scripts/compare_images.sh
################################################################################
# Deploy
################################################################################
if [ ! -z "${AWS_ACCESS_KEY_ID}" ] && [ ! -z "${AWS_SECRET_ACCESS_KEY}" ] ; then
# Install and add awscli to PATH for uploading the results
mapbox_time "install_awscli" \
pip install --user awscli
export PATH="`python -m site --user-base`/bin:${PATH}"
mapbox_time_start "deploy_results"
(cd ./test/suite/ && ./bin/deploy_results.sh)
mapbox_time_finish
fi

View File

@@ -1,5 +0,0 @@
#!/usr/bin/env bash
git submodule update --init .mason
PATH=`pwd`/.mason:$PATH
export MASON_DIR=`pwd`/.mason

View File

@@ -1,8 +0,0 @@
#!/usr/bin/env bash
set -e
set -o pipefail
cd bin
$1 install --clang=1
cd ../

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