summaryrefslogtreecommitdiff
path: root/platform/macos
diff options
context:
space:
mode:
Diffstat (limited to 'platform/macos')
-rw-r--r--platform/macos/config.cmake2
-rw-r--r--platform/macos/macos.xcodeproj/project.pbxproj16
-rw-r--r--platform/macos/sdk-files.json4
-rw-r--r--platform/macos/src/MGLMapView+Impl.h43
-rw-r--r--platform/macos/src/MGLMapView+Impl.mm96
-rw-r--r--platform/macos/src/MGLMapView+OpenGL.h45
-rw-r--r--platform/macos/src/MGLMapView+OpenGL.mm89
-rw-r--r--platform/macos/src/MGLMapView.mm207
-rw-r--r--platform/macos/src/MGLMapViewDelegate.h2
-rw-r--r--platform/macos/src/MGLMapView_Private.h33
-rw-r--r--platform/macos/test/MGLMapViewDelegateIntegrationTests.swift2
11 files changed, 339 insertions, 200 deletions
diff --git a/platform/macos/config.cmake b/platform/macos/config.cmake
index 0e1e6be412..0394d3880a 100644
--- a/platform/macos/config.cmake
+++ b/platform/macos/config.cmake
@@ -10,7 +10,7 @@ macro(mbgl_platform_core)
target_add_mason_package(mbgl-core PUBLIC swiftshader)
else()
target_sources(mbgl-core
- PRIVATE platform/darwin/src/headless_backend_cgl.cpp
+ PRIVATE platform/darwin/src/headless_backend_cgl.mm
)
target_link_libraries(mbgl-core
PUBLIC "-framework OpenGL"
diff --git a/platform/macos/macos.xcodeproj/project.pbxproj b/platform/macos/macos.xcodeproj/project.pbxproj
index 91ed2f4cfa..d2d367d7bb 100644
--- a/platform/macos/macos.xcodeproj/project.pbxproj
+++ b/platform/macos/macos.xcodeproj/project.pbxproj
@@ -95,6 +95,10 @@
556660D61E1D07E400E2C41B /* MGLVersionNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = 556660D51E1D07E400E2C41B /* MGLVersionNumber.m */; };
558DE7A61E56161C00C7916D /* MGLFoundation_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 558DE7A41E56161C00C7916D /* MGLFoundation_Private.h */; };
558DE7A71E56161C00C7916D /* MGLFoundation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 558DE7A51E56161C00C7916D /* MGLFoundation.mm */; };
+ 5591AC6A2298361600FF9ADF /* MGLMapView+Impl.h in Headers */ = {isa = PBXBuildFile; fileRef = 5591AC682298361600FF9ADF /* MGLMapView+Impl.h */; };
+ 5591AC6B2298361600FF9ADF /* MGLMapView+Impl.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5591AC692298361600FF9ADF /* MGLMapView+Impl.mm */; };
+ 55CAF6322294407F00F17770 /* MGLMapView+OpenGL.h in Headers */ = {isa = PBXBuildFile; fileRef = 55CAF6312294407F00F17770 /* MGLMapView+OpenGL.h */; };
+ 55CAF6342294409B00F17770 /* MGLMapView+OpenGL.mm in Sources */ = {isa = PBXBuildFile; fileRef = 55CAF6332294409B00F17770 /* MGLMapView+OpenGL.mm */; };
55CF7533213EDADF00ED86C4 /* libicu.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 55CF7532213EDADF00ED86C4 /* libicu.a */; };
55D120A31F7906E6004B6D81 /* libmbgl-filesource.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 55D120A41F7906E6004B6D81 /* libmbgl-filesource.a */; };
55D120A51F790A0C004B6D81 /* libmbgl-filesource.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 55D120A41F7906E6004B6D81 /* libmbgl-filesource.a */; };
@@ -416,6 +420,10 @@
556660D51E1D07E400E2C41B /* MGLVersionNumber.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = MGLVersionNumber.m; path = ../../darwin/test/MGLVersionNumber.m; sourceTree = "<group>"; };
558DE7A41E56161C00C7916D /* MGLFoundation_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLFoundation_Private.h; sourceTree = "<group>"; };
558DE7A51E56161C00C7916D /* MGLFoundation.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLFoundation.mm; sourceTree = "<group>"; };
+ 5591AC682298361600FF9ADF /* MGLMapView+Impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MGLMapView+Impl.h"; sourceTree = "<group>"; };
+ 5591AC692298361600FF9ADF /* MGLMapView+Impl.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "MGLMapView+Impl.mm"; sourceTree = "<group>"; };
+ 55CAF6312294407F00F17770 /* MGLMapView+OpenGL.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MGLMapView+OpenGL.h"; sourceTree = "<group>"; };
+ 55CAF6332294409B00F17770 /* MGLMapView+OpenGL.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = "MGLMapView+OpenGL.mm"; sourceTree = "<group>"; };
55CF7532213EDADF00ED86C4 /* libicu.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libicu.a; sourceTree = BUILT_PRODUCTS_DIR; };
55D120A41F7906E6004B6D81 /* libmbgl-filesource.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = "libmbgl-filesource.a"; sourceTree = BUILT_PRODUCTS_DIR; };
55D9B4B01D005D3900C1CCE2 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
@@ -1262,6 +1270,10 @@
DAE6C3A01CC31E9400DB3429 /* MGLMapView.h */,
DAE6C3AC1CC31EF300DB3429 /* MGLMapView_Private.h */,
DAE6C3AD1CC31EF300DB3429 /* MGLMapView.mm */,
+ 5591AC682298361600FF9ADF /* MGLMapView+Impl.h */,
+ 5591AC692298361600FF9ADF /* MGLMapView+Impl.mm */,
+ 55CAF6332294409B00F17770 /* MGLMapView+OpenGL.mm */,
+ 55CAF6312294407F00F17770 /* MGLMapView+OpenGL.h */,
DAE6C3A11CC31E9400DB3429 /* MGLMapView+IBAdditions.h */,
DAE6C3AE1CC31EF300DB3429 /* MGLMapView+IBAdditions.mm */,
DAE6C3A21CC31E9400DB3429 /* MGLMapViewDelegate.h */,
@@ -1357,6 +1369,7 @@
35C5D8491D6DD66D00E95907 /* NSCompoundPredicate+MGLAdditions.h in Headers */,
9250B8C32073C69100EF338C /* MGLShapeOfflineRegion.h in Headers */,
747ABE67219B2C3200523B67 /* MGLSymbolStyleLayer_Private.h in Headers */,
+ 55CAF6322294407F00F17770 /* MGLMapView+OpenGL.h in Headers */,
DD0902B31DB1AC6400C5BDCE /* MGLNetworkConfiguration.h in Headers */,
DAE6C3621CC31E0400DB3429 /* MGLOverlay.h in Headers */,
DAE6C3651CC31E0400DB3429 /* MGLPolyline.h in Headers */,
@@ -1367,6 +1380,7 @@
DA8F25B21D51CB270010E6B5 /* NSValue+MGLStyleAttributeAdditions.h in Headers */,
55335DF9212EC542000CE5F8 /* NSImage+MGLAdditions.h in Headers */,
1F7454A31ECFB00300021D39 /* MGLLight_Private.h in Headers */,
+ 5591AC6A2298361600FF9ADF /* MGLMapView+Impl.h in Headers */,
359819591E02F611008FC139 /* NSCoder+MGLAdditions.h in Headers */,
DAE6C38E1CC31E2A00DB3429 /* MGLOfflineStorage_Private.h in Headers */,
747ABE61219B2C0000523B67 /* MGLLineStyleLayer_Private.h in Headers */,
@@ -1638,6 +1652,7 @@
1FCCEC53222EF9FE00302E3B /* MGLSDKMetricsManager.m in Sources */,
DAE6C3981CC31E2A00DB3429 /* NSBundle+MGLAdditions.m in Sources */,
DAE6C3B71CC31EF300DB3429 /* MGLMapView.mm in Sources */,
+ 55CAF6342294409B00F17770 /* MGLMapView+OpenGL.mm in Sources */,
40B77E461DB11BCD003DA2FE /* NSArray+MGLAdditions.mm in Sources */,
DAE6C38C1CC31E2A00DB3429 /* MGLOfflinePack.mm in Sources */,
35D65C5B1D65AD5500722C23 /* NSDate+MGLAdditions.mm in Sources */,
@@ -1697,6 +1712,7 @@
DAD165751CF4CD7A001FF4B9 /* MGLShapeCollection.mm in Sources */,
92FC0AE6207CDD8D007B6B54 /* MGLShapeOfflineRegion.mm in Sources */,
35C5D8481D6DD66D00E95907 /* NSComparisonPredicate+MGLAdditions.mm in Sources */,
+ 5591AC6B2298361600FF9ADF /* MGLMapView+Impl.mm in Sources */,
DA35A2AE1CCA091800E826B2 /* MGLCompassDirectionFormatter.m in Sources */,
DACA8623201920BE00E9693A /* MGLRasterDEMSource.mm in Sources */,
DA8F258C1D51CA540010E6B5 /* MGLLineStyleLayer.mm in Sources */,
diff --git a/platform/macos/sdk-files.json b/platform/macos/sdk-files.json
index 4448de1f5b..6bd767fb98 100644
--- a/platform/macos/sdk-files.json
+++ b/platform/macos/sdk-files.json
@@ -9,6 +9,7 @@
"platform/darwin/src/MGLSDKMetricsManager.m",
"platform/darwin/src/NSBundle+MGLAdditions.m",
"platform/macos/src/MGLMapView.mm",
+ "platform/macos/src/MGLMapView+OpenGL.mm",
"platform/darwin/src/NSArray+MGLAdditions.mm",
"platform/darwin/src/MGLOfflinePack.mm",
"platform/darwin/src/NSDate+MGLAdditions.mm",
@@ -68,6 +69,7 @@
"platform/darwin/src/MGLShapeCollection.mm",
"platform/darwin/src/MGLShapeOfflineRegion.mm",
"platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm",
+ "platform/macos/src/MGLMapView+Impl.mm",
"platform/darwin/src/MGLCompassDirectionFormatter.m",
"platform/darwin/src/MGLRasterDEMSource.mm",
"platform/darwin/src/MGLLineStyleLayer.mm",
@@ -177,11 +179,13 @@
"MGLNetworkConfiguration_Private.h": "platform/darwin/src/MGLNetworkConfiguration_Private.h",
"NSCompoundPredicate+MGLAdditions.h": "platform/darwin/src/NSCompoundPredicate+MGLAdditions.h",
"MGLSymbolStyleLayer_Private.h": "platform/darwin/src/MGLSymbolStyleLayer_Private.h",
+ "MGLMapView+OpenGL.h": "platform/macos/src/MGLMapView+OpenGL.h",
"NSProcessInfo+MGLAdditions.h": "platform/macos/src/NSProcessInfo+MGLAdditions.h",
"MGLRendererFrontend.h": "platform/darwin/src/MGLRendererFrontend.h",
"NSValue+MGLStyleAttributeAdditions.h": "platform/darwin/src/NSValue+MGLStyleAttributeAdditions.h",
"NSImage+MGLAdditions.h": "platform/macos/src/NSImage+MGLAdditions.h",
"MGLLight_Private.h": "platform/darwin/src/MGLLight_Private.h",
+ "MGLMapView+Impl.h": "platform/macos/src/MGLMapView+Impl.h",
"NSCoder+MGLAdditions.h": "platform/darwin/src/NSCoder+MGLAdditions.h",
"MGLOfflineStorage_Private.h": "platform/darwin/src/MGLOfflineStorage_Private.h",
"MGLLineStyleLayer_Private.h": "platform/darwin/src/MGLLineStyleLayer_Private.h",
diff --git a/platform/macos/src/MGLMapView+Impl.h b/platform/macos/src/MGLMapView+Impl.h
new file mode 100644
index 0000000000..19583c17e5
--- /dev/null
+++ b/platform/macos/src/MGLMapView+Impl.h
@@ -0,0 +1,43 @@
+#import <mbgl/gfx/renderer_backend.hpp>
+#import <mbgl/map/map_observer.hpp>
+#import <mbgl/util/image.hpp>
+
+@class MGLMapView;
+
+typedef struct _CGLContextObject* CGLContextObj;
+
+class MGLMapViewImpl : public mbgl::MapObserver {
+public:
+ static std::unique_ptr<MGLMapViewImpl> Create(MGLMapView*);
+
+ MGLMapViewImpl(MGLMapView*);
+ virtual ~MGLMapViewImpl() = default;
+
+ virtual mbgl::gfx::RendererBackend& getRendererBackend() = 0;
+
+ // We need a static image of what was rendered for printing.
+ virtual mbgl::PremultipliedImage readStillImage() = 0;
+
+ virtual CGLContextObj getCGLContextObj() {
+ return nullptr;
+ }
+
+ // mbgl::MapObserver implementation
+ void onCameraWillChange(mbgl::MapObserver::CameraChangeMode) override;
+ void onCameraIsChanging() override;
+ void onCameraDidChange(mbgl::MapObserver::CameraChangeMode) override;
+ void onWillStartLoadingMap() override;
+ void onDidFinishLoadingMap() override;
+ void onDidFailLoadingMap(mbgl::MapLoadError mapError, const std::string& what) override;
+ void onWillStartRenderingFrame() override;
+ void onDidFinishRenderingFrame(mbgl::MapObserver::RenderMode) override;
+ void onWillStartRenderingMap() override;
+ void onDidFinishRenderingMap(mbgl::MapObserver::RenderMode) override;
+ void onDidFinishLoadingStyle() override;
+ void onSourceChanged(mbgl::style::Source& source) override;
+ void onDidBecomeIdle() override;
+
+protected:
+ /// Cocoa map view that this adapter bridges to.
+ __weak MGLMapView *mapView = nullptr;
+};
diff --git a/platform/macos/src/MGLMapView+Impl.mm b/platform/macos/src/MGLMapView+Impl.mm
new file mode 100644
index 0000000000..7be5545671
--- /dev/null
+++ b/platform/macos/src/MGLMapView+Impl.mm
@@ -0,0 +1,96 @@
+#import "MGLMapView+Impl.h"
+#import "MGLMapView+OpenGL.h"
+#import "MGLStyle_Private.h"
+#import "NSBundle+MGLAdditions.h"
+
+#include <mbgl/map/map.hpp>
+#include <mbgl/style/style.hpp>
+
+std::unique_ptr<MGLMapViewImpl> MGLMapViewImpl::Create(MGLMapView* nativeView) {
+ return std::make_unique<MGLMapViewOpenGLImpl>(nativeView);
+}
+
+MGLMapViewImpl::MGLMapViewImpl(MGLMapView* nativeView_) : mapView(nativeView_) {
+}
+
+void MGLMapViewImpl::onCameraWillChange(mbgl::MapObserver::CameraChangeMode mode) {
+ bool animated = mode == mbgl::MapObserver::CameraChangeMode::Animated;
+ [mapView cameraWillChangeAnimated:animated];
+}
+
+void MGLMapViewImpl::onCameraIsChanging() {
+ [mapView cameraIsChanging];
+}
+
+void MGLMapViewImpl::onCameraDidChange(mbgl::MapObserver::CameraChangeMode mode) {
+ bool animated = mode == mbgl::MapObserver::CameraChangeMode::Animated;
+ [mapView cameraDidChangeAnimated:animated];
+}
+
+void MGLMapViewImpl::onWillStartLoadingMap() {
+ [mapView mapViewWillStartLoadingMap];
+}
+
+void MGLMapViewImpl::onDidFinishLoadingMap() {
+ [mapView mapViewDidFinishLoadingMap];
+}
+
+void MGLMapViewImpl::onDidFailLoadingMap(mbgl::MapLoadError mapError, const std::string& what) {
+ NSString *description;
+ MGLErrorCode code;
+ switch (mapError) {
+ case mbgl::MapLoadError::StyleParseError:
+ code = MGLErrorCodeParseStyleFailed;
+ description = NSLocalizedStringWithDefaultValue(@"PARSE_STYLE_FAILED_DESC", nil, nil, @"The map failed to load because the style is corrupted.", @"User-friendly error description");
+ break;
+ case mbgl::MapLoadError::StyleLoadError:
+ code = MGLErrorCodeLoadStyleFailed;
+ description = NSLocalizedStringWithDefaultValue(@"LOAD_STYLE_FAILED_DESC", nil, nil, @"The map failed to load because the style can't be loaded.", @"User-friendly error description");
+ break;
+ case mbgl::MapLoadError::NotFoundError:
+ code = MGLErrorCodeNotFound;
+ description = NSLocalizedStringWithDefaultValue(@"STYLE_NOT_FOUND_DESC", nil, nil, @"The map failed to load because the style can’t be found or is incompatible.", @"User-friendly error description");
+ break;
+ default:
+ code = MGLErrorCodeUnknown;
+ description = NSLocalizedStringWithDefaultValue(@"LOAD_MAP_FAILED_DESC", nil, nil, @"The map failed to load because an unknown error occurred.", @"User-friendly error description");
+ }
+ NSDictionary *userInfo = @{
+ NSLocalizedDescriptionKey: description,
+ NSLocalizedFailureReasonErrorKey: @(what.c_str()),
+ };
+ NSError *error = [NSError errorWithDomain:MGLErrorDomain code:code userInfo:userInfo];
+ [mapView mapViewDidFailLoadingMapWithError:error];
+}
+
+void MGLMapViewImpl::onWillStartRenderingFrame() {
+ [mapView mapViewWillStartRenderingFrame];
+}
+
+void MGLMapViewImpl::onDidFinishRenderingFrame(mbgl::MapObserver::RenderMode mode) {
+ bool fullyRendered = mode == mbgl::MapObserver::RenderMode::Full;
+ [mapView mapViewDidFinishRenderingFrameFullyRendered:fullyRendered];
+}
+
+void MGLMapViewImpl::onWillStartRenderingMap() {
+ [mapView mapViewWillStartRenderingMap];
+}
+
+void MGLMapViewImpl::onDidFinishRenderingMap(mbgl::MapObserver::RenderMode mode) {
+ bool fullyRendered = mode == mbgl::MapObserver::RenderMode::Full;
+ [mapView mapViewDidFinishRenderingMapFullyRendered:fullyRendered];
+}
+
+void MGLMapViewImpl::onDidBecomeIdle() {
+ [mapView mapViewDidBecomeIdle];
+}
+
+void MGLMapViewImpl::onDidFinishLoadingStyle() {
+ [mapView mapViewDidFinishLoadingStyle];
+}
+
+void MGLMapViewImpl::onSourceChanged(mbgl::style::Source& source) {
+ NSString *identifier = @(source.getID().c_str());
+ MGLSource * nativeSource = [mapView.style sourceWithIdentifier:identifier];
+ [mapView sourceDidChange:nativeSource];
+}
diff --git a/platform/macos/src/MGLMapView+OpenGL.h b/platform/macos/src/MGLMapView+OpenGL.h
new file mode 100644
index 0000000000..d4c6a448cd
--- /dev/null
+++ b/platform/macos/src/MGLMapView+OpenGL.h
@@ -0,0 +1,45 @@
+#import "MGLMapView+Impl.h"
+#import "MGLMapView_Private.h"
+
+#include <mbgl/gfx/renderable.hpp>
+#include <mbgl/gl/renderer_backend.hpp>
+
+/// Adapter responsible for bridging calls from mbgl to MGLMapView and Cocoa.
+class MGLMapViewOpenGLImpl final : public MGLMapViewImpl,
+ public mbgl::gl::RendererBackend,
+ public mbgl::gfx::Renderable {
+public:
+ MGLMapViewOpenGLImpl(MGLMapView*);
+ ~MGLMapViewOpenGLImpl() override = default;
+
+public:
+ void restoreFramebufferBinding();
+
+ // Implementation of mbgl::gfx::RendererBackend
+public:
+ mbgl::gfx::Renderable& getDefaultRenderable() override {
+ return *this;
+ }
+
+private:
+ void activate() override;
+ void deactivate() override;
+ // End implementation of mbgl::gfx::RendererBackend
+
+ // Implementation of mbgl::gl::RendererBackend
+public:
+ void updateAssumedState() override;
+
+private:
+ mbgl::gl::ProcAddress getExtensionFunctionPointer(const char* name) override;
+ // End implementation of mbgl::gl::Rendererbackend
+
+ // Implementation of MGLMapViewImpl
+public:
+ mbgl::gfx::RendererBackend& getRendererBackend() override {
+ return *this;
+ }
+
+ mbgl::PremultipliedImage readStillImage() override;
+ CGLContextObj getCGLContextObj() override;
+};
diff --git a/platform/macos/src/MGLMapView+OpenGL.mm b/platform/macos/src/MGLMapView+OpenGL.mm
new file mode 100644
index 0000000000..f6168a4b80
--- /dev/null
+++ b/platform/macos/src/MGLMapView+OpenGL.mm
@@ -0,0 +1,89 @@
+#import "MGLMapView+OpenGL.h"
+#import "MGLOpenGLLayer.h"
+
+#include <mbgl/gl/renderable_resource.hpp>
+
+#import <OpenGL/gl.h>
+
+class MGLMapViewOpenGLRenderableResource final : public mbgl::gl::RenderableResource {
+public:
+ MGLMapViewOpenGLRenderableResource(MGLMapViewOpenGLImpl& backend_) : backend(backend_) {
+ }
+
+ void bind() override {
+ backend.restoreFramebufferBinding();
+ }
+
+private:
+ MGLMapViewOpenGLImpl& backend;
+
+public:
+ // The current framebuffer of the NSOpenGLLayer we are painting to.
+ GLint fbo = 0;
+
+ // The reference counted count of activation calls
+ NSUInteger activationCount = 0;
+};
+
+MGLMapViewOpenGLImpl::MGLMapViewOpenGLImpl(MGLMapView* nativeView_)
+ : MGLMapViewImpl(nativeView_),
+ mbgl::gl::RendererBackend(mbgl::gfx::ContextMode::Unique),
+ mbgl::gfx::Renderable(mapView.framebufferSize,
+ std::make_unique<MGLMapViewOpenGLRenderableResource>(*this)) {
+
+ // Install the OpenGL layer. Interface Builder’s synchronous drawing means
+ // we can’t display a map, so don’t even bother to have a map layer.
+ mapView.layer =
+ mapView.isTargetingInterfaceBuilder ? [CALayer layer] : [MGLOpenGLLayer layer];
+}
+
+mbgl::gl::ProcAddress MGLMapViewOpenGLImpl::getExtensionFunctionPointer(const char* name) {
+ static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
+ if (!framework) {
+ throw std::runtime_error("Failed to load OpenGL framework.");
+ }
+
+ return reinterpret_cast<mbgl::gl::ProcAddress>(CFBundleGetFunctionPointerForName(
+ framework, (__bridge CFStringRef)[NSString stringWithUTF8String:name]));
+}
+
+void MGLMapViewOpenGLImpl::activate() {
+ auto& resource = getResource<MGLMapViewOpenGLRenderableResource>();
+ if (resource.activationCount++) {
+ return;
+ }
+
+ MGLOpenGLLayer* layer = (MGLOpenGLLayer*)mapView.layer;
+ [layer.openGLContext makeCurrentContext];
+}
+
+void MGLMapViewOpenGLImpl::deactivate() {
+ auto& resource = getResource<MGLMapViewOpenGLRenderableResource>();
+ if (--resource.activationCount) {
+ return;
+ }
+
+ [NSOpenGLContext clearCurrentContext];
+}
+
+void MGLMapViewOpenGLImpl::updateAssumedState() {
+ auto& resource = getResource<MGLMapViewOpenGLRenderableResource>();
+ glGetIntegerv(GL_FRAMEBUFFER_BINDING, &resource.fbo);
+ assumeFramebufferBinding(resource.fbo);
+ assumeViewport(0, 0, mapView.framebufferSize);
+}
+
+void MGLMapViewOpenGLImpl::restoreFramebufferBinding() {
+ auto& resource = getResource<MGLMapViewOpenGLRenderableResource>();
+ setFramebufferBinding(resource.fbo);
+ setViewport(0, 0, mapView.framebufferSize);
+}
+
+mbgl::PremultipliedImage MGLMapViewOpenGLImpl::readStillImage() {
+ return readFramebuffer(mapView.framebufferSize);
+}
+
+CGLContextObj MGLMapViewOpenGLImpl::getCGLContextObj() {
+ MGLOpenGLLayer* layer = (MGLOpenGLLayer*)mapView.layer;
+ return layer.openGLContext.CGLContextObj;
+}
diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm
index 77eb300aef..589a39f0b3 100644
--- a/platform/macos/src/MGLMapView.mm
+++ b/platform/macos/src/MGLMapView.mm
@@ -2,7 +2,6 @@
#import "MGLAttributionButton.h"
#import "MGLCompassCell.h"
-#import "MGLOpenGLLayer.h"
#import "MGLStyle.h"
#import "MGLRendererFrontend.h"
#import "MGLRendererConfiguration.h"
@@ -33,8 +32,6 @@
#import <mbgl/storage/reachability.h>
#import <mbgl/style/image.hpp>
#import <mbgl/renderer/renderer.hpp>
-#import <mbgl/gl/renderer_backend.hpp>
-#import <mbgl/gl/renderable_resource.hpp>
#import <mbgl/storage/network_status.hpp>
#import <mbgl/storage/resource_options.hpp>
#import <mbgl/math/wrap.hpp>
@@ -49,6 +46,7 @@
#import <unordered_map>
#import <unordered_set>
+#import "MGLMapView+Impl.h"
#import "NSBundle+MGLAdditions.h"
#import "NSDate+MGLAdditions.h"
#import "NSProcessInfo+MGLAdditions.h"
@@ -60,10 +58,6 @@
#import "NSPredicate+MGLPrivateAdditions.h"
#import "MGLLoggingConfiguration_Private.h"
-#import <QuartzCore/QuartzCore.h>
-#import <OpenGL/gl.h>
-
-class MGLMapViewImpl;
class MGLAnnotationContext;
/// Distance from the edge of the view to ornament views (logo, attribution, etc.).
@@ -160,7 +154,7 @@ public:
@implementation MGLMapView {
/// Cross-platform map view controller.
mbgl::Map *_mbglMap;
- MGLMapViewImpl *_mbglView;
+ std::unique_ptr<MGLMapViewImpl> _mbglView;
std::unique_ptr<MGLRenderFrontend> _rendererFrontend;
NSPanGestureRecognizer *_panGestureRecognizer;
@@ -267,7 +261,7 @@ public:
_isTargetingInterfaceBuilder = NSProcessInfo.processInfo.mgl_isInterfaceBuilderDesignablesAgent;
// Set up cross-platform controllers and resources.
- _mbglView = new MGLMapViewImpl(self);
+ _mbglView = MGLMapViewImpl::Create(self);
// Delete the pre-offline ambient cache at
// ~/Library/Caches/com.mapbox.MapboxGL/cache.db.
@@ -282,9 +276,9 @@ public:
MGLRendererConfiguration *config = [MGLRendererConfiguration currentConfiguration];
- auto renderer = std::make_unique<mbgl::Renderer>(*_mbglView, config.scaleFactor, config.cacheDir, config.localFontFamilyName);
+ auto renderer = std::make_unique<mbgl::Renderer>(_mbglView->getRendererBackend(), config.scaleFactor, config.cacheDir, config.localFontFamilyName);
BOOL enableCrossSourceCollisions = !config.perSourceCollisions;
- _rendererFrontend = std::make_unique<MGLRenderFrontend>(std::move(renderer), self, *_mbglView, true);
+ _rendererFrontend = std::make_unique<MGLRenderFrontend>(std::move(renderer), self, _mbglView->getRendererBackend(), true);
mbgl::MapOptions mapOptions;
mapOptions.withMapMode(mbgl::MapMode::Continuous)
@@ -300,10 +294,6 @@ public:
_mbglMap = new mbgl::Map(*_rendererFrontend, *_mbglView, mapOptions, resourceOptions);
- // Install the OpenGL layer. Interface Builder’s synchronous drawing means
- // we can’t display a map, so don’t even bother to have a map layer.
- self.layer = _isTargetingInterfaceBuilder ? [CALayer layer] : [MGLOpenGLLayer layer];
-
// Notify map object when network reachability status changes.
_reachability = [MGLReachability reachabilityForInternetConnection];
_reachability.reachableBlock = ^(MGLReachability *) {
@@ -550,10 +540,7 @@ public:
delete _mbglMap;
_mbglMap = nullptr;
}
- if (_mbglView) {
- delete _mbglView;
- _mbglView = nullptr;
- }
+ _mbglView.reset();
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(__unused NSDictionary *)change context:(void *)context {
@@ -718,8 +705,7 @@ public:
}
- (CGLContextObj)context {
- MGLOpenGLLayer *layer = _isTargetingInterfaceBuilder ? nil : (MGLOpenGLLayer *)self.layer;
- return layer.openGLContext.CGLContextObj;
+ return _mbglView->getCGLContextObj();
}
- (void)setFrame:(NSRect)frame {
@@ -820,7 +806,11 @@ public:
}
}
-- (void)setNeedsGLDisplay {
+- (BOOL)isTargetingInterfaceBuilder {
+ return _isTargetingInterfaceBuilder;
+}
+
+- (void)setNeedsRerender {
MGLAssertIsMainThread();
[self.layer setNeedsDisplay];
@@ -987,7 +977,7 @@ public:
- (void)print:(__unused id)sender {
_isPrinting = YES;
- [self setNeedsGLDisplay];
+ [self setNeedsRerender];
}
- (void)printWithImage:(NSImage *)image {
@@ -3038,175 +3028,4 @@ public:
_mbglMap->setDebug(options);
}
-class MGLMapViewImpl;
-
-class MGLMapViewRenderable final : public mbgl::gl::RenderableResource {
-public:
- MGLMapViewRenderable(MGLMapViewImpl& backend_) : backend(backend_) {
- }
-
- void bind() override;
-
-private:
- MGLMapViewImpl& backend;
-};
-
-/// Adapter responsible for bridging calls from mbgl to MGLMapView and Cocoa.
-class MGLMapViewImpl : public mbgl::gl::RendererBackend,
- public mbgl::gfx::Renderable,
- public mbgl::MapObserver {
-public:
- MGLMapViewImpl(MGLMapView* nativeView_)
- : mbgl::gl::RendererBackend(mbgl::gfx::ContextMode::Unique),
- mbgl::gfx::Renderable(nativeView_.framebufferSize,
- std::make_unique<MGLMapViewRenderable>(*this)),
- nativeView(nativeView_) {
- }
-
- void onCameraWillChange(mbgl::MapObserver::CameraChangeMode mode) override {
- bool animated = mode == mbgl::MapObserver::CameraChangeMode::Animated;
- [nativeView cameraWillChangeAnimated:animated];
- }
-
- void onCameraIsChanging() override {
- [nativeView cameraIsChanging];
- }
-
- void onCameraDidChange(mbgl::MapObserver::CameraChangeMode mode) override {
- bool animated = mode == mbgl::MapObserver::CameraChangeMode::Animated;
- [nativeView cameraDidChangeAnimated:animated];
- }
-
- void onWillStartLoadingMap() override {
- [nativeView mapViewWillStartLoadingMap];
- }
-
- void onDidFinishLoadingMap() override {
- [nativeView mapViewDidFinishLoadingMap];
- }
-
- void onDidFailLoadingMap(mbgl::MapLoadError mapError, const std::string& what) override {
- NSString *description;
- MGLErrorCode code;
- switch (mapError) {
- case mbgl::MapLoadError::StyleParseError:
- code = MGLErrorCodeParseStyleFailed;
- description = NSLocalizedStringWithDefaultValue(@"PARSE_STYLE_FAILED_DESC", nil, nil, @"The map failed to load because the style is corrupted.", @"User-friendly error description");
- break;
- case mbgl::MapLoadError::StyleLoadError:
- code = MGLErrorCodeLoadStyleFailed;
- description = NSLocalizedStringWithDefaultValue(@"LOAD_STYLE_FAILED_DESC", nil, nil, @"The map failed to load because the style can't be loaded.", @"User-friendly error description");
- break;
- case mbgl::MapLoadError::NotFoundError:
- code = MGLErrorCodeNotFound;
- description = NSLocalizedStringWithDefaultValue(@"STYLE_NOT_FOUND_DESC", nil, nil, @"The map failed to load because the style can’t be found or is incompatible.", @"User-friendly error description");
- break;
- default:
- code = MGLErrorCodeUnknown;
- description = NSLocalizedStringWithDefaultValue(@"LOAD_MAP_FAILED_DESC", nil, nil, @"The map failed to load because an unknown error occurred.", @"User-friendly error description");
- }
- NSDictionary *userInfo = @{
- NSLocalizedDescriptionKey: description,
- NSLocalizedFailureReasonErrorKey: @(what.c_str()),
- };
- NSError *error = [NSError errorWithDomain:MGLErrorDomain code:code userInfo:userInfo];
- [nativeView mapViewDidFailLoadingMapWithError:error];
- }
-
- void onWillStartRenderingFrame() override {
- [nativeView mapViewWillStartRenderingFrame];
- }
-
- void onDidFinishRenderingFrame(mbgl::MapObserver::RenderMode mode) override {
- bool fullyRendered = mode == mbgl::MapObserver::RenderMode::Full;
- [nativeView mapViewDidFinishRenderingFrameFullyRendered:fullyRendered];
- }
-
- void onWillStartRenderingMap() override {
- [nativeView mapViewWillStartRenderingMap];
- }
-
- void onDidFinishRenderingMap(mbgl::MapObserver::RenderMode mode) override {
- bool fullyRendered = mode == mbgl::MapObserver::RenderMode::Full;
- [nativeView mapViewDidFinishRenderingMapFullyRendered:fullyRendered];
- }
-
- void onDidBecomeIdle() override {
- [nativeView mapViewDidBecomeIdle];
- }
-
- void onDidFinishLoadingStyle() override {
- [nativeView mapViewDidFinishLoadingStyle];
- }
-
- void onSourceChanged(mbgl::style::Source& source) override {
- NSString *identifier = @(source.getID().c_str());
- MGLSource * nativeSource = [nativeView.style sourceWithIdentifier:identifier];
- [nativeView sourceDidChange:nativeSource];
- }
-
- mbgl::gl::ProcAddress getExtensionFunctionPointer(const char* name) override {
- static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
- if (!framework) {
- throw std::runtime_error("Failed to load OpenGL framework.");
- }
-
- CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII);
- void *symbol = CFBundleGetFunctionPointerForName(framework, str);
- CFRelease(str);
-
- return reinterpret_cast<mbgl::gl::ProcAddress>(symbol);
- }
-
- mbgl::gfx::Renderable& getDefaultRenderable() override {
- return *this;
- }
-
- void activate() override {
- if (activationCount++) {
- return;
- }
-
- MGLOpenGLLayer *layer = (MGLOpenGLLayer *)nativeView.layer;
- [layer.openGLContext makeCurrentContext];
- }
-
- void deactivate() override {
- if (--activationCount) {
- return;
- }
-
- [NSOpenGLContext clearCurrentContext];
- }
-
- void updateAssumedState() override {
- glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo);
- assumeFramebufferBinding(fbo);
- assumeViewport(0, 0, nativeView.framebufferSize);
- }
-
- void restoreFramebufferBinding() {
- setFramebufferBinding(fbo);
- setViewport(0, 0, nativeView.framebufferSize);
- }
-
- mbgl::PremultipliedImage readStillImage() {
- return readFramebuffer(nativeView.framebufferSize);
- }
-
-private:
- /// Cocoa map view that this adapter bridges to.
- __weak MGLMapView *nativeView = nullptr;
-
- /// The current framebuffer of the NSOpenGLLayer we are painting to.
- GLint fbo = 0;
-
- /// The reference counted count of activation calls
- NSUInteger activationCount = 0;
-};
-
-void MGLMapViewRenderable::bind() {
- backend.restoreFramebufferBinding();
-}
-
@end
diff --git a/platform/macos/src/MGLMapViewDelegate.h b/platform/macos/src/MGLMapViewDelegate.h
index c7d6786666..1de4b47eb7 100644
--- a/platform/macos/src/MGLMapViewDelegate.h
+++ b/platform/macos/src/MGLMapViewDelegate.h
@@ -181,6 +181,8 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (void)mapView:(MGLMapView *)mapView didFinishLoadingStyle:(MGLStyle *)style;
+- (nullable NSImage *)mapView:(MGLMapView *)mapView didFailToLoadImage:(NSString *)imageName;
+
#pragma mark Managing the Appearance of Annotations
/**
diff --git a/platform/macos/src/MGLMapView_Private.h b/platform/macos/src/MGLMapView_Private.h
index 986ae1143a..afd7cf2422 100644
--- a/platform/macos/src/MGLMapView_Private.h
+++ b/platform/macos/src/MGLMapView_Private.h
@@ -1,10 +1,14 @@
#import "MGLMapView.h"
+#include <mbgl/util/size.hpp>
+
namespace mbgl {
class Map;
class Renderer;
}
+@class MGLSource;
+
@interface MGLMapView (Private)
/// True if the view or application is in a state where it is not expected to be
@@ -22,17 +26,36 @@ namespace mbgl {
/// Center longitude set independently of the center latitude in an inspectable.
@property (nonatomic) CLLocationDegrees pendingLongitude;
-/// The map view’s OpenGL rendering context.
-- (CGLContextObj)context;
+/// The map view’s OpenGL rendering context, if it is backed by an OpenGL based view.
+@property (readonly, nonatomic, nullable) CGLContextObj context;
+
+- (mbgl::Size)framebufferSize;
+
+/// Map observers
+- (void)cameraWillChangeAnimated:(BOOL)animated;
+- (void)cameraIsChanging;
+- (void)cameraDidChangeAnimated:(BOOL)animated;
+- (void)mapViewWillStartLoadingMap;
+- (void)mapViewDidFinishLoadingMap;
+- (void)mapViewDidFailLoadingMapWithError:(nonnull NSError *)error;
+- (void)mapViewWillStartRenderingFrame;
+- (void)mapViewDidFinishRenderingFrameFullyRendered:(BOOL)fullyRendered;
+- (void)mapViewWillStartRenderingMap;
+- (void)mapViewDidFinishRenderingMapFullyRendered:(BOOL)fullyRendered;
+- (void)mapViewDidBecomeIdle;
+- (void)mapViewDidFinishLoadingStyle;
+- (void)sourceDidChange:(nonnull MGLSource *)source;
/// Asynchronously render a frame of the map.
-- (void)setNeedsGLDisplay;
+- (void)setNeedsRerender;
/// Synchronously render a frame of the map.
- (void)renderSync;
-- (mbgl::Map *)mbglMap;
+- (BOOL)isTargetingInterfaceBuilder;
+
+- (nonnull mbgl::Map *)mbglMap;
-- (mbgl::Renderer *)renderer;
+- (nonnull mbgl::Renderer *)renderer;
@end
diff --git a/platform/macos/test/MGLMapViewDelegateIntegrationTests.swift b/platform/macos/test/MGLMapViewDelegateIntegrationTests.swift
index 83c7160fde..6c37017be6 100644
--- a/platform/macos/test/MGLMapViewDelegateIntegrationTests.swift
+++ b/platform/macos/test/MGLMapViewDelegateIntegrationTests.swift
@@ -28,6 +28,8 @@ extension MGLMapViewDelegateIntegrationTests: MGLMapViewDelegate {
func mapViewDidBecomeIdle(_ mapView: MGLMapView) {}
func mapViewDidFailLoadingMap(_ mapView: MGLMapView, withError error: Error) {}
+
+ func mapView(_ mapView: MGLMapView, didFailToLoadImage imageName: String) -> NSImage? { return nil }
func mapView(_ mapView: MGLMapView, shapeAnnotationIsEnabled annotation: MGLShape) -> Bool { return false }