diff --git a/.gitmodules b/.gitmodules index 9e5265a6a..6a4b1d516 100644 --- a/.gitmodules +++ b/.gitmodules @@ -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 diff --git a/.travis.yml b/.travis.yml index 690b2b1b6..71936b872 100644 --- a/.travis.yml +++ b/.travis.yml @@ -57,6 +57,7 @@ env: - IOS_PROFILE_NAME="ios-in-house" - secure: "nQqSM8rd7OHtV4MqmNqVnkrVHqxKqQsaWRYk4/nPdhbeVWtTtkk0df711LrF1TUtbEPEewHxYUvTZ/UXmwJNeoKdzTHavI8hnatRkgjyxGERPn1il1Otelht9I+LQQHf+plrpRjVWBrNIW0Zox1B3cqn6d3NglpbXrEQ2EjYGNA=" # end iOS code signing + - KIF_SCREENSHOTS="${TRAVIS_BUILD_DIR}/screenshots" before_install: - if [[ ${TRAVIS_OS_NAME} == "linux" ]]; then sudo service mysql stop; fi @@ -68,6 +69,7 @@ before_install: - ./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 +- if [[ ${TRAVIS_OS_NAME} == "osx" && ${TEST_OS} == "ios" ]]; then mkdir -p ${KIF_SCREENSHOTS}; fi install: - ulimit -c @@ -88,6 +90,9 @@ script: after_script: - ./scripts/ios_travis/remove-key.sh +after_failure: +- if [[ ${TRAVIS_OS_NAME} == "osx" && ${TEST_OS} == "ios" ]]; then ./scripts/ios_travis/upload_screenshots.sh; fi + notifications: slack: secure: HHQYr7sF8M1SzoWSqgKVYtwAgGdLLCyTMsQjFhEEQNYO92ZwURE5s03qWTGH5k8+4Yqn26yrXt3NztLC4JIOpcGervN2mSZyq4dZgFTcWEd61igw0qwSenlwvFfbE1ASK/KYCzfyn9MIfHN+ovwLoRxXZkPwinKDvl3DXjBaFNg= diff --git a/Makefile b/Makefile index 14f78ed0f..11eb5e530 100644 --- a/Makefile +++ b/Makefile @@ -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 sysctl -n hw.ncpu) +endif + JOBS ?= 1 all: mbgl @@ -29,49 +34,45 @@ styles/styles: SMCalloutView: git submodule update --init platform/ios/vendor/SMCalloutView +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/project.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/project.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: Xcode/project + xcodebuild -project ./build/osx/gyp/project.xcodeproj -configuration $(BUILDTYPE) -target test -jobs $(JOBS) xtest-%: xtest ./scripts/run_tests.sh "build/osx/Build/Products/$(BUILDTYPE)/test" --gtest_filter=$* @@ -79,31 +80,22 @@ 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/project.xcodeproj -xosx: Xcode/osx - xcodebuild -project ./build/osx/macosx/mapboxgl-app.xcodeproj -configuration $(BUILDTYPE) -target osxapp -jobs $(JOBS) +xosx: Xcode/project + xcodebuild -project ./build/osx/gyp/project.xcodeproj -configuration $(BUILDTYPE) -target osxapp -jobs $(JOBS) 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 @@ -129,40 +121,28 @@ isim: Xcode/ios ipackage: clean Xcode/ios ./scripts/package_ios.sh +itest: ipackage KIF + ./scripts/test_ios.sh + # Legacy name 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: Xcode/project + xcodebuild -project ./build/osx/gyp/project.xcodeproj -configuration $(BUILDTYPE) -target linuxapp -jobs $(JOBS) run-xlinux: xlinux - "build/osx/Build/Products/$(BUILDTYPE)/mapbox-gl" - -# Legacy name -lproj: xlinux-proj + "gyp/build/$(BUILDTYPE)/mapbox-gl" #### Android libaries ######################################################### @@ -194,22 +174,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/project.xcodeproj -configuration $(BUILDTYPE) -target mbgl-render -jobs $(JOBS) ##### Maintenace operations #################################################### diff --git a/README.md b/README.md index c423c21b5..a44b13861 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,8 @@ If you merely want to install the library for iOS and try it out as an Objective 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. +You can also run `make itest` to run the included tests. Requires `brew install xcpretty`. + 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 diff --git a/bin/render.gyp b/bin/render.gypi similarity index 100% rename from bin/render.gyp rename to bin/render.gypi diff --git a/gyp/project.gyp b/gyp/project.gyp new file mode 100644 index 000000000..9f53eef51 --- /dev/null +++ b/gyp/project.gyp @@ -0,0 +1,19 @@ +{ + 'conditions': [ + ['host == "osx"', { + 'includes': [ + '../macosx/mapboxgl-app.gypi', + '../linux/mapboxgl-app.gypi', + '../test/test.gypi', + '../bin/render.gypi', + ] + }], + ['host == "linux"', { + 'includes': [ + '../linux/mapboxgl-app.gypi', + '../test/test.gypi', + '../bin/render.gypi', + ] + }], + ], +} diff --git a/include/mbgl/ios/MGLMapboxEvents.h b/include/mbgl/ios/MGLMapboxEvents.h index 7a4c45fe1..c6cd13308 100644 --- a/include/mbgl/ios/MGLMapboxEvents.h +++ b/include/mbgl/ios/MGLMapboxEvents.h @@ -32,6 +32,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; diff --git a/include/mbgl/util/math.hpp b/include/mbgl/util/math.hpp index 647fa5e67..6dea628e9 100644 --- a/include/mbgl/util/math.hpp +++ b/include/mbgl/util/math.hpp @@ -74,6 +74,11 @@ inline vec2 normal(const S1& a, const S2& b) { return { dx / c, dy / c }; } +template +inline T perp(const T& a) { + return T(-a.y, a.x); +} + template 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 +inline S unit(const S& a) { + return a * (1 / mag(a)); +} + template T clamp(T value, T min, T max) { return value < min ? min : (value > max ? max : value); diff --git a/include/mbgl/util/vec.hpp b/include/mbgl/util/vec.hpp index 32de85275..052dffcfa 100644 --- a/include/mbgl/util/vec.hpp +++ b/include/mbgl/util/vec.hpp @@ -61,7 +61,13 @@ struct vec2 { template inline typename std::enable_if::value, vec2>::type operator-(const O &o) const { - return {x - o.x, y - o.y}; + return vec2(x - o.x, y - o.y); + } + + template + inline typename std::enable_if::value, vec2>::type + operator+(const O &o) const { + return vec2(x + o.x, y + o.y); } template diff --git a/ios/MapboxGL.podspec b/ios/MapboxGL.podspec index 29e406362..57de3f6f3 100644 --- a/ios/MapboxGL.podspec +++ b/ios/MapboxGL.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |m| m.name = 'MapboxGL' - m.version = '0.2.14' + m.version = '0.2.15' 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.' diff --git a/ios/app/app-info.plist b/ios/app/app-info.plist index cd74f5839..fd03e7324 100644 --- a/ios/app/app-info.plist +++ b/ios/app/app-info.plist @@ -21,7 +21,7 @@ CFBundleSignature MBGL CFBundleVersion - 0.0.2 + 0.0.3 LSRequiresIPhoneOS NSHumanReadableCopyright diff --git a/linux/mapboxgl-app.gyp b/linux/mapboxgl-app.gypi similarity index 100% rename from linux/mapboxgl-app.gyp rename to linux/mapboxgl-app.gypi diff --git a/macosx/mapboxgl-app.gyp b/macosx/mapboxgl-app.gypi similarity index 96% rename from macosx/mapboxgl-app.gyp rename to macosx/mapboxgl-app.gypi index 9817f9d97..381795404 100644 --- a/macosx/mapboxgl-app.gyp +++ b/macosx/mapboxgl-app.gypi @@ -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' }, } diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm index 5f5e99b0e..b61679a7d 100644 --- a/platform/ios/MGLMapView.mm +++ b/platform/ios/MGLMapView.mm @@ -223,8 +223,10 @@ mbgl::DefaultFileSource *mbglFileSource = nullptr; // metrics: initial setup NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"]; NSString *appVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; + NSString *appBuildNumber = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]; if (appName != nil) [MGLMapboxEvents setAppName:appName]; if (appVersion != nil) [MGLMapboxEvents setAppVersion:appVersion]; + if (appBuildNumber != nil) [MGLMapboxEvents setAppBuildNumber:appBuildNumber]; // create GL view // @@ -242,7 +244,8 @@ mbgl::DefaultFileSource *mbglFileSource = nullptr; _glView.contentMode = UIViewContentModeCenter; - [self setBackgroundColor:[UIColor clearColor]]; + self.backgroundColor = [UIColor clearColor]; + self.clipsToBounds = YES; // load extensions // @@ -293,9 +296,9 @@ mbgl::DefaultFileSource *mbglFileSource = nullptr; // setup logo bug // - _logoBug = [[UIImageView alloc] initWithImage:[MGLMapView resourceImageNamed:@"mapbox.png"]]; + UIImage *logo = [[MGLMapView resourceImageNamed:@"mapbox.png"] imageWithAlignmentRectInsets:UIEdgeInsetsMake(1.5, 4, 3.5, 2)]; + _logoBug = [[UIImageView alloc] initWithImage:logo]; _logoBug.accessibilityLabel = @"Mapbox logo"; - _logoBug.frame = CGRectMake(8, self.bounds.size.height - _logoBug.bounds.size.height - 4, _logoBug.bounds.size.width, _logoBug.bounds.size.height); _logoBug.translatesAutoresizingMaskIntoConstraints = NO; [self addSubview:_logoBug]; @@ -304,7 +307,6 @@ mbgl::DefaultFileSource *mbglFileSource = nullptr; _attributionButton = [UIButton buttonWithType:UIButtonTypeInfoLight]; _attributionButton.accessibilityLabel = @"Attribution info"; [_attributionButton addTarget:self action:@selector(showAttribution:) forControlEvents:UIControlEventTouchUpInside]; - _attributionButton.frame = CGRectMake(self.bounds.size.width - _attributionButton.bounds.size.width - 8, self.bounds.size.height - _attributionButton.bounds.size.height - 8, _attributionButton.bounds.size.width, _attributionButton.bounds.size.height); _attributionButton.translatesAutoresizingMaskIntoConstraints = NO; [self addSubview:_attributionButton]; @@ -315,7 +317,7 @@ mbgl::DefaultFileSource *mbglFileSource = nullptr; UIImage *compassImage = [MGLMapView resourceImageNamed:@"Compass.png"]; _compass.frame = CGRectMake(0, 0, compassImage.size.width, compassImage.size.height); _compass.alpha = 0; - UIView *container = [[UIView alloc] initWithFrame:CGRectMake(self.bounds.size.width - compassImage.size.width - 5, 5, compassImage.size.width, compassImage.size.height)]; + UIView *container = [[UIView alloc] initWithFrame:CGRectZero]; [container addSubview:_compass]; container.translatesAutoresizingMaskIntoConstraints = NO; [container addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleCompassTapGesture:)]]; @@ -491,70 +493,122 @@ mbgl::DefaultFileSource *mbglFileSource = nullptr; // views so they don't underlap navigation or tool bars. If we don't have a reference, apply // constraints against ourself to maintain (albeit less ideal) placement of the subviews. // - NSString *topGuideFormatString = (self.viewControllerForLayoutGuides ? @"[topLayoutGuide]" : @"|"); - NSString *bottomGuideFormatString = (self.viewControllerForLayoutGuides ? @"[bottomLayoutGuide]" : @"|"); - - id topGuideViewsObject = (self.viewControllerForLayoutGuides ? (id)self.viewControllerForLayoutGuides.topLayoutGuide : (id)@""); - id bottomGuideViewsObject = (self.viewControllerForLayoutGuides ? (id)self.viewControllerForLayoutGuides.bottomLayoutGuide : (id)@""); - - UIView *constraintParentView = (self.viewControllerForLayoutGuides.view ? self.viewControllerForLayoutGuides.view : self); + UIView *constraintParentView = (self.viewControllerForLayoutGuides.view ? + self.viewControllerForLayoutGuides.view : + self); // compass // UIView *compassContainer = self.compass.superview; - [constraintParentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"V:%@-topSpacing-[container]", topGuideFormatString] - options:0 - metrics:@{ @"topSpacing" : @(5) } - views:@{ @"topLayoutGuide" : topGuideViewsObject, - @"container" : compassContainer }]]; + if (self.viewControllerForLayoutGuides) + { + [constraintParentView addConstraint: + [NSLayoutConstraint constraintWithItem:compassContainer + attribute:NSLayoutAttributeTop + relatedBy:NSLayoutRelationGreaterThanOrEqual + toItem:self.viewControllerForLayoutGuides.topLayoutGuide + attribute:NSLayoutAttributeBottom + multiplier:1 + constant:5]]; + } + [constraintParentView addConstraint: + [NSLayoutConstraint constraintWithItem:compassContainer + attribute:NSLayoutAttributeTop + relatedBy:NSLayoutRelationGreaterThanOrEqual + toItem:self + attribute:NSLayoutAttributeTop + multiplier:1 + constant:5]]; - [constraintParentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[container]-rightSpacing-|" - options:0 - metrics:@{ @"rightSpacing" : @(5) } - views:@{ @"container" : compassContainer }]]; + [constraintParentView addConstraint: + [NSLayoutConstraint constraintWithItem:self + attribute:NSLayoutAttributeTrailing + relatedBy:NSLayoutRelationEqual + toItem:compassContainer + attribute:NSLayoutAttributeTrailing + multiplier:1 + constant:5]]; - [compassContainer addConstraint:[NSLayoutConstraint constraintWithItem:compassContainer - attribute:NSLayoutAttributeWidth - relatedBy:NSLayoutRelationEqual - toItem:nil - attribute:NSLayoutAttributeNotAnAttribute - multiplier:1 - constant:self.compass.image.size.width]]; + [compassContainer addConstraint: + [NSLayoutConstraint constraintWithItem:compassContainer + attribute:NSLayoutAttributeWidth + relatedBy:NSLayoutRelationEqual + toItem:nil + attribute:NSLayoutAttributeNotAnAttribute + multiplier:1 + constant:self.compass.image.size.width]]; - [compassContainer addConstraint:[NSLayoutConstraint constraintWithItem:compassContainer - attribute:NSLayoutAttributeHeight - relatedBy:NSLayoutRelationEqual - toItem:nil - attribute:NSLayoutAttributeNotAnAttribute - multiplier:1 - constant:self.compass.image.size.height]]; + [compassContainer addConstraint: + [NSLayoutConstraint constraintWithItem:compassContainer + attribute:NSLayoutAttributeHeight + relatedBy:NSLayoutRelationEqual + toItem:nil + attribute:NSLayoutAttributeNotAnAttribute + multiplier:1 + constant:self.compass.image.size.height]]; // logo bug // - [constraintParentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"V:[logoBug]-bottomSpacing-%@", bottomGuideFormatString] - options:0 - metrics:@{ @"bottomSpacing" : @(4) } - views:@{ @"logoBug" : self.logoBug, - @"bottomLayoutGuide" : bottomGuideViewsObject }]]; + if (self.viewControllerForLayoutGuides) + { + [constraintParentView addConstraint: + [NSLayoutConstraint constraintWithItem:self.viewControllerForLayoutGuides.bottomLayoutGuide + attribute:NSLayoutAttributeTop + relatedBy:NSLayoutRelationGreaterThanOrEqual + toItem:self.logoBug + attribute:NSLayoutAttributeBaseline + multiplier:1 + constant:8]]; + } + [constraintParentView addConstraint: + [NSLayoutConstraint constraintWithItem:self + attribute:NSLayoutAttributeBottom + relatedBy:NSLayoutRelationGreaterThanOrEqual + toItem:self.logoBug + attribute:NSLayoutAttributeBaseline + multiplier:1 + constant:8]]; - [constraintParentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-leftSpacing-[logoBug]" - options:0 - metrics:@{ @"leftSpacing" : @(8) } - views:@{ @"logoBug" : self.logoBug }]]; + [constraintParentView addConstraint: + [NSLayoutConstraint constraintWithItem:self.logoBug + attribute:NSLayoutAttributeLeading + relatedBy:NSLayoutRelationEqual + toItem:self + attribute:NSLayoutAttributeLeading + multiplier:1 + constant:8]]; // attribution button // - [constraintParentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:@"V:[attributionButton]-bottomSpacing-%@", bottomGuideFormatString] - options:0 - metrics:@{ @"bottomSpacing" : @(8) } - views:@{ @"attributionButton" : self.attributionButton, - @"bottomLayoutGuide" : bottomGuideViewsObject }]]; + if (self.viewControllerForLayoutGuides) + { + [constraintParentView addConstraint: + [NSLayoutConstraint constraintWithItem:self.viewControllerForLayoutGuides.bottomLayoutGuide + attribute:NSLayoutAttributeTop + relatedBy:NSLayoutRelationGreaterThanOrEqual + toItem:self.attributionButton + attribute:NSLayoutAttributeBaseline + multiplier:1 + constant:8]]; + } + [constraintParentView addConstraint: + [NSLayoutConstraint constraintWithItem:self + attribute:NSLayoutAttributeBottom + relatedBy:NSLayoutRelationGreaterThanOrEqual + toItem:self.attributionButton + attribute:NSLayoutAttributeBaseline + multiplier:1 + constant:8]]; - [constraintParentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[attributionButton]-rightSpacing-|" - options:0 - metrics:@{ @"rightSpacing" : @(8) } - views:@{ @"attributionButton" : self.attributionButton }]]; + [constraintParentView addConstraint: + [NSLayoutConstraint constraintWithItem:self + attribute:NSLayoutAttributeTrailing + relatedBy:NSLayoutRelationEqual + toItem:self.attributionButton + attribute:NSLayoutAttributeTrailing + multiplier:1 + constant:8]]; [super updateConstraints]; } @@ -1151,12 +1205,6 @@ mbgl::DefaultFileSource *mbglFileSource = nullptr; if (finished) { [self notifyMapChange:@(animated ? mbgl::MapChangeRegionDidChangeAnimated : mbgl::MapChangeRegionDidChange)]; - - [UIView animateWithDuration:MGLAnimationDuration - animations:^ - { - self.compass.alpha = 0; - }]; } }]; } @@ -2255,6 +2303,17 @@ CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng) } completion:nil]; } + else if (mbglMap->getBearing() == 0 && self.compass.alpha > 0) + { + [UIView animateWithDuration:MGLAnimationDuration + delay:0 + options:UIViewAnimationOptionBeginFromCurrentState + animations:^ + { + self.compass.alpha = 0; + } + completion:nil]; + } } + (UIImage *)resourceImageNamed:(NSString *)imageName diff --git a/platform/ios/MGLMapboxEvents.m b/platform/ios/MGLMapboxEvents.m index c4bd7cf0b..fa2a27f78 100644 --- a/platform/ios/MGLMapboxEvents.m +++ b/platform/ios/MGLMapboxEvents.m @@ -50,7 +50,7 @@ NSString *const MGLEventGestureRotateStart = @"Rotation"; // from within a single thread use underscore syntax. // // All captures of `self` from within asynchronous -// dispatches will use a `weakSelf` to avoid cyclical +// dispatches will use a `strongSelf` to avoid cyclical // strong references. // @@ -62,6 +62,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,6 +75,7 @@ NSString *const MGLEventGestureRotateStart = @"Rotation"; @property (atomic) NSDateFormatter *rfc3339DateFormatter; @property (atomic) CGFloat scale; @property (atomic) NSURLSession *session; +@property (atomic) NSData *digicertCert; @property (atomic) NSData *geoTrustCert; @@ -111,13 +113,13 @@ NSString *const MGLEventGestureRotateStart = @"Rotation"; 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) { @@ -140,18 +142,17 @@ NSString *const MGLEventGestureRotateStart = @"Rotation"; // 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 = [[NSBundle bundleForClass:[MGLMapboxEvents class]] pathForResource:@"api_mapbox_com-geotrust" ofType:@"der"]; if (cerPath != nil) { _geoTrustCert = [NSData dataWithContentsOfFile:cerPath]; } + cerPath = nil; + cerPath = [[NSBundle bundleForClass:[MGLMapboxEvents class]] pathForResource:@"api_mapbox_com-digicert" ofType:@"der"]; + if (cerPath != nil) { + _digicertCert = [NSData dataWithContentsOfFile:cerPath]; + } + // Events Control _eventQueue = [[NSMutableArray alloc] init]; _flushAt = 20; @@ -254,6 +255,13 @@ NSString *const MGLEventGestureRotateStart = @"Rotation"; [MGLMapboxEvents sharedManager].appVersion = appVersion; } +// Must be called from the main thread. +// ++ (void) setAppBuildNumber:(NSString *)appBuildNumber { + assert([[NSThread currentThread] isMainThread]); + [MGLMapboxEvents sharedManager].appBuildNumber = appBuildNumber; +} + // Must be called from the main thread. // + (void) pauseMetricsCollection { @@ -292,6 +300,9 @@ NSString *const MGLEventGestureRotateStart = @"Rotation"; __weak MGLMapboxEvents *weakSelf = self; dispatch_async(_serialQueue, ^{ + MGLMapboxEvents *strongSelf = weakSelf; + if ( ! strongSelf) return; + // Opt Out Checking When Built if (![[NSUserDefaults standardUserDefaults] boolForKey:@"mapbox_metrics_enabled_preference"]) { [_eventQueue removeAllObjects]; @@ -315,35 +326,35 @@ NSString *const MGLEventGestureRotateStart = @"Rotation"; // mapbox-events stock attributes [evt setObject:event forKey:@"event"]; [evt setObject:@(1) forKey:@"version"]; - [evt setObject:[weakSelf.rfc3339DateFormatter stringFromDate:[NSDate date]] forKey:@"created"]; - [evt setObject:weakSelf.instanceID forKey:@"instance"]; - [evt setObject:weakSelf.advertiserId forKey:@"advertiserId"]; - [evt setObject:weakSelf.vendorId forKey:@"vendorId"]; - [evt setObject:weakSelf.appBundleId forKeyedSubscript:@"appBundleId"]; + [evt setObject:[strongSelf.rfc3339DateFormatter stringFromDate:[NSDate date]] forKey:@"created"]; + [evt setObject:strongSelf.instanceID forKey:@"instance"]; + [evt setObject:strongSelf.advertiserId forKey:@"advertiserId"]; + [evt setObject:strongSelf.vendorId forKey:@"vendorId"]; + [evt setObject:strongSelf.appBundleId forKeyedSubscript:@"appBundleId"]; // mapbox-events-ios stock attributes - [evt setValue:weakSelf.model forKey:@"model"]; - [evt setValue:weakSelf.iOSVersion forKey:@"operatingSystem"]; - [evt setValue:[weakSelf getDeviceOrientation] forKey:@"orientation"]; + [evt setValue:strongSelf.model forKey:@"model"]; + [evt setValue:strongSelf.iOSVersion forKey:@"operatingSystem"]; + [evt setValue:[strongSelf getDeviceOrientation] forKey:@"orientation"]; [evt setValue:@((int)(100 * [UIDevice currentDevice].batteryLevel)) forKey:@"batteryLevel"]; - [evt setValue:@(weakSelf.scale) forKey:@"resolution"]; - [evt setValue:weakSelf.carrier forKey:@"carrier"]; + [evt setValue:@(strongSelf.scale) forKey:@"resolution"]; + [evt setValue:strongSelf.carrier forKey:@"carrier"]; - NSString *cell = [weakSelf getCurrentCellularNetworkConnectionType]; + NSString *cell = [strongSelf getCurrentCellularNetworkConnectionType]; if (cell) { [evt setValue:cell forKey:@"cellularNetworkType"]; } else { [evt setObject:[NSNull null] forKey:@"cellularNetworkType"]; } - NSString *wifi = [weakSelf getWifiNetworkName]; + NSString *wifi = [strongSelf getWifiNetworkName]; if (wifi) { [evt setValue:wifi forKey:@"wifi"]; } else { [evt setObject:[NSNull null] forKey:@"wifi"]; } - [evt setValue:@([weakSelf getContentSizeScale]) forKey:@"accessibilityFontScale"]; + [evt setValue:@([strongSelf getContentSizeScale]) forKey:@"accessibilityFontScale"]; // Make Immutable Version NSDictionary *finalEvent = [NSDictionary dictionaryWithDictionary:evt]; @@ -352,12 +363,12 @@ NSString *const MGLEventGestureRotateStart = @"Rotation"; [_eventQueue addObject:finalEvent]; // Has Flush Limit Been Reached? - if (_eventQueue.count >= weakSelf.flushAt) { - [weakSelf flush]; + if (_eventQueue.count >= strongSelf.flushAt) { + [strongSelf flush]; } // Reset Timer (Initial Starting of Timer after first event is pushed) - [weakSelf startTimer]; + [strongSelf startTimer]; }); } @@ -375,10 +386,13 @@ NSString *const MGLEventGestureRotateStart = @"Rotation"; __weak MGLMapboxEvents *weakSelf = self; dispatch_async(_serialQueue, ^{ + MGLMapboxEvents *strongSelf = weakSelf; + if ( ! strongSelf) return; + __block NSArray *events; - NSUInteger upper = weakSelf.flushAt; - if (weakSelf.flushAt > [_eventQueue count]) { + NSUInteger upper = strongSelf.flushAt; + if (strongSelf.flushAt > [_eventQueue count]) { if ([_eventQueue count] == 0) { return; } @@ -393,7 +407,7 @@ NSString *const MGLEventGestureRotateStart = @"Rotation"; [_eventQueue removeObjectsInRange:theRange]; // Send Array of Events to Server - [weakSelf postEvents:events]; + [strongSelf postEvents:events]; }); } @@ -456,8 +470,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; } @@ -680,6 +694,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)); @@ -694,8 +709,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 diff --git a/platform/ios/MGLUserLocationAnnotationView.m b/platform/ios/MGLUserLocationAnnotationView.m index 779382b5e..c130582d6 100644 --- a/platform/ios/MGLUserLocationAnnotationView.m +++ b/platform/ios/MGLUserLocationAnnotationView.m @@ -30,6 +30,7 @@ const CGFloat MGLTrackingDotRingWidth = 24.0; self.annotation.mapView = mapView; _mapView = mapView; [self setupLayers]; + self.accessibilityLabel = @"User location"; } return self; } diff --git a/platform/ios/resources/api_mapbox_com-digicert.der b/platform/ios/resources/api_mapbox_com-digicert.der new file mode 100644 index 000000000..d84cee390 Binary files /dev/null and b/platform/ios/resources/api_mapbox_com-digicert.der differ diff --git a/scripts/build-version.py b/scripts/build-version.py index 3fe789185..0110e6a2e 100755 --- a/scripts/build-version.py +++ b/scripts/build-version.py @@ -13,9 +13,9 @@ else: if sys.argv[2] == sys.argv[3]: tag = [0, 0, 0] else: - ver = re.sub("[^0-9.]", "", sys.argv[2]) + ver = re.sub("[^0-9.]", "", sys.argv[2]) tag = map(int, ver.split('.')) - rev = sys.argv[3][0:8] + rev = sys.argv[3][0:8] def mkdir_p(path): diff --git a/scripts/ios_travis/upload_screenshots.sh b/scripts/ios_travis/upload_screenshots.sh new file mode 100755 index 000000000..88a6427f7 --- /dev/null +++ b/scripts/ios_travis/upload_screenshots.sh @@ -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 diff --git a/scripts/package_ios.sh b/scripts/package_ios.sh index da55b297a..07e568faa 100755 --- a/scripts/package_ios.sh +++ b/scripts/package_ios.sh @@ -31,11 +31,12 @@ step "Creating build files..." export MASON_PLATFORM=ios export BUILDTYPE=${BUILDTYPE:-Release} export HOST=ios -make Xcode/mbgl +make Xcode/ios -step "Building iOS targets..." +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 \ @@ -45,6 +46,7 @@ xcodebuild -sdk iphoneos${IOS_SDK_VERSION} \ 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 \ diff --git a/scripts/test_ios.sh b/scripts/test_ios.sh new file mode 100755 index 000000000..77d4d90ad --- /dev/null +++ b/scripts/test_ios.sh @@ -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 diff --git a/scripts/travis_script.sh b/scripts/travis_script.sh index 0351f9414..093b31273 100755 --- a/scripts/travis_script.sh +++ b/scripts/travis_script.sh @@ -48,15 +48,24 @@ elif [[ ${TRAVIS_OS_NAME} == "osx" && ${MASON_PLATFORM} == "osx" ]]; then elif [[ ${TRAVIS_OS_NAME} == "osx" && ${MASON_PLATFORM} == "ios" ]]; then # - # build & package iOS - # - mapbox_time "package_ios" - make ipackage - # - # conditionally deploy iOS build + # conditionally publish or test # if [[ -n "$PUBLISH_TAG" ]]; then + # + # build & package iOS + # + mapbox_time "package_ios" + make ipackage + # + # publish iOS build + # mapbox_time "deploy_ios" ./scripts/publish_ios.sh "$PUBLISH_VERSION" + else + # + # build & test iOS + # + mapbox_time "run_ios_tests" + make itest fi fi diff --git a/src/mbgl/geometry/elements_buffer.cpp b/src/mbgl/geometry/elements_buffer.cpp index 79af1b7e3..3e2e2794d 100644 --- a/src/mbgl/geometry/elements_buffer.cpp +++ b/src/mbgl/geometry/elements_buffer.cpp @@ -14,8 +14,3 @@ void LineElementsBuffer::add(element_type a, element_type b) { elements[0] = a; elements[1] = b; } - -void PointElementsBuffer::add(element_type a) { - uint16_t *data = static_cast(addElement()); - data[0] = a; -} diff --git a/src/mbgl/geometry/elements_buffer.hpp b/src/mbgl/geometry/elements_buffer.hpp index 5c1b421d3..24753ebaf 100644 --- a/src/mbgl/geometry/elements_buffer.hpp +++ b/src/mbgl/geometry/elements_buffer.hpp @@ -44,16 +44,6 @@ public: void add(element_type a, element_type b); }; -class PointElementsBuffer : public Buffer< - 2, // bytes per point (1 unsigned short) - GL_ELEMENT_ARRAY_BUFFER -> { -public: - typedef uint16_t element_type; - - void add(element_type a); -}; - } #endif diff --git a/src/mbgl/map/source.cpp b/src/mbgl/map/source.cpp index 3245bab2e..9e318964b 100644 --- a/src/mbgl/map/source.cpp +++ b/src/mbgl/map/source.cpp @@ -245,7 +245,7 @@ TileData::State Source::addTile(Map &map, Worker &worker, } if (!new_tile.data) { - new_tile.data = cache.get(id.to_uint64()); + new_tile.data = cache.get(normalized_id.to_uint64()); } if (!new_tile.data) { @@ -418,7 +418,7 @@ void Source::update(Map &map, if (!obsolete) { retain_data.insert(tile.data->id); } else if (type != SourceType::Raster && tile.data->ready()) { - tileCache.add(tile.id.to_uint64(), tile.data); + tileCache.add(tile.id.normalized().to_uint64(), tile.data); } return obsolete; }); @@ -432,7 +432,7 @@ void Source::update(Map &map, bool obsolete = retain_data.find(tile->id) == retain_data.end(); if (obsolete) { - if (!tileCache.has(tile->id.to_uint64())) { + if (!tileCache.has(tile->id.normalized().to_uint64())) { tile->cancel(); } return true; diff --git a/src/mbgl/map/tile_cache.cpp b/src/mbgl/map/tile_cache.cpp index b64c8e2a6..25aed6d15 100644 --- a/src/mbgl/map/tile_cache.cpp +++ b/src/mbgl/map/tile_cache.cpp @@ -20,11 +20,16 @@ void TileCache::setSize(size_t size_) { void TileCache::add(uint64_t key, std::shared_ptr data) { - assert(tiles.find(key) == tiles.end()); + // insert new or query existing data + if (tiles.emplace(key, data).second) { + // remove existing data key + orderedKeys.remove(key); + } - tiles.emplace(key, data); + // (re-)insert data key as newest orderedKeys.push_back(key); + // purge oldest key/data if necessary if (orderedKeys.size() > size) { get(orderedKeys.front()); } diff --git a/src/mbgl/map/tile_parser.cpp b/src/mbgl/map/tile_parser.cpp index 275b77be9..d0d17aaf3 100644 --- a/src/mbgl/map/tile_parser.cpp +++ b/src/mbgl/map/tile_parser.cpp @@ -172,8 +172,7 @@ std::unique_ptr TileParser::createFillBucket(const GeometryTileLayer& la std::unique_ptr TileParser::createLineBucket(const GeometryTileLayer& layer, const StyleBucket& bucket_desc) { auto bucket = util::make_unique(tile.lineVertexBuffer, - tile.triangleElementsBuffer, - tile.pointElementsBuffer); + tile.triangleElementsBuffer); const float z = tile.id.z; auto& layout = bucket->layout; diff --git a/src/mbgl/map/vector_tile_data.hpp b/src/mbgl/map/vector_tile_data.hpp index 4e2f252f8..e87978c24 100644 --- a/src/mbgl/map/vector_tile_data.hpp +++ b/src/mbgl/map/vector_tile_data.hpp @@ -50,7 +50,6 @@ protected: TriangleElementsBuffer triangleElementsBuffer; LineElementsBuffer lineElementsBuffer; - PointElementsBuffer pointElementsBuffer; // Holds the buckets of this tile. // They contain the location offsets in the buffers stored above diff --git a/src/mbgl/renderer/line_bucket.cpp b/src/mbgl/renderer/line_bucket.cpp index 4e09b7464..78da158f1 100644 --- a/src/mbgl/renderer/line_bucket.cpp +++ b/src/mbgl/renderer/line_bucket.cpp @@ -8,34 +8,25 @@ #include #include -#define BUFFER_OFFSET(i) ((char *)nullptr + (i)) +#ifndef BUFFER_OFFSET +#define BUFFER_OFFSET(i) ((char*)nullptr + (i)) +#endif #include using namespace mbgl; -LineBucket::LineBucket(LineVertexBuffer &vertexBuffer_, - TriangleElementsBuffer &triangleElementsBuffer_, - PointElementsBuffer &pointElementsBuffer_) +LineBucket::LineBucket(LineVertexBuffer& vertexBuffer_, + TriangleElementsBuffer& triangleElementsBuffer_) : vertexBuffer(vertexBuffer_), triangleElementsBuffer(triangleElementsBuffer_), - pointElementsBuffer(pointElementsBuffer_), vertex_start(vertexBuffer_.index()), - triangle_elements_start(triangleElementsBuffer_.index()), - point_elements_start(pointElementsBuffer_.index()) { -} + triangle_elements_start(triangleElementsBuffer_.index()){}; LineBucket::~LineBucket() { // Do not remove. header file only contains forward definitions to unique pointers. } -struct TriangleElement { - TriangleElement(uint16_t a_, uint16_t b_, uint16_t c_) : a(a_), b(b_), c(c_) {} - uint16_t a, b, c; -}; - -typedef uint16_t PointElement; - void LineBucket::addGeometry(const GeometryCollection& geometryCollection) { for (auto& line : geometryCollection) { addGeometry(line); @@ -43,366 +34,365 @@ void LineBucket::addGeometry(const GeometryCollection& geometryCollection) { } void LineBucket::addGeometry(const std::vector& vertices) { - // TODO: use roundLimit - // const float roundLimit = geometry.round_limit; + const auto len = [&vertices] { + auto l = vertices.size(); + // If the line has duplicate vertices at the end, adjust length to remove them. + while (l > 2 && vertices[l - 1] == vertices[l - 2]) { + l--; + } + return l; + }(); - if (vertices.size() < 2) { + if (len < 2) { // fprintf(stderr, "a line must have at least two vertices\n"); return; } - Coordinate firstVertex = vertices.front(); - Coordinate lastVertex = vertices.back(); - bool closed = firstVertex.x == lastVertex.x && firstVertex.y == lastVertex.y; + const float miterLimit = layout.join == JoinType::Bevel ? 1.05f : layout.miter_limit; - if (vertices.size() == 2 && closed) { + const Coordinate firstVertex = vertices.front(); + const Coordinate lastVertex = vertices[len - 1]; + const bool closed = firstVertex == lastVertex; + + if (len == 2 && closed) { // fprintf(stderr, "a line may not have coincident points\n"); return; } - CapType beginCap = layout.cap; - CapType endCap = closed ? CapType::Butt : layout.cap; - - JoinType currentJoin = JoinType::Miter; - - Coordinate currentVertex = Coordinate::null(), - prevVertex = Coordinate::null(), - nextVertex = Coordinate::null(); - vec2 prevNormal = vec2::null(), - nextNormal = vec2::null(); - - int32_t e1 = -1, e2 = -1, e3 = -1; + const CapType beginCap = layout.cap; + const CapType endCap = closed ? CapType::Butt : layout.cap; int8_t flip = 1; double distance = 0; + bool startOfLine = true; + Coordinate currentVertex = Coordinate::null(), prevVertex = Coordinate::null(), + nextVertex = Coordinate::null(); + vec2 prevNormal = vec2::null(), nextNormal = vec2::null(); + + // the last three vertices added + e1 = e2 = e3 = -1; if (closed) { - currentVertex = vertices[vertices.size() - 2]; - nextNormal = util::normal(currentVertex, lastVertex); + currentVertex = vertices[len - 2]; + nextNormal = util::perp(util::unit(vec2(firstVertex - currentVertex))); } - int32_t start_vertex = (int32_t)vertexBuffer.index(); + const int32_t startVertex = (int32_t)vertexBuffer.index(); + std::vector triangleStore; - std::vector triangle_store; - std::vector point_store; - - for (size_t i = 0; i < vertices.size(); ++i) { - if (nextNormal) prevNormal = { -nextNormal.x, -nextNormal.y }; - if (currentVertex) prevVertex = currentVertex; - - currentVertex = vertices[i]; - currentJoin = layout.join; - - if (prevVertex) distance += util::dist(currentVertex, prevVertex); - - // Find the next vertex. - if (i + 1 < vertices.size()) { + for (size_t i = 0; i < len; ++i) { + if (closed && i == len - 1) { + // if the line is closed, we treat the last vertex like the first + nextVertex = vertices[i]; + } else if (i + 1 < len) { + // just the next vertex nextVertex = vertices[i + 1]; } else { + // there is no next vertex nextVertex = Coordinate::null(); } - // If the line is closed, we treat the last vertex like the first vertex. - if (!nextVertex && closed) { - nextVertex = vertices[1]; + // if two consecutive vertices exist, skip the current one + if (nextVertex && vertices[i] == nextVertex) { + continue; } - if (nextVertex) { - // if two consecutive vertices exist, skip one - if (currentVertex.x == nextVertex.x && currentVertex.y == nextVertex.y) continue; + if (nextNormal) { + prevNormal = nextNormal; } + if (currentVertex) { + prevVertex = currentVertex; + } + + currentVertex = vertices[i]; + + // Calculate how far along the line the currentVertex is + if (prevVertex) + distance += util::dist(currentVertex, prevVertex); // Calculate the normal towards the next vertex in this line. In case // there is no next vertex, pretend that the line is continuing straight, - // meaning that we are just reversing the previous normal - if (nextVertex) { - nextNormal = util::normal(currentVertex, nextVertex); - } else { - nextNormal = { -prevNormal.x, -prevNormal.y }; - } + // meaning that we are just using the previous normal. + nextNormal = nextVertex ? util::perp(util::unit(vec2(nextVertex - currentVertex))) + : prevNormal; // If we still don't have a previous normal, this is the beginning of a // non-closed line, so we're doing a straight "join". if (!prevNormal) { - prevNormal = { -nextNormal.x, -nextNormal.y }; + prevNormal = nextNormal; } // Determine the normal of the join extrusion. It is the angle bisector // of the segments between the previous line and the next line. - vec2 joinNormal = { - prevNormal.x + nextNormal.x, - prevNormal.y + nextNormal.y - }; + vec2 joinNormal = util::unit(prevNormal + nextNormal); - // Cross product yields 0..1 depending on whether they are parallel - // or perpendicular. - double joinAngularity = nextNormal.x * joinNormal.y - nextNormal.y * joinNormal.x; - joinNormal.x /= joinAngularity; - joinNormal.y /= joinAngularity; - double roundness = std::fmax(std::abs(joinNormal.x), std::abs(joinNormal.y)); + /* joinNormal prevNormal + * ↖ ↑ + * .________. prevVertex + * | + * nextNormal ← | currentVertex + * | + * nextVertex ! + * + */ + // Calculate the length of the miter (the ratio of the miter to the width). + // Find the cosine of the angle between the next and join normals + // using dot product. The inverse of that is the miter length. + const float cosHalfAngle = joinNormal.x * nextNormal.x + joinNormal.y * nextNormal.y; + const float miterLength = 1 / cosHalfAngle; - // Switch to miter joins if the angle is very low. - if (currentJoin != JoinType::Miter) { - if (std::fabs(joinAngularity) < 0.5 && roundness < layout.miter_limit) { + // The join if a middle vertex, otherwise the cap + const bool middleVertex = prevVertex && nextVertex; + JoinType currentJoin = layout.join; + const CapType currentCap = nextVertex ? beginCap : endCap; + + if (middleVertex) { + if (currentJoin == JoinType::Round && miterLength < layout.round_limit) { currentJoin = JoinType::Miter; } - } - // Add offset square begin cap. - if (!prevVertex && beginCap == CapType::Square) { - // Add first vertex - e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos - flip * (prevNormal.x + prevNormal.y), flip * (-prevNormal.x + prevNormal.y), // extrude normal - 0, 0, distance) - start_vertex; // texture normal - - if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3); - e1 = e2; e2 = e3; - - // Add second vertex - e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos - flip * (prevNormal.x - prevNormal.y), flip * (prevNormal.x + prevNormal.y), // extrude normal - 0, 1, distance) - start_vertex; // texture normal - - if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3); - e1 = e2; e2 = e3; - } - - // Add offset square end cap. - else if (!nextVertex && endCap == CapType::Square) { - // Add first vertex - e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos - nextNormal.x - flip * nextNormal.y, flip * nextNormal.x + nextNormal.y, // extrude normal - 0, 0, distance) - start_vertex; // texture normal - - if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3); - e1 = e2; e2 = e3; - - // Add second vertex - e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos - nextNormal.x + flip * nextNormal.y, -flip * nextNormal.x + nextNormal.y, // extrude normal - 0, 1, distance) - start_vertex; // texture normal - - if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3); - e1 = e2; e2 = e3; - } - - else if (currentJoin == JoinType::Miter) { - // MITER JOIN - if (std::fabs(joinAngularity) < 0.01) { - // The two normals are almost parallel. - joinNormal.x = -nextNormal.y; - joinNormal.y = nextNormal.x; - } else if (roundness > layout.miter_limit) { - // If the miter grows too large, flip the direction to make a - // bevel join. - joinNormal.x = (prevNormal.x - nextNormal.x) / joinAngularity; - joinNormal.y = (prevNormal.y - nextNormal.y) / joinAngularity; + if (currentJoin == JoinType::Miter && miterLength > miterLimit) { + currentJoin = JoinType::Bevel; } - if (roundness > layout.miter_limit) { - flip = -flip; - } - - // Add first vertex - e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos - flip * joinNormal.x, flip * joinNormal.y, // extrude normal - 0, 0, distance) - start_vertex; // texture normal - - if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3); - e1 = e2; e2 = e3; - - // Add second vertex - e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos - -flip * joinNormal.x, -flip * joinNormal.y, // extrude normal - 0, 1, distance) - start_vertex; // texture normal - - if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3); - e1 = e2; e2 = e3; - - if ((!prevVertex && beginCap == CapType::Round) || - (!nextVertex && endCap == CapType::Round)) { - point_store.emplace_back(e1); - } - } - - else { - // Close up the previous line - // Add first vertex - e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos - flip * prevNormal.y, -flip * prevNormal.x, // extrude normal - 0, 0, distance) - start_vertex; // texture normal - - if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3); - e1 = e2; e2 = e3; - - // Add second vertex. - e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos - -flip * prevNormal.y, flip * prevNormal.x, // extrude normal - 0, 1, distance) - start_vertex; // texture normal - - if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3); - e1 = e2; e2 = e3; - - prevNormal = { -nextNormal.x, -nextNormal.y }; - flip = 1; - - - // begin/end caps - if ((!prevVertex && beginCap == CapType::Round) || - (!nextVertex && endCap == CapType::Round)) { - point_store.emplace_back(e1); - } - - - if (currentJoin == JoinType::Round) { - if (prevVertex && nextVertex && (!closed || i > 0)) { - point_store.emplace_back(e1); + if (currentJoin == JoinType::Bevel) { + // The maximum extrude length is 128 / 63 = 2 times the width of the line + // so if miterLength >= 2 we need to draw a different type of bevel where. + if (miterLength > 2) { + currentJoin = JoinType::FlipBevel; } - // Reset the previous vertices so that we don't accidentally create - // any triangles. - e1 = -1; e2 = -1; e3 = -1; + // If the miterLength is really small and the line bevel wouldn't be visible, + // just draw a miter join to save a triangle. + if (miterLength < miterLimit) { + currentJoin = JoinType::Miter; + } + } + } + + if (middleVertex && currentJoin == JoinType::Miter) { + joinNormal = joinNormal * miterLength; + addCurrentVertex(currentVertex, flip, distance, joinNormal, 0, 0, false, startVertex, + triangleStore); + + } else if (middleVertex && currentJoin == JoinType::FlipBevel) { + // miter is too big, flip the direction to make a beveled join + + if (miterLength > 100) { + // Almost parallel lines + joinNormal = nextNormal; + } else { + const float bevelLength = miterLength * util::mag(prevNormal + nextNormal) / + util::mag(prevNormal - nextNormal); + joinNormal = util::perp(joinNormal) * bevelLength; } - // Start the new quad. - // Add first vertex - e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos - -flip * nextNormal.y, flip * nextNormal.x, // extrude normal - 0, 0, distance) - start_vertex; // texture normal + addCurrentVertex(currentVertex, flip, distance, joinNormal, 0, 0, false, startVertex, + triangleStore); + flip = -flip; - if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3); - e1 = e2; e2 = e3; + } else if (middleVertex && currentJoin == JoinType::Bevel) { + const float dir = prevNormal.x * nextNormal.y - prevNormal.y * nextNormal.x; + const float offset = -std::sqrt(miterLength * miterLength - 1); + float offsetA; + float offsetB; - // Add second vertex - e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, // vertex pos - flip * nextNormal.y, -flip * nextNormal.x, // extrude normal - 0, 1, distance) - start_vertex; // texture normal + if (flip * dir > 0) { + offsetB = 0; + offsetA = offset; + } else { + offsetA = 0; + offsetB = offset; + } - if (e1 >= 0 && e2 >= 0 && e3 >= 0) triangle_store.emplace_back(e1, e2, e3); - e1 = e2; e2 = e3; + // Close previous segement with bevel + if (!startOfLine) { + addCurrentVertex(currentVertex, flip, distance, prevNormal, offsetA, offsetB, false, + startVertex, triangleStore); + } + + // Start next segment + if (nextVertex) { + addCurrentVertex(currentVertex, flip, distance, nextNormal, -offsetA, -offsetB, + false, startVertex, triangleStore); + } + + } else if (!middleVertex && currentCap == CapType::Butt) { + if (!startOfLine) { + // Close previous segment with a butt + addCurrentVertex(currentVertex, flip, distance, prevNormal, 0, 0, false, + startVertex, triangleStore); + } + + // Start next segment with a butt + if (nextVertex) { + addCurrentVertex(currentVertex, flip, distance, nextNormal, 0, 0, false, + startVertex, triangleStore); + } + + } else if (!middleVertex && currentCap == CapType::Square) { + if (!startOfLine) { + // Close previous segment with a square cap + addCurrentVertex(currentVertex, flip, distance, prevNormal, 1, 1, false, + startVertex, triangleStore); + + // The segment is done. Unset vertices to disconnect segments. + e1 = e2 = -1; + flip = 1; + } + + // Start next segment + if (nextVertex) { + addCurrentVertex(currentVertex, flip, distance, nextNormal, -1, -1, false, + startVertex, triangleStore); + } + + } else if (middleVertex ? currentJoin == JoinType::Round : currentCap == CapType::Round) { + if (!startOfLine) { + // Close previous segment with a butt + addCurrentVertex(currentVertex, flip, distance, prevNormal, 0, 0, false, + startVertex, triangleStore); + + // Add round cap or linejoin at end of segment + addCurrentVertex(currentVertex, flip, distance, prevNormal, 1, 1, true, startVertex, + triangleStore); + + // The segment is done. Unset vertices to disconnect segments. + e1 = e2 = -1; + flip = 1; + + } else if (beginCap == CapType::Round) { + // Add round cap before first segment + addCurrentVertex(currentVertex, flip, distance, nextNormal, -1, -1, true, + startVertex, triangleStore); + } + + // Start next segment with a butt + if (nextVertex) { + addCurrentVertex(currentVertex, flip, distance, nextNormal, 0, 0, false, + startVertex, triangleStore); + } } + + startOfLine = false; } - size_t end_vertex = vertexBuffer.index(); - size_t vertex_count = end_vertex - start_vertex; + const size_t endVertex = vertexBuffer.index(); + const size_t vertexCount = endVertex - startVertex; // Store the triangle/line groups. { - if (!triangleGroups.size() || (triangleGroups.back()->vertex_length + vertex_count > 65535)) { + if (!triangleGroups.size() || + (triangleGroups.back()->vertex_length + vertexCount > 65535)) { // Move to a new group because the old one can't hold the geometry. - triangleGroups.emplace_back(util::make_unique()); + triangleGroups.emplace_back(util::make_unique()); } assert(triangleGroups.back()); - triangle_group_type& group = *triangleGroups.back(); - for (const auto& triangle : triangle_store) { - triangleElementsBuffer.add( - group.vertex_length + triangle.a, - group.vertex_length + triangle.b, - group.vertex_length + triangle.c - ); + auto& group = *triangleGroups.back(); + for (const auto& triangle : triangleStore) { + triangleElementsBuffer.add(group.vertex_length + triangle.a, + group.vertex_length + triangle.b, + group.vertex_length + triangle.c); } - group.vertex_length += vertex_count; - group.elements_length += triangle_store.size(); - } - - // Store the line join/cap groups. - { - if (!pointGroups.size() || (pointGroups.back()->vertex_length + vertex_count > 65535)) { - // Move to a new group because the old one can't hold the geometry. - pointGroups.emplace_back(util::make_unique()); - } - - assert(pointGroups.back()); - point_group_type& group = *pointGroups.back(); - for (const auto point : point_store) { - pointElementsBuffer.add(group.vertex_length + point); - } - - group.vertex_length += vertex_count; - group.elements_length += point_store.size(); + group.vertex_length += vertexCount; + group.elements_length += triangleStore.size(); } } -void LineBucket::render(Painter &painter, const StyleLayer &layer_desc, const TileID &id, - const mat4 &matrix) { +void LineBucket::addCurrentVertex(const Coordinate& currentVertex, + float flip, + double distance, + const vec2& normal, + float endLeft, + float endRight, + bool round, + int32_t startVertex, + std::vector& triangleStore) { + int8_t tx = round ? 1 : 0; + + vec2 extrude = normal * flip; + if (endLeft) + extrude = extrude - (util::perp(normal) * endLeft); + e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, extrude.x, extrude.y, tx, 0, + distance) - + startVertex; + if (e1 >= 0 && e2 >= 0) { + triangleStore.emplace_back(e1, e2, e3); + } + e1 = e2; + e2 = e3; + + extrude = normal * (-flip); + if (endRight) + extrude = extrude - (util::perp(normal) * endRight); + e3 = (int32_t)vertexBuffer.add(currentVertex.x, currentVertex.y, extrude.x, extrude.y, tx, 1, + distance) - + startVertex; + if (e1 >= 0 && e2 >= 0) { + triangleStore.emplace_back(e1, e2, e3); + } + e1 = e2; + e2 = e3; +} + +void LineBucket::render(Painter& painter, + const StyleLayer& layer_desc, + const TileID& id, + const mat4& matrix) { painter.renderLine(*this, layer_desc, id, matrix); } bool LineBucket::hasData() const { - return !triangleGroups.empty() || !pointGroups.empty(); -} - -bool LineBucket::hasPoints() const { - if (!pointGroups.empty()) { - for (const auto& group : pointGroups) { - assert(group); - if (group->elements_length) { - return true; - } - } - } - return false; + return !triangleGroups.empty(); } void LineBucket::drawLines(LineShader& shader) { - char *vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer.itemSize); - char *elements_index = BUFFER_OFFSET(triangle_elements_start * triangleElementsBuffer.itemSize); + char* vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer.itemSize); + char* elements_index = BUFFER_OFFSET(triangle_elements_start * triangleElementsBuffer.itemSize); for (auto& group : triangleGroups) { assert(group); if (!group->elements_length) { continue; } group->array[0].bind(shader, vertexBuffer, triangleElementsBuffer, vertex_index); - MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, group->elements_length * 3, GL_UNSIGNED_SHORT, elements_index)); + MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, group->elements_length * 3, GL_UNSIGNED_SHORT, + elements_index)); vertex_index += group->vertex_length * vertexBuffer.itemSize; elements_index += group->elements_length * triangleElementsBuffer.itemSize; } } void LineBucket::drawLineSDF(LineSDFShader& shader) { - char *vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer.itemSize); - char *elements_index = BUFFER_OFFSET(triangle_elements_start * triangleElementsBuffer.itemSize); + char* vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer.itemSize); + char* elements_index = BUFFER_OFFSET(triangle_elements_start * triangleElementsBuffer.itemSize); for (auto& group : triangleGroups) { assert(group); if (!group->elements_length) { continue; } group->array[2].bind(shader, vertexBuffer, triangleElementsBuffer, vertex_index); - MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, group->elements_length * 3, GL_UNSIGNED_SHORT, elements_index)); + MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, group->elements_length * 3, GL_UNSIGNED_SHORT, + elements_index)); vertex_index += group->vertex_length * vertexBuffer.itemSize; elements_index += group->elements_length * triangleElementsBuffer.itemSize; } } void LineBucket::drawLinePatterns(LinepatternShader& shader) { - char *vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer.itemSize); - char *elements_index = BUFFER_OFFSET(triangle_elements_start * triangleElementsBuffer.itemSize); + char* vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer.itemSize); + char* elements_index = BUFFER_OFFSET(triangle_elements_start * triangleElementsBuffer.itemSize); for (auto& group : triangleGroups) { assert(group); if (!group->elements_length) { continue; } group->array[1].bind(shader, vertexBuffer, triangleElementsBuffer, vertex_index); - MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, group->elements_length * 3, GL_UNSIGNED_SHORT, elements_index)); + MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, group->elements_length * 3, GL_UNSIGNED_SHORT, + elements_index)); vertex_index += group->vertex_length * vertexBuffer.itemSize; elements_index += group->elements_length * triangleElementsBuffer.itemSize; } } - -void LineBucket::drawPoints(LinejoinShader& shader) { - char *vertex_index = BUFFER_OFFSET(vertex_start * vertexBuffer.itemSize); - char *elements_index = BUFFER_OFFSET(point_elements_start * pointElementsBuffer.itemSize); - for (auto& group : pointGroups) { - assert(group); - if (!group->elements_length) { - continue; - } - group->array[0].bind(shader, vertexBuffer, pointElementsBuffer, vertex_index); - MBGL_CHECK_ERROR(glDrawElements(GL_POINTS, group->elements_length, GL_UNSIGNED_SHORT, elements_index)); - vertex_index += group->vertex_length * vertexBuffer.itemSize; - elements_index += group->elements_length * pointElementsBuffer.itemSize; - } -} diff --git a/src/mbgl/renderer/line_bucket.hpp b/src/mbgl/renderer/line_bucket.hpp index d70801e0b..64f353d7c 100644 --- a/src/mbgl/renderer/line_bucket.hpp +++ b/src/mbgl/renderer/line_bucket.hpp @@ -18,18 +18,14 @@ class Style; class LineVertexBuffer; class TriangleElementsBuffer; class LineShader; -class LinejoinShader; class LineSDFShader; class LinepatternShader; class LineBucket : public Bucket { - typedef ElementGroup<3> triangle_group_type; - typedef ElementGroup<1> point_group_type; + using TriangleGroup = ElementGroup<3>; public: - LineBucket(LineVertexBuffer &vertexBuffer, - TriangleElementsBuffer &triangleElementsBuffer, - PointElementsBuffer &pointElementsBuffer); + LineBucket(LineVertexBuffer &vertexBuffer, TriangleElementsBuffer &triangleElementsBuffer); ~LineBucket() override; void render(Painter &painter, const StyleLayer &layer_desc, const TileID &id, @@ -39,12 +35,18 @@ public: void addGeometry(const GeometryCollection&); void addGeometry(const std::vector& line); - bool hasPoints() const; - void drawLines(LineShader& shader); void drawLineSDF(LineSDFShader& shader); void drawLinePatterns(LinepatternShader& shader); - void drawPoints(LinejoinShader& shader); + +private: + struct TriangleElement { + TriangleElement(uint16_t a_, uint16_t b_, uint16_t c_) : a(a_), b(b_), c(c_) {} + uint16_t a, b, c; + }; + void addCurrentVertex(const Coordinate& currentVertex, float flip, double distance, + const vec2& normal, float endLeft, float endRight, bool round, + int32_t startVertex, std::vector& triangleStore); public: StyleLayoutLine layout; @@ -52,14 +54,15 @@ public: private: LineVertexBuffer& vertexBuffer; TriangleElementsBuffer& triangleElementsBuffer; - PointElementsBuffer& pointElementsBuffer; const size_t vertex_start; const size_t triangle_elements_start; - const size_t point_elements_start; - std::vector> triangleGroups; - std::vector> pointGroups; + int32_t e1; + int32_t e2; + int32_t e3; + + std::vector> triangleGroups; }; } diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp index cafd61424..1e34f5320 100644 --- a/src/mbgl/renderer/painter.cpp +++ b/src/mbgl/renderer/painter.cpp @@ -62,7 +62,6 @@ void Painter::setup() { assert(plainShader); assert(outlineShader); assert(lineShader); - assert(linejoinShader); assert(linepatternShader); assert(patternShader); assert(rasterShader); @@ -96,7 +95,6 @@ void Painter::setupShaders() { if (!plainShader) plainShader = util::make_unique(); if (!outlineShader) outlineShader = util::make_unique(); if (!lineShader) lineShader = util::make_unique(); - if (!linejoinShader) linejoinShader = util::make_unique(); if (!linesdfShader) linesdfShader = util::make_unique(); if (!linepatternShader) linepatternShader = util::make_unique(); if (!patternShader) patternShader = util::make_unique(); @@ -112,7 +110,6 @@ void Painter::deleteShaders() { plainShader = nullptr; outlineShader = nullptr; lineShader = nullptr; - linejoinShader = nullptr; linepatternShader = nullptr; patternShader = nullptr; iconShader = nullptr; diff --git a/src/mbgl/renderer/painter.hpp b/src/mbgl/renderer/painter.hpp index cf01c0391..76cacba43 100644 --- a/src/mbgl/renderer/painter.hpp +++ b/src/mbgl/renderer/painter.hpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -199,7 +198,6 @@ public: std::unique_ptr plainShader; std::unique_ptr outlineShader; std::unique_ptr lineShader; - std::unique_ptr linejoinShader; std::unique_ptr linesdfShader; std::unique_ptr linepatternShader; std::unique_ptr patternShader; diff --git a/src/mbgl/renderer/painter_line.cpp b/src/mbgl/renderer/painter_line.cpp index 2f8c3face..57690da46 100644 --- a/src/mbgl/renderer/painter_line.cpp +++ b/src/mbgl/renderer/painter_line.cpp @@ -51,29 +51,6 @@ void Painter::renderLine(LineBucket& bucket, const StyleLayer &layer_desc, const depthRange(strata, 1.0f); - // We're only drawing end caps + round line joins if the line is > 2px. Otherwise, they aren't visible anyway. - if (bucket.hasPoints() && outset > 1.0f) { - useProgram(linejoinShader->program); - linejoinShader->u_matrix = vtxMatrix; - linejoinShader->u_color = color; - linejoinShader->u_world = {{ - state.getFramebufferWidth() * 0.5f, - state.getFramebufferHeight() * 0.5f - }}; - linejoinShader->u_linewidth = {{ - ((outset - 0.25f) * state.getPixelRatio()), - ((inset - 0.25f) * state.getPixelRatio()) - }}; - - float pointSize = std::ceil(state.getPixelRatio() * outset * 2.0); -#if defined(GL_ES_VERSION_2_0) - linejoinShader->u_size = pointSize; -#else - MBGL_CHECK_ERROR(glPointSize(pointSize)); -#endif - bucket.drawPoints(*linejoinShader); - } - if (properties.dash_array.from.size()) { useProgram(linesdfShader->program); diff --git a/src/mbgl/renderer/painter_symbol.cpp b/src/mbgl/renderer/painter_symbol.cpp index 2785e8bae..79ad50e75 100644 --- a/src/mbgl/renderer/painter_symbol.cpp +++ b/src/mbgl/renderer/painter_symbol.cpp @@ -35,7 +35,7 @@ void Painter::renderSDF(SymbolBucket &bucket, } // If layerStyle.size > bucket.info.fontSize then labels may collide - float fontSize = std::fmin(styleProperties.size, bucketProperties.max_size); + float fontSize = styleProperties.size; float fontScale = fontSize / sdfFontSize; matrix::scale(exMatrix, exMatrix, fontScale, fontScale, 1.0f); diff --git a/src/mbgl/renderer/symbol_bucket.cpp b/src/mbgl/renderer/symbol_bucket.cpp index 517c8835c..4563cf647 100644 --- a/src/mbgl/renderer/symbol_bucket.cpp +++ b/src/mbgl/renderer/symbol_bucket.cpp @@ -183,7 +183,8 @@ void SymbolBucket::addFeatures(const GeometryTileLayer& layer, if (feature.label.length()) { shaping = fontStack->getShaping( /* string */ feature.label, - /* maxWidth: ems */ layout.text.max_width * 24, + /* maxWidth: ems */ layout.placement != PlacementType::Line ? + layout.text.max_width * 24 : 0, /* lineHeight: ems */ layout.text.line_height * 24, /* horizontalAlign */ horizontalAlign, /* verticalAlign */ verticalAlign, diff --git a/src/mbgl/shader/linejoin.fragment.glsl b/src/mbgl/shader/linejoin.fragment.glsl deleted file mode 100644 index 705a57766..000000000 --- a/src/mbgl/shader/linejoin.fragment.glsl +++ /dev/null @@ -1,14 +0,0 @@ -uniform vec4 u_color; -uniform vec2 u_linewidth; - -varying vec2 v_pos; - -void main() { - float dist = length(v_pos - gl_FragCoord.xy); - - // Calculate the antialiasing fade factor. This is either when fading in - // the line in case of an offset line (v_linewidth.t) or when fading out - // (v_linewidth.s) - float alpha = clamp(min(dist - (u_linewidth.t - 1.0), u_linewidth.s - dist), 0.0, 1.0); - gl_FragColor = u_color * alpha; -} diff --git a/src/mbgl/shader/linejoin.vertex.glsl b/src/mbgl/shader/linejoin.vertex.glsl deleted file mode 100644 index 2e03561e5..000000000 --- a/src/mbgl/shader/linejoin.vertex.glsl +++ /dev/null @@ -1,13 +0,0 @@ -attribute vec2 a_pos; - -uniform mat4 u_matrix; -uniform vec2 u_world; -uniform float u_size; - -varying vec2 v_pos; - -void main() { - gl_Position = u_matrix * vec4(floor(a_pos / 2.0), 0.0, 1.0); - v_pos = (gl_Position.xy + 1.0) * u_world; - gl_PointSize = u_size; -} diff --git a/src/mbgl/shader/linejoin_shader.cpp b/src/mbgl/shader/linejoin_shader.cpp deleted file mode 100644 index b3c5638b5..000000000 --- a/src/mbgl/shader/linejoin_shader.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include -#include -#include - -#include - -using namespace mbgl; - -LinejoinShader::LinejoinShader() - : Shader( - "linejoin", - shaders[LINEJOIN_SHADER].vertex, - shaders[LINEJOIN_SHADER].fragment - ) { - a_pos = MBGL_CHECK_ERROR(glGetAttribLocation(program, "a_pos")); -} - -void LinejoinShader::bind(char *offset) { - MBGL_CHECK_ERROR(glEnableVertexAttribArray(a_pos)); - // Note: We're referring to the vertices in a line array, which are 8 bytes long! - MBGL_CHECK_ERROR(glVertexAttribPointer(a_pos, 2, GL_SHORT, false, 8, offset)); -} diff --git a/src/mbgl/shader/linejoin_shader.hpp b/src/mbgl/shader/linejoin_shader.hpp deleted file mode 100644 index 61406fd45..000000000 --- a/src/mbgl/shader/linejoin_shader.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef MBGL_SHADER_SHADER_LINEJOIN -#define MBGL_SHADER_SHADER_LINEJOIN - -#include -#include - -namespace mbgl { - -class LinejoinShader : public Shader { -public: - LinejoinShader(); - - void bind(char *offset); - - UniformMatrix<4> u_matrix = {"u_matrix", *this}; - Uniform> u_color = {"u_color", *this}; - Uniform> u_world = {"u_world", *this}; - Uniform> u_linewidth = {"u_linewidth", *this}; - Uniform u_size = {"u_size", *this}; - -private: - int32_t a_pos = -1; -}; - -} - -#endif diff --git a/src/mbgl/style/property_fallback.cpp b/src/mbgl/style/property_fallback.cpp index dce226cde..655a75df9 100644 --- a/src/mbgl/style/property_fallback.cpp +++ b/src/mbgl/style/property_fallback.cpp @@ -22,7 +22,6 @@ const std::map PropertyFallbackValue::properties = { { PropertyKey::LineBlur, defaultStyleProperties().blur }, { PropertyKey::IconOpacity, defaultStyleProperties().icon.opacity }, - { PropertyKey::IconRotate, defaultStyleProperties().icon.rotate }, { PropertyKey::IconSize, defaultStyleProperties().icon.size }, { PropertyKey::IconColor, defaultStyleProperties().icon.color }, { PropertyKey::IconHaloColor, defaultStyleProperties().icon.halo_color }, diff --git a/src/mbgl/style/style_layer.cpp b/src/mbgl/style/style_layer.cpp index 542c4eb8a..e9c301d8c 100644 --- a/src/mbgl/style/style_layer.cpp +++ b/src/mbgl/style/style_layer.cpp @@ -194,7 +194,6 @@ void StyleLayer::applyStyleProperties(const float z, const Tim properties.set(); SymbolProperties &symbol = properties.get(); applyTransitionedStyleProperty(PropertyKey::IconOpacity, symbol.icon.opacity, z, now, zoomHistory); - applyTransitionedStyleProperty(PropertyKey::IconRotate, symbol.icon.rotate, z, now, zoomHistory); applyTransitionedStyleProperty(PropertyKey::IconSize, symbol.icon.size, z, now, zoomHistory); applyTransitionedStyleProperty(PropertyKey::IconColor, symbol.icon.color, z, now, zoomHistory); applyTransitionedStyleProperty(PropertyKey::IconHaloColor, symbol.icon.halo_color, z, now, zoomHistory); diff --git a/src/mbgl/style/style_parser.cpp b/src/mbgl/style/style_parser.cpp index afed2eeee..dc91c250c 100644 --- a/src/mbgl/style/style_parser.cpp +++ b/src/mbgl/style/style_parser.cpp @@ -811,7 +811,6 @@ void StyleParser::parsePaint(JSVal value, ClassProperties &klass) { parseOptionalProperty>("icon-opacity", Key::IconOpacity, klass, value); parseOptionalProperty("icon-opacity-transition", Key::IconOpacity, klass, value); - parseOptionalProperty>("icon-rotate", Key::IconRotate, klass, value); parseOptionalProperty>("icon-size", Key::IconSize, klass, value); parseOptionalProperty("icon-size-transition", Key::IconSize, klass, value); parseOptionalProperty>("icon-color", Key::IconColor, klass, value); diff --git a/src/mbgl/style/style_properties.hpp b/src/mbgl/style/style_properties.hpp index f50722542..8e8619fb9 100644 --- a/src/mbgl/style/style_properties.hpp +++ b/src/mbgl/style/style_properties.hpp @@ -51,7 +51,6 @@ struct SymbolProperties { struct { float opacity = 1.0f; - float rotate = 0.0f; float size = 1.0f; Color color = {{ 0, 0, 0, 1 }}; Color halo_color = {{ 0, 0, 0, 0 }}; diff --git a/src/mbgl/style/types.hpp b/src/mbgl/style/types.hpp index 3b24d6399..f6ffcd686 100644 --- a/src/mbgl/style/types.hpp +++ b/src/mbgl/style/types.hpp @@ -91,13 +91,15 @@ MBGL_DEFINE_ENUM_CLASS(CapTypeClass, CapType, { enum class JoinType : uint8_t { Miter, Bevel, - Round + Round, + FlipBevel }; MBGL_DEFINE_ENUM_CLASS(JoinTypeClass, JoinType, { { JoinType::Miter, "miter" }, { JoinType::Bevel, "bevel" }, { JoinType::Round, "round" }, + { JoinType::FlipBevel, "flipbevel" }, }); // ------------------------------------------------------------------------------------------------- diff --git a/test/ios/KIF b/test/ios/KIF index ab5a46ff7..976aafa2e 160000 --- a/test/ios/KIF +++ b/test/ios/KIF @@ -1 +1 @@ -Subproject commit ab5a46ff7e970de5578df48a1e1f013bd5e1bd4e +Subproject commit 976aafa2e211dd095411bfef09da6c0919d70476 diff --git a/test/ios/KIFTestActor+MapboxGL.h b/test/ios/KIFTestActor+MapboxGL.h index 199091b29..d16e34848 100644 --- a/test/ios/KIFTestActor+MapboxGL.h +++ b/test/ios/KIFTestActor+MapboxGL.h @@ -1,11 +1,12 @@ +#import #import -@class MGLMapView; +@class MGLTViewController, MGLMapView; @interface KIFTestActor (MapboxGL) @property (nonatomic, readonly) UIWindow *window; -@property (nonatomic, readonly) UIViewController *viewController; +@property (nonatomic, readonly) MGLTViewController *viewController; @property (nonatomic, readonly) MGLMapView *mapView; @property (nonatomic, readonly) UIView *compass; diff --git a/test/ios/KIFTestActor+MapboxGL.m b/test/ios/KIFTestActor+MapboxGL.m index b267e0c0b..330adfdc2 100644 --- a/test/ios/KIFTestActor+MapboxGL.m +++ b/test/ios/KIFTestActor+MapboxGL.m @@ -1,7 +1,8 @@ #import "KIFTestActor+MapboxGL.h" + +#import "MapboxGL.h" + #import -#import -#import "MGLMapView.h" @implementation KIFTestActor (MapboxGL) @@ -9,8 +10,8 @@ return [[UIApplication sharedApplication] statusBarWindow]; } -- (UIViewController *)viewController { - return (UIViewController *)[[tester.mapView nextResponder] nextResponder]; +- (MGLTViewController *)viewController { + return (MGLTViewController *)[[tester.mapView nextResponder] nextResponder]; } - (MGLMapView *)mapView { diff --git a/test/ios/MGLTAppDelegate.h b/test/ios/MGLTAppDelegate.h index e5c459beb..c0025582e 100644 --- a/test/ios/MGLTAppDelegate.h +++ b/test/ios/MGLTAppDelegate.h @@ -2,6 +2,6 @@ @interface MGLTAppDelegate : UIResponder -@property (strong, nonatomic) UIWindow *window; +@property (nonatomic) UIWindow *window; @end diff --git a/test/ios/MGLTViewController.h b/test/ios/MGLTViewController.h index 39df59bb5..0be0e1ff2 100644 --- a/test/ios/MGLTViewController.h +++ b/test/ios/MGLTViewController.h @@ -2,4 +2,7 @@ @interface MGLTViewController : UIViewController +- (void)insetMapView; +- (void)resetMapView; + @end diff --git a/test/ios/MGLTViewController.m b/test/ios/MGLTViewController.m index 9caa64c79..e8b500b43 100644 --- a/test/ios/MGLTViewController.m +++ b/test/ios/MGLTViewController.m @@ -1,18 +1,31 @@ #import "MGLTViewController.h" -#import "MGLMapView.h" +#import "MapboxGL.h" @implementation MGLTViewController +{ + MGLMapView *_mapView; +} - (void)viewDidLoad { [super viewDidLoad]; - MGLMapView *mapView = [[MGLMapView alloc] initWithFrame:self.view.bounds + _mapView = [[MGLMapView alloc] initWithFrame:self.view.bounds accessToken:@"pk.eyJ1IjoianVzdGluIiwiYSI6Ik9RX3RRQzAifQ.dmOg_BAp1ywuDZMM7YsXRg"]; - mapView.viewControllerForLayoutGuides = self; - mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + _mapView.viewControllerForLayoutGuides = self; + _mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - [self.view addSubview:mapView]; + [self.view addSubview:_mapView]; +} + +- (void)insetMapView +{ + _mapView.frame = CGRectInset(_mapView.frame, 50, 50); +} + +- (void)resetMapView +{ + _mapView.frame = self.view.bounds; } @end diff --git a/test/ios/MapViewTests.h b/test/ios/MapViewTests.h deleted file mode 100644 index 5057ffd64..000000000 --- a/test/ios/MapViewTests.h +++ /dev/null @@ -1,5 +0,0 @@ -#import - -@interface MapViewTests : KIFTestCase - -@end diff --git a/test/ios/MapViewTests.m b/test/ios/MapViewTests.m index adf3aeba0..fff52adc0 100644 --- a/test/ios/MapViewTests.m +++ b/test/ios/MapViewTests.m @@ -1,9 +1,12 @@ -#import "MapViewTests.h" +#import #import -#import "KIFTestActor+MapboxGL.h" -#import "MGLMapView.h" -@interface MapViewTests () +#import "KIFTestActor+MapboxGL.h" + +#import "MapboxGL.h" +#import "MGLTViewController.h" + +@interface MapViewTests : KIFTestCase @end @@ -11,120 +14,133 @@ - (void)beforeEach { [system simulateDeviceRotationToOrientation:UIDeviceOrientationPortrait]; - tester.mapView.viewControllerForLayoutGuides = tester.viewController; + [tester.viewController resetMapView]; + tester.mapView.centerCoordinate = CLLocationCoordinate2DMake(38.913175, -77.032458); tester.mapView.zoomLevel = 14; tester.mapView.direction = 0; + tester.mapView.zoomEnabled = YES; tester.mapView.scrollEnabled = YES; tester.mapView.rotateEnabled = YES; + tester.viewController.navigationController.navigationBarHidden = YES; tester.viewController.navigationController.toolbarHidden = YES; + tester.mapView.delegate = self; } - (void)testDirectionSet { tester.mapView.direction = 270; - __KIFAssertEqual(tester.mapView.direction, - 270, - @"setting direction should take effect"); + + XCTAssertEqual(tester.mapView.direction, + 270, + @"setting direction should take effect"); [tester waitForTimeInterval:1]; - __KIFAssertEqual(tester.compass.alpha, - 1, - @"compass should be visible when map is rotated"); - __KIFAssertEqualObjects([NSValue valueWithCGAffineTransform:tester.compass.transform], - [NSValue valueWithCGAffineTransform:CGAffineTransformMakeRotation(M_PI * 1.5)], - @"compass rotation should indicate map rotation"); + XCTAssertEqual(tester.compass.alpha, + 1, + @"compass should be visible when map is rotated"); + + XCTAssertEqualObjects([NSValue valueWithCGAffineTransform:tester.compass.transform], + [NSValue valueWithCGAffineTransform:CGAffineTransformMakeRotation(M_PI * 1.5)], + @"compass rotation should indicate map rotation"); } - (void)testCompassTap { tester.mapView.direction = 180; - __KIFAssertEqual(tester.mapView.direction, - 180, - @"setting direction should take effect"); - [tester waitForTimeInterval:1]; + XCTAssertEqual(tester.mapView.direction, + 180, + @"setting direction should take effect"); [tester.compass tap]; [tester waitForTimeInterval:1]; - __KIFAssertEqual(tester.mapView.direction, - 0, - @"tapping compass should reset map direction"); - __KIFAssertEqual(tester.compass.alpha, - 0, - @"compass should not be visible when map is unrotated"); - __KIFAssertEqualObjects([NSValue valueWithCGAffineTransform:tester.compass.transform], - [NSValue valueWithCGAffineTransform:CGAffineTransformIdentity], - @"compass rotation should indicate map rotation"); + XCTAssertEqual(tester.mapView.direction, + 0, + @"tapping compass should reset map direction"); + + XCTAssertEqual(tester.compass.alpha, + 0, + @"compass should not be visible when map is unrotated"); + + XCTAssertEqualObjects([NSValue valueWithCGAffineTransform:tester.compass.transform], + [NSValue valueWithCGAffineTransform:CGAffineTransformIdentity], + @"compass rotation should indicate map rotation"); } - (void)testDirectionReset { - tester.mapView.direction = 100; - __KIFAssertEqual(tester.mapView.direction, - 100, - @"setting direction should take effect"); + tester.mapView.direction = 90; + + XCTAssertEqual(tester.mapView.direction, + 90, + @"setting direction should take effect"); [tester.mapView resetNorth]; [tester waitForTimeInterval:1]; - __KIFAssertEqual(tester.mapView.direction, - 0, - @"resetting north should reset map direction"); - __KIFAssertEqual(tester.compass.alpha, - 0, - @"compass should not be visible when map is unrotated"); - __KIFAssertEqualObjects([NSValue valueWithCGAffineTransform:tester.compass.transform], - [NSValue valueWithCGAffineTransform:CGAffineTransformIdentity], - @"compass rotation should indicate map rotation"); + XCTAssertEqual(tester.mapView.direction, + 0, + @"resetting north should reset map direction"); + + XCTAssertEqual(tester.compass.alpha, + 0, + @"compass should not be visible when map is unrotated"); + + XCTAssertEqualObjects([NSValue valueWithCGAffineTransform:tester.compass.transform], + [NSValue valueWithCGAffineTransform:CGAffineTransformIdentity], + @"compass rotation should indicate map rotation"); } - (void)testZoom { double zoom = tester.mapView.zoomLevel; - [tester.mapView zoomAtPoint:CGPointMake(tester.mapView.bounds.size.width / 2, + [tester.mapView zoomAtPoint:CGPointMake(tester.mapView.bounds.size.width / 2, tester.mapView.bounds.size.height / 2) distance:50 steps:10]; - XCTAssertTrue(tester.mapView.zoomLevel > zoom, - @"zoom gesture should increase zoom level"); + XCTAssertGreaterThan(tester.mapView.zoomLevel, + zoom, + @"zoom gesture should increase zoom level"); zoom = tester.mapView.zoomLevel; - [tester.mapView pinchAtPoint:CGPointMake(tester.mapView.bounds.size.width / 2, + + [tester.mapView pinchAtPoint:CGPointMake(tester.mapView.bounds.size.width / 2, tester.mapView.bounds.size.height / 2) distance:50 steps:10]; - XCTAssertTrue(tester.mapView.zoomLevel < zoom, - @"pinch gesture should decrease zoom level"); + XCTAssertLessThan(tester.mapView.zoomLevel, + zoom, + @"pinch gesture should decrease zoom level"); } - (void)testZoomDisabled { tester.mapView.zoomEnabled = NO; double zoom = tester.mapView.zoomLevel; - [tester.mapView zoomAtPoint:CGPointMake(tester.mapView.bounds.size.width / 2, + [tester.mapView zoomAtPoint:CGPointMake(tester.mapView.bounds.size.width / 2, tester.mapView.bounds.size.height / 2) distance:50 steps:10]; - __KIFAssertEqual(tester.mapView.zoomLevel, - zoom, - @"disabling zoom gesture should disallow zooming"); + XCTAssertEqual(tester.mapView.zoomLevel, + zoom, + @"disabling zoom gesture should disallow zooming"); - [tester.mapView pinchAtPoint:CGPointMake(tester.mapView.bounds.size.width / 2, - tester.mapView.bounds.size.height / 2) + [tester.mapView pinchAtPoint:CGPointMake(tester.mapView.bounds.size.width / 2, + tester.mapView.bounds.size.height / 2) distance:50 steps:10]; - __KIFAssertEqual(tester.mapView.zoomLevel, - zoom, - @"disabling zoom gesture should disallow pinching"); + XCTAssertEqual(tester.mapView.zoomLevel, + zoom, + @"disabling zoom gesture should disallow pinching"); } - (void)testPan { @@ -132,10 +148,13 @@ [tester.mapView dragFromPoint:CGPointMake(10, 10) toPoint:CGPointMake(300, 300) steps:10]; - XCTAssertTrue(tester.mapView.centerCoordinate.latitude > centerCoordinate.latitude, - @"panning map down should increase center latitude"); - XCTAssertTrue(tester.mapView.centerCoordinate.longitude < centerCoordinate.longitude, - @"panning map right should decrease center longitude"); + XCTAssertGreaterThan(tester.mapView.centerCoordinate.latitude, + centerCoordinate.latitude, + @"panning map down should increase center latitude"); + + XCTAssertLessThan(tester.mapView.centerCoordinate.longitude, + centerCoordinate.longitude, + @"panning map right should decrease center longitude"); } - (void)testPanDisabled { @@ -144,42 +163,82 @@ [tester.mapView dragFromPoint:CGPointMake(10, 10) toPoint:CGPointMake(300, 300) steps:10]; - __KIFAssertEqual(centerCoordinate.latitude, - tester.mapView.centerCoordinate.latitude, - @"disabling pan gesture should disallow vertical panning"); - __KIFAssertEqual(centerCoordinate.longitude, - tester.mapView.centerCoordinate.longitude, - @"disabling pan gesture should disallow horizontal panning"); + XCTAssertEqualWithAccuracy(centerCoordinate.latitude, + tester.mapView.centerCoordinate.latitude, + 0.005, + @"disabling pan gesture should disallow vertical panning"); + + XCTAssertEqualWithAccuracy(centerCoordinate.longitude, + tester.mapView.centerCoordinate.longitude, + 0.005, + @"disabling pan gesture should disallow horizontal panning"); +} + +- (void)testRotate { + CLLocationDirection startAngle = tester.mapView.direction; + + XCTAssertNotEqual(startAngle, + 45, + @"start angle must not be destination angle"); + + [tester.mapView twoFingerRotateAtPoint:tester.mapView.center angle:45]; + + XCTAssertGreaterThanOrEqual(fabs(tester.mapView.direction - startAngle), + 20, + @"rotating map should change angle"); +} + +- (void)testRotateDisabled { + tester.mapView.rotateEnabled = NO; + CLLocationDirection startAngle = tester.mapView.direction; + + XCTAssertNotEqual(startAngle, + 45, + @"start angle must not be destination angle"); + + [tester.mapView twoFingerRotateAtPoint:tester.mapView.center angle:45]; + + XCTAssertEqualWithAccuracy(tester.mapView.direction, + startAngle, + 0.005, + @"disabling rotation show disallow rotation gestures"); } - (void)testCenterSet { CLLocationCoordinate2D newCenterCoordinate = CLLocationCoordinate2DMake(45.23237263, -122.23287129); + XCTAssertNotEqual(tester.mapView.centerCoordinate.latitude, newCenterCoordinate.latitude, @"initial setup should have differing center latitude"); + XCTAssertNotEqual(tester.mapView.centerCoordinate.longitude, newCenterCoordinate.longitude, @"initial setup should have differing center longitude"); - [tester.mapView setCenterCoordinate:newCenterCoordinate]; + tester.mapView.centerCoordinate = newCenterCoordinate; - XCTAssertTrue(tester.mapView.centerCoordinate.latitude == newCenterCoordinate.latitude, - @"setting center should change latitude"); - XCTAssertTrue(tester.mapView.centerCoordinate.longitude == newCenterCoordinate.longitude, - @"setting center should change longitude"); + XCTAssertEqual(tester.mapView.centerCoordinate.latitude, + newCenterCoordinate.latitude, + @"setting center should change latitude"); + + XCTAssertEqual(tester.mapView.centerCoordinate.longitude, + newCenterCoordinate.longitude, + @"setting center should change longitude"); } - (void)testZoomSet { double newZoom = 11.65; + XCTAssertNotEqual(tester.mapView.zoomLevel, newZoom, @"initial setup should have differing zoom"); tester.mapView.zoomLevel = newZoom; - __KIFAssertEqual(tester.mapView.zoomLevel, - newZoom, - @"setting zoom should take effect"); + XCTAssertEqualWithAccuracy(tester.mapView.zoomLevel, + newZoom, + 0.01, + @"setting zoom should take effect"); } - (void)testTopLayoutGuide { @@ -233,19 +292,41 @@ logoBugFrame = [logoBug.superview convertRect:logoBug.frame toView:nil]; toolbarFrame = [tester.window convertRect:toolbar.frame toView:nil]; XCTAssertFalse(CGRectIntersectsRect(logoBugFrame, toolbarFrame), - @"rotated device should not have logo buy under toolbar"); + @"rotated device should not have logo bug under toolbar"); attributionButtonFrame = [attributionButton.superview convertRect:attributionButton.frame toView:nil]; XCTAssertFalse(CGRectIntersectsRect(attributionButtonFrame, toolbarFrame), @"rotated device should not have attribution button under toolbar"); } +- (void)testInsetMapView { + [tester.viewController insetMapView]; + [tester waitForAnimationsToFinish]; + + UIView *logoBug = (UIView *)[tester waitForViewWithAccessibilityLabel:@"Mapbox logo"]; + UIView *attributionButton = (UIView *)[tester waitForViewWithAccessibilityLabel:@"Attribution info"]; + + CGRect mapViewFrame = [tester.mapView.superview convertRect:tester.mapView.frame toView:nil]; + + CGRect logoBugFrame = [logoBug.superview convertRect:logoBug.frame toView:nil]; + XCTAssertTrue(CGRectIntersectsRect(logoBugFrame, mapViewFrame), + @"logo bug should lie inside shrunken map view"); + + CGRect attributionButtonFrame = [attributionButton.superview convertRect:attributionButton.frame toView:nil]; + XCTAssertTrue(CGRectIntersectsRect(attributionButtonFrame, mapViewFrame), + @"attribution button should lie inside shrunken map view"); + + CGRect compassFrame = [tester.compass.superview convertRect:tester.compass.frame toView:nil]; + XCTAssertTrue(CGRectIntersectsRect(compassFrame, mapViewFrame), + @"compass should lie inside shrunken map view"); +} + - (void)testDelegateRegionWillChange { - __block NSUInteger unanimatedCount = 0; - __block NSUInteger animatedCount = 0; + __block NSUInteger unanimatedCount; + __block NSUInteger animatedCount; [[NSNotificationCenter defaultCenter] addObserverForName:@"regionWillChangeAnimated" object:tester.mapView - queue:[NSOperationQueue mainQueue] + queue:nil usingBlock:^(NSNotification *note) { if ([note.userInfo[@"animated"] boolValue]) { animatedCount++; @@ -254,35 +335,40 @@ } }]; + [tester waitForTimeInterval:1]; + + unanimatedCount = 0; + animatedCount = 0; + NSNotification *notification = [system waitForNotificationName:@"regionWillChangeAnimated" object:tester.mapView whileExecutingBlock:^{ tester.mapView.centerCoordinate = CLLocationCoordinate2DMake(0, 0); }]; + [tester waitForTimeInterval:1]; - XCTAssertNotNil(notification, - @"regionWillChange delegate should produce a notification"); - __KIFAssertEqual([notification.userInfo[@"animated"] boolValue], - NO, - @"regionWillChange delegate should not indicate animated change"); - __KIFAssertEqual(unanimatedCount, - 1, - @"regionWillChange delegate should indicate one unanimated change"); + + XCTAssertEqual([notification.userInfo[@"animated"] boolValue], + NO, + @"regionWillChange delegate should not indicate animated change"); + XCTAssertEqual(unanimatedCount, + 1, + @"regionWillChange delegate should indicate one unanimated change"); notification = [system waitForNotificationName:@"regionWillChangeAnimated" object:tester.mapView whileExecutingBlock:^{ [tester.mapView setCenterCoordinate:CLLocationCoordinate2DMake(45, 100) animated:YES]; }]; + [tester waitForTimeInterval:1]; - XCTAssertNotNil(notification, - @"regionWillChange delegate should produce a notification"); - __KIFAssertEqual([notification.userInfo[@"animated"] boolValue], - YES, - @"regionWillChange delegate should indicate an animated change"); - __KIFAssertEqual(animatedCount, - 1, - @"regionWillChange delegate should indicate one animated change"); + + XCTAssertEqual([notification.userInfo[@"animated"] boolValue], + YES, + @"regionWillChange delegate should indicate an animated change"); + XCTAssertEqual(animatedCount, + 1, + @"regionWillChange delegate should indicate one animated change"); [[NSNotificationCenter defaultCenter] removeObserver:self name:@"regionWillChangeAnimated" @@ -296,11 +382,11 @@ } - (void)testDelegateRegionDidChange { - __block NSUInteger unanimatedCount = 0; - __block NSUInteger animatedCount = 0; + __block NSUInteger unanimatedCount; + __block NSUInteger animatedCount; [[NSNotificationCenter defaultCenter] addObserverForName:@"regionDidChangeAnimated" object:tester.mapView - queue:[NSOperationQueue mainQueue] + queue:nil usingBlock:^(NSNotification *note) { if ([note.userInfo[@"animated"] boolValue]) { animatedCount++; @@ -309,35 +395,40 @@ } }]; + [tester waitForTimeInterval:1]; + + unanimatedCount = 0; + animatedCount = 0; + NSNotification *notification = [system waitForNotificationName:@"regionDidChangeAnimated" object:tester.mapView whileExecutingBlock:^{ tester.mapView.centerCoordinate = CLLocationCoordinate2DMake(0, 0); }]; + [tester waitForTimeInterval:1]; - XCTAssertNotNil(notification, - @"regionDidChange delegate should produce a notification"); - __KIFAssertEqual([notification.userInfo[@"animated"] boolValue], - NO, - @"regionDidChange delegate should not indicate animated change"); - __KIFAssertEqual(unanimatedCount, - 1, - @"regionDidChange delegate should indicate one unanimated change"); + + XCTAssertEqual([notification.userInfo[@"animated"] boolValue], + NO, + @"regionDidChange delegate should not indicate animated change"); + XCTAssertEqual(unanimatedCount, + 1, + @"regionDidChange delegate should indicate one unanimated change"); notification = [system waitForNotificationName:@"regionDidChangeAnimated" object:tester.mapView whileExecutingBlock:^{ [tester.mapView setCenterCoordinate:CLLocationCoordinate2DMake(45, 100) animated:YES]; }]; + [tester waitForTimeInterval:1]; - XCTAssertNotNil(notification, - @"regionDidChange delegate should produce a notification"); - __KIFAssertEqual([notification.userInfo[@"animated"] boolValue], - YES, - @"regionDidChange delegate should indicate animated change"); - __KIFAssertEqual(animatedCount, - 1, - @"regionDidChange delegate should indicate one animated change"); + + XCTAssertEqual([notification.userInfo[@"animated"] boolValue], + YES, + @"regionDidChange delegate should indicate animated change"); + XCTAssertEqual(animatedCount, + 1, + @"regionDidChange delegate should indicate one animated change"); [[NSNotificationCenter defaultCenter] removeObserver:self name:@"regionDidChangeAnimated" diff --git a/test/ios/README.md b/test/ios/README.md deleted file mode 100644 index 21975e177..000000000 --- a/test/ios/README.md +++ /dev/null @@ -1,9 +0,0 @@ -This is a harness app for integration testing of Mapbox GL Cocoa. It uses the static library build of Mapbox GL Cocoa in order to be entirely self-contained and not need the `mapbox-gl-native` upstream C++ project. - -To run tests, either open the enclosed `ios-tests.xcodeproj` and run the tests or use `xcodebuild test` at the command line from this directory. For example: - -```bash -xcodebuild -scheme 'Mapbox GL Tests' \ - -destination 'platform=iOS Simulator,name=iPad,OS=7.1' \ - test -``` diff --git a/test/ios/ios-tests.xcodeproj/project.pbxproj b/test/ios/ios-tests.xcodeproj/project.pbxproj index 86f125132..f644d912d 100644 --- a/test/ios/ios-tests.xcodeproj/project.pbxproj +++ b/test/ios/ios-tests.xcodeproj/project.pbxproj @@ -7,27 +7,24 @@ objects = { /* Begin PBXBuildFile section */ - DD043327196DB9BC00E6F39D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD043326196DB9BC00E6F39D /* Foundation.framework */; }; - DD043329196DB9BC00E6F39D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD043328196DB9BC00E6F39D /* CoreGraphics.framework */; }; - DD04332B196DB9BC00E6F39D /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD04332A196DB9BC00E6F39D /* UIKit.framework */; }; DD043363196DBBD500E6F39D /* MGLTAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DD04335F196DBBD500E6F39D /* MGLTAppDelegate.m */; }; DD043364196DBBD500E6F39D /* MGLTViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DD043360196DBBD500E6F39D /* MGLTViewController.m */; }; DD043366196DBBE000E6F39D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DD043365196DBBE000E6F39D /* main.m */; }; - DD1A9EA8199BEA0D007BC651 /* libc++.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DD1A9EA7199BEA0D007BC651 /* libc++.dylib */; }; - DD61240819CCF06E006845B1 /* libMapboxGL.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DD61240619CCF06E006845B1 /* libMapboxGL.a */; }; - DD61240919CCF06E006845B1 /* MapboxGL.bundle in Resources */ = {isa = PBXBuildFile; fileRef = DD61240719CCF06E006845B1 /* MapboxGL.bundle */; }; - DD8A790D196DC0A900FAD883 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DD8A790C196DC0A900FAD883 /* libz.dylib */; }; - DD8A790F196DC0AD00FAD883 /* GLKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD8A790E196DC0AD00FAD883 /* GLKit.framework */; }; - DD8A7911196DC0BB00FAD883 /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD8A7910196DC0BB00FAD883 /* CoreLocation.framework */; }; - DD96917919F1C08400729E7D /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DD96917819F1C08400729E7D /* libsqlite3.dylib */; }; - DD96918119F1C09200729E7D /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD96918019F1C09200729E7D /* SystemConfiguration.framework */; }; - DDBD0154196DC3D70033959E /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DDBD0153196DC3D70033959E /* XCTest.framework */; }; - DDBD0155196DC3D70033959E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD043326196DB9BC00E6F39D /* Foundation.framework */; }; - DDBD0156196DC3D70033959E /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD04332A196DB9BC00E6F39D /* UIKit.framework */; }; + DD0580E81ACB628200B112C9 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD0580E71ACB628200B112C9 /* IOKit.framework */; }; + DD0581041ACB661200B112C9 /* Headers in Resources */ = {isa = PBXBuildFile; fileRef = DD0581031ACB661200B112C9 /* Headers */; }; + DD0581061ACB661C00B112C9 /* MapboxGL.bundle in Resources */ = {isa = PBXBuildFile; fileRef = DD0581051ACB661C00B112C9 /* MapboxGL.bundle */; }; + DD0581081ACB663200B112C9 /* libMapboxGL.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DD0581071ACB663200B112C9 /* libMapboxGL.a */; }; + DD41CE091ACB5DBC00FA7979 /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD41CE081ACB5DBC00FA7979 /* CoreTelephony.framework */; }; + DD41CE0B1ACB5DC400FA7979 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD41CE0A1ACB5DC400FA7979 /* SystemConfiguration.framework */; }; + DD41CE0D1ACB5DCB00FA7979 /* libc++.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DD41CE0C1ACB5DCB00FA7979 /* libc++.dylib */; }; + DD41CE0F1ACB5DD000FA7979 /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DD41CE0E1ACB5DD000FA7979 /* libsqlite3.dylib */; }; + DD41CE111ACB5DD500FA7979 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DD41CE101ACB5DD500FA7979 /* libz.dylib */; }; + DD41CE131ACB5DDA00FA7979 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD41CE121ACB5DDA00FA7979 /* MobileCoreServices.framework */; }; + DD41CE151ACB5DE000FA7979 /* ImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD41CE141ACB5DE000FA7979 /* ImageIO.framework */; }; + DD41CE171ACB5DE700FA7979 /* GLKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD41CE161ACB5DE700FA7979 /* GLKit.framework */; }; DDBD016C196DC4740033959E /* MapViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DDBD0168196DC4740033959E /* MapViewTests.m */; }; DDBD016D196DC4740033959E /* KIFTestActor+MapboxGL.m in Sources */ = {isa = PBXBuildFile; fileRef = DDBD016A196DC4740033959E /* KIFTestActor+MapboxGL.m */; }; DDBD016E196DC4A10033959E /* libKIF.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DDBD0144196DC3AE0033959E /* libKIF.a */; }; - DDBD016F196DC4A90033959E /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD043328196DB9BC00E6F39D /* CoreGraphics.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -77,35 +74,30 @@ /* Begin PBXFileReference section */ DD043323196DB9BC00E6F39D /* Mapbox GL Tests.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Mapbox GL Tests.app"; sourceTree = BUILT_PRODUCTS_DIR; }; - DD043326196DB9BC00E6F39D /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - DD043328196DB9BC00E6F39D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; - DD04332A196DB9BC00E6F39D /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; DD04335F196DBBD500E6F39D /* MGLTAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLTAppDelegate.m; sourceTree = SOURCE_ROOT; }; DD043360196DBBD500E6F39D /* MGLTViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLTViewController.m; sourceTree = SOURCE_ROOT; }; DD043361196DBBD500E6F39D /* MGLTViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLTViewController.h; sourceTree = SOURCE_ROOT; }; DD043362196DBBD500E6F39D /* MGLTAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLTAppDelegate.h; sourceTree = SOURCE_ROOT; }; DD043365196DBBE000E6F39D /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = SOURCE_ROOT; }; DD043367196DBCC200E6F39D /* App-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "App-Info.plist"; sourceTree = SOURCE_ROOT; }; - DD1A9EA7199BEA0D007BC651 /* libc++.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libc++.dylib"; path = "usr/lib/libc++.dylib"; sourceTree = SDKROOT; }; - DD61240019CCF06E006845B1 /* MGLMapView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MGLMapView.h; path = ../dist/static/Headers/MGLMapView.h; sourceTree = SOURCE_ROOT; }; - DD61240119CCF06E006845B1 /* MGLStyleFunctionValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MGLStyleFunctionValue.h; path = ../dist/static/Headers/MGLStyleFunctionValue.h; sourceTree = SOURCE_ROOT; }; - DD61240219CCF06E006845B1 /* MGLTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MGLTypes.h; path = ../dist/static/Headers/MGLTypes.h; sourceTree = SOURCE_ROOT; }; - DD61240319CCF06E006845B1 /* NSArray+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSArray+MGLAdditions.h"; path = "../dist/static/Headers/NSArray+MGLAdditions.h"; sourceTree = SOURCE_ROOT; }; - DD61240419CCF06E006845B1 /* NSDictionary+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSDictionary+MGLAdditions.h"; path = "../dist/static/Headers/NSDictionary+MGLAdditions.h"; sourceTree = SOURCE_ROOT; }; - DD61240519CCF06E006845B1 /* UIColor+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIColor+MGLAdditions.h"; path = "../dist/static/Headers/UIColor+MGLAdditions.h"; sourceTree = SOURCE_ROOT; }; - DD61240619CCF06E006845B1 /* libMapboxGL.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libMapboxGL.a; path = ../dist/static/libMapboxGL.a; sourceTree = SOURCE_ROOT; }; - DD61240719CCF06E006845B1 /* MapboxGL.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; name = MapboxGL.bundle; path = ../dist/static/MapboxGL.bundle; sourceTree = SOURCE_ROOT; }; - DD8A790C196DC0A900FAD883 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; - DD8A790E196DC0AD00FAD883 /* GLKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GLKit.framework; path = System/Library/Frameworks/GLKit.framework; sourceTree = SDKROOT; }; - DD8A7910196DC0BB00FAD883 /* CoreLocation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreLocation.framework; path = System/Library/Frameworks/CoreLocation.framework; sourceTree = SDKROOT; }; - DD96917819F1C08400729E7D /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; }; - DD96918019F1C09200729E7D /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; + DD0580E71ACB628200B112C9 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/Frameworks/IOKit.framework; sourceTree = DEVELOPER_DIR; }; + DD0580EF1ACB62BE00B112C9 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + DD0581031ACB661200B112C9 /* Headers */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Headers; path = ../../build/ios/pkg/static/Headers; sourceTree = SOURCE_ROOT; }; + DD0581051ACB661C00B112C9 /* MapboxGL.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; name = MapboxGL.bundle; path = ../../build/ios/pkg/static/MapboxGL.bundle; sourceTree = SOURCE_ROOT; }; + DD0581071ACB663200B112C9 /* libMapboxGL.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libMapboxGL.a; path = ../../build/ios/pkg/static/libMapboxGL.a; sourceTree = SOURCE_ROOT; }; + DD41CE061ACB5DB300FA7979 /* libMapboxGL.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libMapboxGL.a; path = ../../build/ios/pkg/static/libMapboxGL.a; sourceTree = ""; }; + DD41CE081ACB5DBC00FA7979 /* CoreTelephony.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreTelephony.framework; path = System/Library/Frameworks/CoreTelephony.framework; sourceTree = SDKROOT; }; + DD41CE0A1ACB5DC400FA7979 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; + DD41CE0C1ACB5DCB00FA7979 /* libc++.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libc++.dylib"; path = "usr/lib/libc++.dylib"; sourceTree = SDKROOT; }; + DD41CE0E1ACB5DD000FA7979 /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; }; + DD41CE101ACB5DD500FA7979 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; + DD41CE121ACB5DDA00FA7979 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; }; + DD41CE141ACB5DE000FA7979 /* ImageIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ImageIO.framework; path = System/Library/Frameworks/ImageIO.framework; sourceTree = SDKROOT; }; + DD41CE161ACB5DE700FA7979 /* GLKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GLKit.framework; path = System/Library/Frameworks/GLKit.framework; sourceTree = SDKROOT; }; DDBD013A196DC3AE0033959E /* KIF.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = KIF.xcodeproj; path = KIF/KIF.xcodeproj; sourceTree = SOURCE_ROOT; }; DDBD0152196DC3D70033959E /* Test Bundle.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Test Bundle.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; - DDBD0153196DC3D70033959E /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; DDBD0165196DC4560033959E /* Bundle-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Bundle-Info.plist"; sourceTree = SOURCE_ROOT; }; DDBD0168196DC4740033959E /* MapViewTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MapViewTests.m; sourceTree = SOURCE_ROOT; }; - DDBD0169196DC4740033959E /* MapViewTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MapViewTests.h; sourceTree = SOURCE_ROOT; }; DDBD016A196DC4740033959E /* KIFTestActor+MapboxGL.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "KIFTestActor+MapboxGL.m"; sourceTree = SOURCE_ROOT; }; DDBD016B196DC4740033959E /* KIFTestActor+MapboxGL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "KIFTestActor+MapboxGL.h"; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ @@ -115,16 +107,15 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - DD043329196DB9BC00E6F39D /* CoreGraphics.framework in Frameworks */, - DD8A7911196DC0BB00FAD883 /* CoreLocation.framework in Frameworks */, - DD043327196DB9BC00E6F39D /* Foundation.framework in Frameworks */, - DD8A790F196DC0AD00FAD883 /* GLKit.framework in Frameworks */, - DD96918119F1C09200729E7D /* SystemConfiguration.framework in Frameworks */, - DD04332B196DB9BC00E6F39D /* UIKit.framework in Frameworks */, - DD61240819CCF06E006845B1 /* libMapboxGL.a in Frameworks */, - DD1A9EA8199BEA0D007BC651 /* libc++.dylib in Frameworks */, - DD96917919F1C08400729E7D /* libsqlite3.dylib in Frameworks */, - DD8A790D196DC0A900FAD883 /* libz.dylib in Frameworks */, + DD41CE091ACB5DBC00FA7979 /* CoreTelephony.framework in Frameworks */, + DD41CE171ACB5DE700FA7979 /* GLKit.framework in Frameworks */, + DD41CE151ACB5DE000FA7979 /* ImageIO.framework in Frameworks */, + DD41CE131ACB5DDA00FA7979 /* MobileCoreServices.framework in Frameworks */, + DD41CE0B1ACB5DC400FA7979 /* SystemConfiguration.framework in Frameworks */, + DD0581081ACB663200B112C9 /* libMapboxGL.a in Frameworks */, + DD41CE0D1ACB5DCB00FA7979 /* libc++.dylib in Frameworks */, + DD41CE0F1ACB5DD000FA7979 /* libsqlite3.dylib in Frameworks */, + DD41CE111ACB5DD500FA7979 /* libz.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -132,10 +123,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - DDBD016F196DC4A90033959E /* CoreGraphics.framework in Frameworks */, - DDBD0155196DC3D70033959E /* Foundation.framework in Frameworks */, - DDBD0156196DC3D70033959E /* UIKit.framework in Frameworks */, - DDBD0154196DC3D70033959E /* XCTest.framework in Frameworks */, + DD0580E81ACB628200B112C9 /* IOKit.framework in Frameworks */, DDBD016E196DC4A10033959E /* libKIF.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -165,16 +153,17 @@ DD043325196DB9BC00E6F39D /* Frameworks */ = { isa = PBXGroup; children = ( - DD96918019F1C09200729E7D /* SystemConfiguration.framework */, - DD96917819F1C08400729E7D /* libsqlite3.dylib */, - DD043328196DB9BC00E6F39D /* CoreGraphics.framework */, - DD8A7910196DC0BB00FAD883 /* CoreLocation.framework */, - DD043326196DB9BC00E6F39D /* Foundation.framework */, - DD8A790E196DC0AD00FAD883 /* GLKit.framework */, - DD04332A196DB9BC00E6F39D /* UIKit.framework */, - DDBD0153196DC3D70033959E /* XCTest.framework */, - DD1A9EA7199BEA0D007BC651 /* libc++.dylib */, - DD8A790C196DC0A900FAD883 /* libz.dylib */, + DD0580EF1ACB62BE00B112C9 /* CoreGraphics.framework */, + DD41CE081ACB5DBC00FA7979 /* CoreTelephony.framework */, + DD41CE161ACB5DE700FA7979 /* GLKit.framework */, + DD0580E71ACB628200B112C9 /* IOKit.framework */, + DD41CE141ACB5DE000FA7979 /* ImageIO.framework */, + DD41CE121ACB5DDA00FA7979 /* MobileCoreServices.framework */, + DD41CE0A1ACB5DC400FA7979 /* SystemConfiguration.framework */, + DD41CE061ACB5DB300FA7979 /* libMapboxGL.a */, + DD41CE0C1ACB5DCB00FA7979 /* libc++.dylib */, + DD41CE0E1ACB5DD000FA7979 /* libsqlite3.dylib */, + DD41CE101ACB5DD500FA7979 /* libz.dylib */, ); name = Frameworks; sourceTree = ""; @@ -186,7 +175,7 @@ DD04335F196DBBD500E6F39D /* MGLTAppDelegate.m */, DD043361196DBBD500E6F39D /* MGLTViewController.h */, DD043360196DBBD500E6F39D /* MGLTViewController.m */, - DD8A77AD196DBFDA00FAD883 /* GL Library */, + DDAE739B1ACB557500E1A793 /* GL Library */, DD04332D196DB9BC00E6F39D /* Supporting Files */, ); name = App; @@ -202,26 +191,12 @@ name = "Supporting Files"; sourceTree = ""; }; - DD6123FF19CCF06E006845B1 /* Headers */ = { + DDAE739B1ACB557500E1A793 /* GL Library */ = { isa = PBXGroup; children = ( - DD61240019CCF06E006845B1 /* MGLMapView.h */, - DD61240119CCF06E006845B1 /* MGLStyleFunctionValue.h */, - DD61240219CCF06E006845B1 /* MGLTypes.h */, - DD61240319CCF06E006845B1 /* NSArray+MGLAdditions.h */, - DD61240419CCF06E006845B1 /* NSDictionary+MGLAdditions.h */, - DD61240519CCF06E006845B1 /* UIColor+MGLAdditions.h */, - ); - name = Headers; - path = ../../dist/static/Headers; - sourceTree = SOURCE_ROOT; - }; - DD8A77AD196DBFDA00FAD883 /* GL Library */ = { - isa = PBXGroup; - children = ( - DD6123FF19CCF06E006845B1 /* Headers */, - DD61240619CCF06E006845B1 /* libMapboxGL.a */, - DD61240719CCF06E006845B1 /* MapboxGL.bundle */, + DD0581031ACB661200B112C9 /* Headers */, + DD0581071ACB663200B112C9 /* libMapboxGL.a */, + DD0581051ACB661C00B112C9 /* MapboxGL.bundle */, ); name = "GL Library"; sourceTree = ""; @@ -231,7 +206,6 @@ children = ( DDBD016B196DC4740033959E /* KIFTestActor+MapboxGL.h */, DDBD016A196DC4740033959E /* KIFTestActor+MapboxGL.m */, - DDBD0169196DC4740033959E /* MapViewTests.h */, DDBD0168196DC4740033959E /* MapViewTests.m */, DDBD0167196DC46B0033959E /* Supporting Files */, DDBD014D196DC3B00033959E /* KIF */, @@ -313,7 +287,7 @@ isa = PBXProject; attributes = { CLASSPREFIX = MGLT; - LastUpgradeCheck = 0510; + LastUpgradeCheck = 0620; ORGANIZATIONNAME = Mapbox; TargetAttributes = { DDBD0151196DC3D70033959E = { @@ -389,7 +363,8 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - DD61240919CCF06E006845B1 /* MapboxGL.bundle in Resources */, + DD0581041ACB661200B112C9 /* Headers in Resources */, + DD0581061ACB661C00B112C9 /* MapboxGL.bundle in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -407,9 +382,9 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - DD043364196DBBD500E6F39D /* MGLTViewController.m in Sources */, DD043366196DBBE000E6F39D /* main.m in Sources */, DD043363196DBBD500E6F39D /* MGLTAppDelegate.m in Sources */, + DD043364196DBBD500E6F39D /* MGLTViewController.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -508,26 +483,20 @@ DD043359196DB9BC00E6F39D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = ( - armv7, - armv7s, - arm64, - i386, - x86_64, - ); ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; HEADER_SEARCH_PATHS = ( "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, - ../dist/static/Headers, + "../../build/ios/pkg/static/**", ); INFOPLIST_FILE = "$(SRCROOT)/App-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 7.0; LIBRARY_SEARCH_PATHS = ( "$(inherited)", - ../dist/static, + ../../build/ios/pkg/static, ); + OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; TARGETED_DEVICE_FAMILY = "1,2"; WRAPPER_EXTENSION = app; @@ -537,26 +506,20 @@ DD04335A196DB9BC00E6F39D /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = ( - armv7, - armv7s, - arm64, - i386, - x86_64, - ); ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; HEADER_SEARCH_PATHS = ( "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, - ../dist/static/Headers, + "../../build/ios/pkg/static/**", ); INFOPLIST_FILE = "$(SRCROOT)/App-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 7.0; LIBRARY_SEARCH_PATHS = ( "$(inherited)", - ../dist/static, + ../../build/ios/pkg/static, ); + OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; TARGETED_DEVICE_FAMILY = "1,2"; WRAPPER_EXTENSION = app; @@ -571,6 +534,7 @@ "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", "$(DEVELOPER_FRAMEWORKS_DIR)", + "$(DEVELOPER_DIR)/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/Frameworks", ); GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -580,7 +544,7 @@ HEADER_SEARCH_PATHS = ( "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, - ../dist/static/Headers, + "../../build/ios/pkg/static/**", ); INFOPLIST_FILE = "Bundle-Info.plist"; OTHER_LDFLAGS = ( @@ -603,12 +567,13 @@ "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", "$(DEVELOPER_FRAMEWORKS_DIR)", + "$(DEVELOPER_DIR)/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/Frameworks", ); GCC_PREPROCESSOR_DEFINITIONS = "KIF_XCTEST=1"; HEADER_SEARCH_PATHS = ( "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, - ../dist/static/Headers, + "../../build/ios/pkg/static/**", ); INFOPLIST_FILE = "Bundle-Info.plist"; OTHER_LDFLAGS = ( diff --git a/test/ios/ios-tests.xcodeproj/project.xcworkspace/xcshareddata/ios-tests.xccheckout b/test/ios/ios-tests.xcodeproj/project.xcworkspace/xcshareddata/ios-tests.xccheckout index 8f3ca408b..e2f98de8f 100644 --- a/test/ios/ios-tests.xcodeproj/project.xcworkspace/xcshareddata/ios-tests.xccheckout +++ b/test/ios/ios-tests.xcodeproj/project.xcworkspace/xcshareddata/ios-tests.xccheckout @@ -14,26 +14,22 @@ https://github.com/mapbox/KIF.git 7E68CB584078A487C0535CC191D3B7551EEE2095 github.com:mapbox/mapbox-gl-native.git - FC967DACF69B3B67E6F2E9FBE56B64B73B118AFF - github.com:mapbox/mapbox-gl-cocoa.git IDESourceControlProjectPath - test/ios-tests.xcodeproj + test/ios/ios-tests.xcodeproj IDESourceControlProjectRelativeInstallPathDictionary 10265E242415D473A6A613214DB7AC3EE3D43F93 - ../../..test/KIF/ + ../../../..test/ios/KIF 7E68CB584078A487C0535CC191D3B7551EEE2095 - ../../../../.. - FC967DACF69B3B67E6F2E9FBE56B64B73B118AFF - ../../.. + ../../../.. IDESourceControlProjectURL - github.com:mapbox/mapbox-gl-cocoa.git + github.com:mapbox/mapbox-gl-native.git IDESourceControlProjectVersion 111 IDESourceControlProjectWCCIdentifier - FC967DACF69B3B67E6F2E9FBE56B64B73B118AFF + 7E68CB584078A487C0535CC191D3B7551EEE2095 IDESourceControlProjectWCConfigurations @@ -42,7 +38,7 @@ IDESourceControlWCCIdentifierKey 7E68CB584078A487C0535CC191D3B7551EEE2095 IDESourceControlWCCName - .. + gl-native IDESourceControlRepositoryExtensionIdentifierKey @@ -52,14 +48,6 @@ IDESourceControlWCCName KIF - - IDESourceControlRepositoryExtensionIdentifierKey - public.vcs.git - IDESourceControlWCCIdentifierKey - FC967DACF69B3B67E6F2E9FBE56B64B73B118AFF - IDESourceControlWCCName - mapbox-gl-cocoa - diff --git a/test/ios/ios-tests.xcodeproj/xcshareddata/xcschemes/Mapbox GL Tests.xcscheme b/test/ios/ios-tests.xcodeproj/xcshareddata/xcschemes/Mapbox GL Tests.xcscheme index f3c2bd7ff..911f949fa 100644 --- a/test/ios/ios-tests.xcodeproj/xcshareddata/xcschemes/Mapbox GL Tests.xcscheme +++ b/test/ios/ios-tests.xcodeproj/xcshareddata/xcschemes/Mapbox GL Tests.xcscheme @@ -1,6 +1,6 @@ + + + + @@ -72,7 +77,8 @@ ignoresPersistentStateOnLaunch = "NO" debugDocumentVersioning = "YES" allowLocationSimulation = "YES"> - + - +