diff options
Diffstat (limited to 'platform/macos/src/MGLMapView.mm')
-rw-r--r-- | platform/macos/src/MGLMapView.mm | 145 |
1 files changed, 87 insertions, 58 deletions
diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm index 0a567a8510..b32edffd43 100644 --- a/platform/macos/src/MGLMapView.mm +++ b/platform/macos/src/MGLMapView.mm @@ -4,6 +4,8 @@ #import "MGLCompassCell.h" #import "MGLOpenGLLayer.h" #import "MGLStyle.h" +#import "MGLRendererFrontend.h" +#import "MGLRendererConfiguration.h" #import "MGLAnnotationImage_Private.h" #import "MGLAttributionInfo_Private.h" @@ -13,6 +15,7 @@ #import "MGLMultiPoint_Private.h" #import "MGLOfflineStorage_Private.h" #import "MGLStyle_Private.h" +#import "MGLShape_Private.h" #import "MGLAccountManager.h" #import "MGLMapCamera.h" @@ -23,15 +26,15 @@ #import "MGLImageSource.h" #import <mbgl/map/map.hpp> -#import <mbgl/map/view.hpp> #import <mbgl/style/style.hpp> #import <mbgl/annotation/annotation.hpp> #import <mbgl/map/camera.hpp> #import <mbgl/storage/reachability.h> #import <mbgl/util/default_thread_pool.hpp> -#import <mbgl/map/backend.hpp> -#import <mbgl/map/backend_scope.hpp> #import <mbgl/style/image.hpp> +#import <mbgl/renderer/renderer.hpp> +#import <mbgl/renderer/renderer_backend.hpp> +#import <mbgl/renderer/backend_scope.hpp> #import <mbgl/storage/default_file_source.hpp> #import <mbgl/storage/network_status.hpp> #import <mbgl/math/wrap.hpp> @@ -155,6 +158,7 @@ public: /// Cross-platform map view controller. mbgl::Map *_mbglMap; MGLMapViewImpl *_mbglView; + std::unique_ptr<MGLRenderFrontend> _rendererFrontend; std::shared_ptr<mbgl::ThreadPool> _mbglThreadPool; NSPanGestureRecognizer *_panGestureRecognizer; @@ -267,11 +271,12 @@ public: NSURL *legacyCacheURL = [cachesDirectoryURL URLByAppendingPathComponent:@"cache.db"]; [[NSFileManager defaultManager] removeItemAtURL:legacyCacheURL error:NULL]; - mbgl::DefaultFileSource* mbglFileSource = [MGLOfflineStorage sharedOfflineStorage].mbglFileSource; - _mbglThreadPool = mbgl::sharedThreadPool(); - _mbglMap = new mbgl::Map(*_mbglView, self.size, [NSScreen mainScreen].backingScaleFactor, *mbglFileSource, *_mbglThreadPool, mbgl::MapMode::Continuous, mbgl::GLContextMode::Unique, mbgl::ConstrainMode::None, mbgl::ViewportMode::Default); - [self validateTileCacheSize]; + MGLRendererConfiguration *config = [MGLRendererConfiguration currentConfiguration]; + + auto renderer = std::make_unique<mbgl::Renderer>(*_mbglView, config.scaleFactor, *config.fileSource, *_mbglThreadPool, config.contextMode, config.cacheDir, config.localFontFamilyName); + _rendererFrontend = std::make_unique<MGLRenderFrontend>(std::move(renderer), self, *_mbglView, true); + _mbglMap = new mbgl::Map(*_rendererFrontend, *_mbglView, self.size, config.scaleFactor, *config.fileSource, *_mbglThreadPool, mbgl::MapMode::Continuous, mbgl::ConstrainMode::None, mbgl::ViewportMode::Default); // 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. @@ -643,6 +648,10 @@ public: return _mbglMap; } +- (mbgl::Renderer *)renderer { + return _rendererFrontend->getRenderer(); +} + #pragma mark View hierarchy and drawing - (void)viewWillMoveToWindow:(NSWindow *)newWindow { @@ -687,9 +696,6 @@ public: - (void)setFrame:(NSRect)frame { super.frame = frame; - if (!NSEqualRects(frame, self.frame)) { - [self validateTileCacheSize]; - } if (!_isTargetingInterfaceBuilder) { _mbglMap->setSize(self.size); } @@ -773,11 +779,8 @@ public: } - (void)renderSync { - if (!self.dormant) { - // The OpenGL implementation automatically enables the OpenGL context for us. - mbgl::BackendScope scope { *_mbglView, mbgl::BackendScope::ScopeType::Implicit }; - - _mbglMap->render(*_mbglView); + if (!self.dormant && _rendererFrontend) { + _rendererFrontend->render(); if (_isPrinting) { _isPrinting = NO; @@ -789,21 +792,6 @@ public: } } -- (void)validateTileCacheSize { - if (!_mbglMap) { - return; - } - - CGFloat zoomFactor = self.maximumZoomLevel - self.minimumZoomLevel + 1; - CGFloat cpuFactor = [NSProcessInfo processInfo].processorCount; - CGFloat memoryFactor = (CGFloat)[NSProcessInfo processInfo].physicalMemory / 1000 / 1000 / 1000; - CGFloat sizeFactor = (NSWidth(self.bounds) / mbgl::util::tileSize) * (NSHeight(self.bounds) / mbgl::util::tileSize); - - NSUInteger cacheSize = zoomFactor * cpuFactor * memoryFactor * sizeFactor * 0.5; - - _mbglMap->setSourceTileCacheSize(cacheSize); -} - - (void)setNeedsGLDisplay { MGLAssertIsMainThread(); @@ -1061,13 +1049,11 @@ public: - (void)setMinimumZoomLevel:(double)minimumZoomLevel { _mbglMap->setMinZoom(minimumZoomLevel); - [self validateTileCacheSize]; } - (void)setMaximumZoomLevel:(double)maximumZoomLevel { _mbglMap->setMaxZoom(maximumZoomLevel); - [self validateTileCacheSize]; } - (double)maximumZoomLevel { @@ -1136,6 +1122,10 @@ public: } - (void)setCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function completionHandler:(nullable void (^)(void))completion { + [self setCamera:camera withDuration:duration animationTimingFunction:function edgePadding:self.contentInsets completionHandler:completion]; +} + +- (void)setCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function edgePadding:(NSEdgeInsets)edgePadding completionHandler:(nullable void (^)(void))completion { mbgl::AnimationOptions animationOptions; if (duration > 0) { animationOptions.duration.emplace(MGLDurationFromTimeInterval(duration)); @@ -1163,7 +1153,7 @@ public: [self willChangeValueForKey:@"camera"]; _mbglMap->cancelTransitions(); - mbgl::CameraOptions cameraOptions = [self cameraOptionsObjectForAnimatingToCamera:camera]; + mbgl::CameraOptions cameraOptions = [self cameraOptionsObjectForAnimatingToCamera:camera edgePadding:edgePadding]; _mbglMap->easeTo(cameraOptions, animationOptions); [self didChangeValueForKey:@"camera"]; } @@ -1209,17 +1199,17 @@ public: [self willChangeValueForKey:@"camera"]; _mbglMap->cancelTransitions(); - mbgl::CameraOptions cameraOptions = [self cameraOptionsObjectForAnimatingToCamera:camera]; + mbgl::CameraOptions cameraOptions = [self cameraOptionsObjectForAnimatingToCamera:camera edgePadding:self.contentInsets]; _mbglMap->flyTo(cameraOptions, animationOptions); [self didChangeValueForKey:@"camera"]; } /// Returns a CameraOptions object that specifies parameters for animating to /// the given camera. -- (mbgl::CameraOptions)cameraOptionsObjectForAnimatingToCamera:(MGLMapCamera *)camera { +- (mbgl::CameraOptions)cameraOptionsObjectForAnimatingToCamera:(MGLMapCamera *)camera edgePadding:(NSEdgeInsets) edgePadding { mbgl::CameraOptions options; options.center = MGLLatLngFromLocationCoordinate2D(camera.centerCoordinate); - options.padding = MGLEdgeInsetsFromNSEdgeInsets(self.contentInsets); + options.padding = MGLEdgeInsetsFromNSEdgeInsets(edgePadding); options.zoom = MGLZoomLevelForAltitude(camera.altitude, camera.pitch, camera.centerCoordinate.latitude, self.frame.size); @@ -1282,6 +1272,15 @@ public: return [self cameraForCameraOptions:cameraOptions]; } +- (MGLMapCamera *)cameraThatFitsShape:(MGLShape *)shape direction:(CLLocationDirection)direction edgePadding:(NSEdgeInsets)insets { + mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(insets); + padding += MGLEdgeInsetsFromNSEdgeInsets(self.contentInsets); + + mbgl::CameraOptions cameraOptions = _mbglMap->cameraForGeometry([shape geometryObject], padding, direction); + + return [self cameraForCameraOptions:cameraOptions]; +} + - (MGLMapCamera *)cameraForCameraOptions:(const mbgl::CameraOptions &)cameraOptions { CLLocationCoordinate2D centerCoordinate = MGLLocationCoordinate2DFromLatLng(cameraOptions.center ? *cameraOptions.center : _mbglMap->getLatLng()); double zoomLevel = cameraOptions.zoom ? *cameraOptions.zoom : self.zoomLevel; @@ -1374,7 +1373,7 @@ public: // Move the cursor back to the start point and show it again, creating // the illusion that it has stayed in place during the entire gesture. CGPoint cursorPoint = [self convertPoint:startPoint toView:nil]; - cursorPoint = [self.window convertRectToScreen:{ startPoint, NSZeroSize }].origin; + cursorPoint = [self.window convertRectToScreen:{ cursorPoint, NSZeroSize }].origin; cursorPoint.y = self.window.screen.frame.size.height - cursorPoint.y; CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cursorPoint); CGDisplayShowCursor(kCGDirectMainDisplay); @@ -1489,7 +1488,7 @@ public: if (hitAnnotationTag != _selectedAnnotationTag) { id <MGLAnnotation> annotation = [self annotationWithTag:hitAnnotationTag]; NSAssert(annotation, @"Cannot select nonexistent annotation with tag %u", hitAnnotationTag); - [self selectAnnotation:annotation]; + [self selectAnnotation:annotation atPoint:gesturePoint]; } } else { [self deselectAnnotation:self.selectedAnnotation]; @@ -1792,6 +1791,12 @@ public: } std::vector<MGLAnnotationTag> annotationTags = [self annotationTagsInRect:rect]; + std::vector<MGLAnnotationTag> shapeAnnotationTags = [self shapeAnnotationTagsInRect:rect]; + + if (shapeAnnotationTags.size()) { + annotationTags.insert(annotationTags.end(), shapeAnnotationTags.begin(), shapeAnnotationTags.end()); + } + if (annotationTags.size()) { NSMutableArray *annotations = [NSMutableArray arrayWithCapacity:annotationTags.size()]; @@ -2051,13 +2056,18 @@ public: queryRect = NSInsetRect(queryRect, -MGLAnnotationImagePaddingForHitTest, -MGLAnnotationImagePaddingForHitTest); std::vector<MGLAnnotationTag> nearbyAnnotations = [self annotationTagsInRect:queryRect]; + std::vector<MGLAnnotationTag> nearbyShapeAnnotations = [self shapeAnnotationTagsInRect:queryRect]; + + if (nearbyShapeAnnotations.size()) { + nearbyAnnotations.insert(nearbyAnnotations.end(), nearbyShapeAnnotations.begin(), nearbyShapeAnnotations.end()); + } if (nearbyAnnotations.size()) { // Assume that the user is fat-fingering an annotation. NSRect hitRect = NSInsetRect({ point, NSZeroSize }, -MGLAnnotationImagePaddingForHitTest, -MGLAnnotationImagePaddingForHitTest); - + // Filter out any annotation whose image is unselectable or for which // hit testing fails. auto end = std::remove_if(nearbyAnnotations.begin(), nearbyAnnotations.end(), [&](const MGLAnnotationTag annotationTag) { @@ -2066,12 +2076,17 @@ public: if (!annotation) { return true; } - + + if ([annotation isKindOfClass:[MGLShape class]]) + { + return false; + } + MGLAnnotationImage *annotationImage = [self imageOfAnnotationWithTag:annotationTag]; if (!annotationImage.selectable) { return true; } - + // Filter out the annotation if the fattened finger didn’t land on a // translucent or opaque pixel in the image. NSRect annotationRect = [self frameOfImage:annotationImage.image @@ -2144,7 +2159,15 @@ public: /// Returns the tags of the annotations coincident with the given rectangle. - (std::vector<MGLAnnotationTag>)annotationTagsInRect:(NSRect)rect { // Cocoa origin is at the lower-left corner. - return _mbglMap->queryPointAnnotations({ + return self.renderer->queryPointAnnotations({ + { NSMinX(rect), NSHeight(self.bounds) - NSMaxY(rect) }, + { NSMaxX(rect), NSHeight(self.bounds) - NSMinY(rect) }, + }); +} + +- (std::vector<MGLAnnotationTag>)shapeAnnotationTagsInRect:(NSRect)rect { + // Cocoa origin is at the lower-left corner. + return _rendererFrontend->getRenderer()->queryShapeAnnotations({ { NSMinX(rect), NSHeight(self.bounds) - NSMaxY(rect) }, { NSMaxX(rect), NSHeight(self.bounds) - NSMinY(rect) }, }); @@ -2193,11 +2216,11 @@ public: - (void)selectAnnotation:(id <MGLAnnotation>)annotation { - // Only point annotations can be selected. - if (!annotation || [annotation isKindOfClass:[MGLMultiPoint class]]) { - return; - } + [self selectAnnotation:annotation atPoint:NSZeroPoint]; +} +- (void)selectAnnotation:(id <MGLAnnotation>)annotation atPoint:(NSPoint)gesturePoint +{ id <MGLAnnotation> selectedAnnotation = self.selectedAnnotation; if (annotation == selectedAnnotation) { return; @@ -2212,10 +2235,10 @@ public: [self addAnnotation:annotation]; } - // The annotation can’t be selected if no part of it is hittable. + // The annotation's anchor will bounce to the current click. NSRect positioningRect = [self positioningRectForCalloutForAnnotationWithTag:annotationTag]; if (NSIsEmptyRect(NSIntersectionRect(positioningRect, self.bounds))) { - return; + positioningRect = CGRectMake(gesturePoint.x, gesturePoint.y, positioningRect.size.width, positioningRect.size.height); } self.selectedAnnotation = annotation; @@ -2315,6 +2338,13 @@ public: if (!annotation) { return NSZeroRect; } + if ([annotation isKindOfClass:[MGLMultiPoint class]]) { + CLLocationCoordinate2D origin = annotation.coordinate; + CGPoint originPoint = [self convertCoordinate:origin toPointToView:self]; + return CGRectMake(originPoint.x, originPoint.y, MGLAnnotationImagePaddingForHitTest, MGLAnnotationImagePaddingForHitTest); + + } + NSImage *image = [self imageOfAnnotationWithTag:annotationTag].image; if (!image) { image = [self dequeueReusableAnnotationImageWithIdentifier:MGLDefaultStyleMarkerSymbolName].image; @@ -2565,7 +2595,7 @@ public: optionalFilter = predicate.mgl_filter; } - std::vector<mbgl::Feature> features = _mbglMap->queryRenderedFeatures(screenCoordinate, { optionalLayerIDs, optionalFilter }); + std::vector<mbgl::Feature> features = _rendererFrontend->getRenderer()->queryRenderedFeatures(screenCoordinate, { optionalLayerIDs, optionalFilter }); return MGLFeaturesFromMBGLFeatures(features); } @@ -2599,7 +2629,7 @@ public: optionalFilter = predicate.mgl_filter; } - std::vector<mbgl::Feature> features = _mbglMap->queryRenderedFeatures(screenBox, { optionalLayerIDs, optionalFilter }); + std::vector<mbgl::Feature> features = _rendererFrontend->getRenderer()->queryRenderedFeatures(screenBox, { optionalLayerIDs, optionalFilter }); return MGLFeaturesFromMBGLFeatures(features); } @@ -2777,10 +2807,9 @@ public: } /// Adapter responsible for bridging calls from mbgl to MGLMapView and Cocoa. -class MGLMapViewImpl : public mbgl::View, public mbgl::Backend { +class MGLMapViewImpl : public mbgl::RendererBackend, public mbgl::MapObserver { public: - MGLMapViewImpl(MGLMapView *nativeView_) - : nativeView(nativeView_) {} + MGLMapViewImpl(MGLMapView *nativeView_) : nativeView(nativeView_) {} void onCameraWillChange(mbgl::MapObserver::CameraChangeMode mode) override { bool animated = mode == mbgl::MapObserver::CameraChangeMode::Animated; @@ -2858,7 +2887,7 @@ public: [nativeView sourceDidChange:nativeSource]; } - mbgl::gl::ProcAddress initializeExtension(const char* name) override { + 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."); @@ -2871,10 +2900,6 @@ public: return reinterpret_cast<mbgl::gl::ProcAddress>(symbol); } - void invalidate() override { - [nativeView setNeedsGLDisplay]; - } - void activate() override { if (activationCount++) { return; @@ -2903,6 +2928,10 @@ public: setViewport(0, 0, nativeView.framebufferSize); } + mbgl::Size getFramebufferSize() const override { + return nativeView.framebufferSize; + } + mbgl::PremultipliedImage readStillImage() { return readFramebuffer(nativeView.framebufferSize); } |