diff options
author | Roman Blum <rmnblm@gmail.com> | 2016-10-12 21:30:20 +0200 |
---|---|---|
committer | Minh Nguyễn <mxn@1ec5.org> | 2016-10-12 12:30:20 -0700 |
commit | a24e559ac83a47d19e28290c7ded427adeb303a3 (patch) | |
tree | 930c91599bea3b6a524559ba900fb42b8b034f98 /platform/ios/src | |
parent | 7bbf4a286e36ac26e7fa7317bd7942b5163c1188 (diff) | |
download | qtlocation-mapboxgl-a24e559ac83a47d19e28290c7ded427adeb303a3.tar.gz |
[ios, macos] possibility to set custom images to style (#6637)
* [ios, macos] possibility to set custom images to style
* [ios, macos] setImage:forName now supports MGLImage (UIImage/NSImage)
* [ios, macos] update documentation for setImage:forName: and removeImageForName:
* [ios, macos] rename method and fix prefix
* [ios, macos] change header visibility to project
* [ios, macos] update header imports
* [ios, macos] delete unnecessary whitespaces
* [ios, macos] remove unnecessary nil checks
* [ios, macos] delete unnecessary whitespaces
* [ios, macos] update documentation
* [ios, macos] make mgl_spriteImage a parameter-less instance method
* [ios, macos] add asserts
Diffstat (limited to 'platform/ios/src')
-rw-r--r-- | platform/ios/src/MGLMapView.mm | 387 | ||||
-rw-r--r-- | platform/ios/src/UIImage+MGLAdditions.h | 9 | ||||
-rw-r--r-- | platform/ios/src/UIImage+MGLAdditions.mm | 27 |
3 files changed, 221 insertions, 202 deletions
diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index 8b58fbaf65..d0c95d9c0c 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -38,6 +38,7 @@ #import "NSProcessInfo+MGLAdditions.h" #import "NSException+MGLAdditions.h" #import "NSURL+MGLAdditions.h" +#import "UIImage+MGLAdditions.h" #import "MGLFaux3DUserLocationAnnotationView.h" #import "MGLUserLocationAnnotationView.h" @@ -257,16 +258,16 @@ public: { mbgl::Map *_mbglMap; MBGLView *_mbglView; - + BOOL _opaque; NS_MUTABLE_ARRAY_OF(NSURL *) *_bundledStyleURLs; - + MGLAnnotationContextMap _annotationContextsByAnnotationTag; /// Tag of the selected annotation. If the user location annotation is selected, this ivar is set to `MGLAnnotationTagNotFound`. MGLAnnotationTag _selectedAnnotationTag; NS_MUTABLE_DICTIONARY_OF(NSString *, NS_MUTABLE_ARRAY_OF(MGLAnnotationView *) *) *_annotationViewReuseQueueByIdentifier; - + BOOL _userLocationAnnotationIsSelected; /// Size of the rectangle formed by unioning the maximum slop area around every annotation image and annotation image view. CGSize _unionedAnnotationRepresentationSize; @@ -283,18 +284,18 @@ public: CADisplayLink *_displayLink; BOOL _needsDisplayRefresh; - + NSUInteger _changeDelimiterSuppressionDepth; - + /// Center coordinate of the pinch gesture on the previous iteration of the gesture. CLLocationCoordinate2D _previousPinchCenterCoordinate; NSUInteger _previousPinchNumberOfTouches; - + BOOL _delegateHasAlphasForShapeAnnotations; BOOL _delegateHasStrokeColorsForShapeAnnotations; BOOL _delegateHasFillColorsForShapeAnnotations; BOOL _delegateHasLineWidthsForShapeAnnotations; - + MGLCompassDirectionFormatter *_accessibilityCompassFormatter; } @@ -381,14 +382,14 @@ public: self.accessibilityTraits = UIAccessibilityTraitAllowsDirectInteraction | UIAccessibilityTraitAdjustable; _accessibilityCompassFormatter = [[MGLCompassDirectionFormatter alloc] init]; _accessibilityCompassFormatter.unitStyle = NSFormattingUnitStyleLong; - + self.backgroundColor = [UIColor clearColor]; self.clipsToBounds = YES; // setup mbgl view const float scaleFactor = [UIScreen instancesRespondToSelector:@selector(nativeScale)] ? [[UIScreen mainScreen] nativeScale] : [[UIScreen mainScreen] scale]; _mbglView = new MBGLView(self, scaleFactor); - + // Delete the pre-offline ambient cache at ~/Library/Caches/cache.db. NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); NSString *fileCachePath = [paths.firstObject stringByAppendingPathComponent:@"cache.db"]; @@ -416,7 +417,7 @@ public: _isWaitingForRedundantReachableNotification = YES; } [reachability startNotifier]; - + // Set up annotation management and selection state. _annotationImagesByIdentifier = [NSMutableDictionary dictionary]; _annotationContextsByAnnotationTag = {}; @@ -581,7 +582,7 @@ public: UIImage *scaleImage = [MGLMapView resourceImageNamed:@"Compass.png"]; UIGraphicsBeginImageContextWithOptions(scaleImage.size, NO, [UIScreen mainScreen].scale); [scaleImage drawInRect:{ CGPointZero, scaleImage.size }]; - + CGFloat northSize = 9; UIFont *northFont; if ([UIFont respondsToSelector:@selector(systemFontOfSize:weight:)]) @@ -600,7 +601,7 @@ public: scaleImage.size.height * 0.45, north.size.width, north.size.height); [north drawInRect:stringRect]; - + UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return image; @@ -627,14 +628,14 @@ public: { [[NSNotificationCenter defaultCenter] removeObserver:self]; [_attributionButton removeObserver:self forKeyPath:@"hidden"]; - + // Removing the annotations unregisters any outstanding KVO observers. NSArray *annotations = self.annotations; if (annotations) { [self removeAnnotations:annotations]; } - + [self validateDisplayLink]; if (_mbglMap) @@ -665,7 +666,7 @@ public: if (_delegate == delegate) return; _delegate = delegate; - + _delegateHasAlphasForShapeAnnotations = [_delegate respondsToSelector:@selector(mapView:alphaForShapeAnnotation:)]; _delegateHasStrokeColorsForShapeAnnotations = [_delegate respondsToSelector:@selector(mapView:strokeColorForShapeAnnotation:)]; _delegateHasFillColorsForShapeAnnotations = [_delegate respondsToSelector:@selector(mapView:fillColorForPolygonAnnotation:)]; @@ -703,7 +704,7 @@ public: { return; } - + CGFloat zoomFactor = self.maximumZoomLevel - self.minimumZoomLevel + 1; CGFloat cpuFactor = [NSProcessInfo processInfo].processorCount; CGFloat memoryFactor = (CGFloat)[NSProcessInfo processInfo].physicalMemory / 1000 / 1000 / 1000; @@ -795,7 +796,7 @@ public: // [constraintParentView removeConstraints:self.logoViewConstraints]; [self.logoViewConstraints removeAllObjects]; - + [self.logoViewConstraints addObject: [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeBottom @@ -819,7 +820,7 @@ public: // [constraintParentView removeConstraints:self.attributionButtonConstraints]; [self.attributionButtonConstraints removeAllObjects]; - + [self.attributionButtonConstraints addObject: [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeBottom @@ -867,7 +868,7 @@ public: - (void)layoutSubviews { [super layoutSubviews]; - + [self adjustContentInset]; if ( ! _isTargetingInterfaceBuilder) @@ -885,7 +886,7 @@ public: [self updateHeadingForDeviceOrientation]; [self updateCompass]; } - + [self updateUserLocationAnnotationView]; } @@ -907,12 +908,12 @@ public: // This map view is an immediate child of a view controller’s content view. viewController = (UIViewController *)self.superview.nextResponder; } - + if ( ! viewController.automaticallyAdjustsScrollViewInsets) { return; } - + UIEdgeInsets contentInset = UIEdgeInsetsZero; CGPoint topPoint = CGPointMake(0, viewController.topLayoutGuide.length); contentInset.top = [self convertPoint:topPoint fromView:viewController.view].y; @@ -939,14 +940,14 @@ public: { return; } - + // After adjusting the content inset, move the center coordinate from the // old frame of reference to the new one represented by the newly set // content inset. CLLocationCoordinate2D oldCenter = self.centerCoordinate; - + _contentInset = contentInset; - + if (self.userTrackingMode == MGLUserTrackingModeNone) { // Don’t call -setCenterCoordinate:, which resets the user tracking mode. @@ -956,7 +957,7 @@ public: { [self didUpdateLocationWithUserTrackingAnimated:animated]; } - + // Compass, logo and attribution button constraints needs to be updated. [self setNeedsUpdateConstraints]; } @@ -1016,7 +1017,7 @@ public: { _mbglMap->setConstrainMode(mbgl::ConstrainMode::HeightOnly); } - + _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateFromDisplayLink)]; _displayLink.frameInterval = MGLTargetFrameInterval; [_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; @@ -1053,7 +1054,7 @@ public: [self validateLocationServices]; [MGLMapboxEvents flush]; - + _displayLink.paused = YES; if ( ! self.glSnapshotView) @@ -1094,11 +1095,11 @@ public: [self.glSnapshotView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; [self.glView bindDrawable]; - + _displayLink.paused = NO; [self validateLocationServices]; - + [MGLMapboxEvents pushEvent:MGLEventTypeMapLoad withAttributes:@{}]; } } @@ -1179,7 +1180,7 @@ public: [self trackGestureEvent:MGLEventGesturePanStart forRecognizer:pan]; self.userTrackingMode = MGLUserTrackingModeNone; - + [self notifyGestureDidBegin]; } else if (pan.state == UIGestureRecognizerStateChanged) @@ -1228,7 +1229,7 @@ public: if (_mbglMap->getZoom() <= _mbglMap->getMinZoom() && pinch.scale < 1) return; _mbglMap->cancelTransitions(); - + CGPoint centerPoint = [self anchorPointForGesture:pinch]; if (pinch.state == UIGestureRecognizerStateBegan) @@ -1236,7 +1237,7 @@ public: [self trackGestureEvent:MGLEventGesturePinchStart forRecognizer:pinch]; self.scale = _mbglMap->getScale(); - + [self notifyGestureDidBegin]; } else if (pinch.state == UIGestureRecognizerStateChanged) @@ -1244,9 +1245,9 @@ public: CGFloat newScale = self.scale * pinch.scale; if (log2(newScale) < _mbglMap->getMinZoom()) return; - + _mbglMap->setScale(newScale, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }); - + // The gesture recognizer only reports the gesture’s current center // point, so use the previous center point to anchor the transition. // If the number of touches has changed, the remembered center point is @@ -1300,7 +1301,7 @@ public: [self unrotateIfNeededForGesture]; } - + _previousPinchCenterCoordinate = [self convertPoint:centerPoint toCoordinateFromView:self]; _previousPinchNumberOfTouches = pinch.numberOfTouches; } @@ -1310,7 +1311,7 @@ public: if ( ! self.isRotateEnabled) return; _mbglMap->cancelTransitions(); - + CGPoint centerPoint = [self anchorPointForGesture:rotate]; if (rotate.state == UIGestureRecognizerStateBegan) @@ -1323,7 +1324,7 @@ public: { self.userTrackingMode = MGLUserTrackingModeFollow; } - + [self notifyGestureDidBegin]; } else if (rotate.state == UIGestureRecognizerStateChanged) @@ -1337,7 +1338,7 @@ public: newDegrees = fminf(newDegrees, 30); newDegrees = fmaxf(newDegrees, -30); } - + _mbglMap->setBearing(newDegrees, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }); [self notifyMapChange:mbgl::MapChangeRegionIsChanging]; @@ -1378,7 +1379,7 @@ public: return; } [self trackGestureEvent:MGLEventGestureSingleTap forRecognizer:singleTap]; - + if (self.mapViewProxyAccessibilityElement.accessibilityElementIsFocused) { id nextElement; @@ -1433,7 +1434,7 @@ public: } } } - + MGLAnnotationTag hitAnnotationTag = [self annotationTagAtPoint:tapPoint persistingResults:YES]; if (hitAnnotationTag != MGLAnnotationTagNotFound) { @@ -1514,7 +1515,7 @@ public: self.scale = _mbglMap->getScale(); self.quickZoomStart = [quickZoom locationInView:quickZoom.view].y; - + [self notifyGestureDidBegin]; } else if (quickZoom.state == UIGestureRecognizerStateChanged) @@ -1524,7 +1525,7 @@ public: CGFloat newZoom = log2f(self.scale) + (distance / 75); if (newZoom < _mbglMap->getMinZoom()) return; - + CGPoint centerPoint = [self anchorPointForGesture:quickZoom]; _mbglMap->scaleBy(powf(2, newZoom) / _mbglMap->getScale(), @@ -1557,7 +1558,7 @@ public: CGFloat slowdown = 20.0; CGFloat pitchNew = currentPitch - (gestureDistance / slowdown); - + CGPoint centerPoint = [self anchorPointForGesture:twoFingerDrag]; _mbglMap->setPitch(pitchNew, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }); @@ -1582,7 +1583,7 @@ public: { return self.contentCenter; } - + return [gesture locationInView:gesture.view]; } @@ -1690,7 +1691,7 @@ public: nil]; } - + [self.attributionSheet showFromRect:self.attributionButton.frame inView:self animated:YES]; } @@ -1791,7 +1792,7 @@ public: // Redundantly move the associated annotation view outside the scope of the animation-less transaction block in -updateAnnotationViews. annotationContext.annotationView.center = [self convertCoordinate:annotationContext.annotation.coordinate toPointToView:self]; } - + MGLAnnotationImage *annotationImage = [self imageOfAnnotationWithTag:annotationTag]; NSString *symbolName = annotationImage.styleIconIdentifier; @@ -1968,14 +1969,14 @@ public: - (UIBezierPath *)accessibilityPath { UIBezierPath *path = [UIBezierPath bezierPathWithRect:self.accessibilityFrame]; - + // Exclude any visible annotation callout view. if (self.calloutViewForSelectedAnnotation) { UIBezierPath *calloutViewPath = [UIBezierPath bezierPathWithRect:self.calloutViewForSelectedAnnotation.frame]; [path appendPath:calloutViewPath]; } - + return path; } @@ -2016,7 +2017,7 @@ public: return nil; } std::vector<MGLAnnotationTag> visibleAnnotations = [self annotationTagsInRect:self.bounds]; - + // Ornaments if (index == 0) { @@ -2034,7 +2035,7 @@ public: { return self.attributionButton; } - + std::sort(visibleAnnotations.begin(), visibleAnnotations.end()); CGPoint centerPoint = self.contentCenter; if (self.userTrackingMode != MGLUserTrackingModeNone) @@ -2051,7 +2052,7 @@ public: coordinateB.longitude - currentCoordinate.longitude); return deltaA < deltaB; }); - + NSUInteger annotationIndex = MGLAnnotationTagNotFound; if (index >= 0 && (NSUInteger)(index - 2) < visibleAnnotations.size()) { @@ -2062,20 +2063,20 @@ public: NSAssert(_annotationContextsByAnnotationTag.count(annotationTag), @"Missing annotation for tag %u.", annotationTag); MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(annotationTag); id <MGLAnnotation> annotation = annotationContext.annotation; - + // Let the annotation view serve as its own accessibility element. MGLAnnotationView *annotationView = annotationContext.annotationView; if (annotationView && annotationView.superview) { return annotationView; } - + // Lazily create an accessibility element for the found annotation. if ( ! annotationContext.accessibilityElement) { annotationContext.accessibilityElement = [[MGLAnnotationAccessibilityElement alloc] initWithAccessibilityContainer:self tag:annotationTag]; } - + // Update the accessibility element. MGLAnnotationImage *annotationImage = [self imageOfAnnotationWithTag:annotationTag]; CGRect annotationFrame = [self frameOfImage:annotationImage.image centeredAtCoordinate:annotation.coordinate]; @@ -2087,7 +2088,7 @@ public: CGRect screenRect = UIAccessibilityConvertFrameToScreenCoordinates(annotationFrame, self); annotationContext.accessibilityElement.accessibilityFrame = screenRect; annotationContext.accessibilityElement.accessibilityHint = NSLocalizedStringWithDefaultValue(@"ANNOTATION_A11Y_HINT", nil, nil, @"Shows more info", @"Accessibility hint"); - + if ([annotation respondsToSelector:@selector(title)]) { annotationContext.accessibilityElement.accessibilityLabel = annotation.title; @@ -2096,7 +2097,7 @@ public: { annotationContext.accessibilityElement.accessibilityValue = annotation.subtitle; } - + return annotationContext.accessibilityElement; } @@ -2115,9 +2116,9 @@ public: { return 1; } - + std::vector<MGLAnnotationTag> visibleAnnotations = [self annotationTagsInRect:self.bounds]; - + MGLAnnotationTag tag = MGLAnnotationTagNotFound; if ([element isKindOfClass:[MGLAnnotationView class]]) { @@ -2136,7 +2137,7 @@ public: { return NSNotFound; } - + std::sort(visibleAnnotations.begin(), visibleAnnotations.end()); auto foundElement = std::find(visibleAnnotations.begin(), visibleAnnotations.end(), tag); if (foundElement == visibleAnnotations.end()) @@ -2176,7 +2177,7 @@ public: } _mbglMap->scaleBy(scaleFactor, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }); [self unrotateIfNeededForGesture]; - + UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, self.accessibilityValue); } @@ -2226,7 +2227,7 @@ public: - (void)_setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate edgePadding:(UIEdgeInsets)insets zoomLevel:(double)zoomLevel direction:(CLLocationDirection)direction duration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function completionHandler:(nullable void (^)(void))completion { _mbglMap->cancelTransitions(); - + mbgl::CameraOptions cameraOptions; cameraOptions.center = MGLLatLngFromLocationCoordinate2D(centerCoordinate); cameraOptions.padding = MGLEdgeInsetsFromNSEdgeInsets(insets); @@ -2235,7 +2236,7 @@ public: { cameraOptions.angle = MGLRadiansFromDegrees(-direction); } - + mbgl::AnimationOptions animationOptions; if (duration) { @@ -2275,9 +2276,9 @@ public: { if (zoomLevel == self.zoomLevel) return; _mbglMap->cancelTransitions(); - + CGFloat duration = animated ? MGLAnimationDuration : 0; - + _mbglMap->setZoom(zoomLevel, MGLEdgeInsetsFromNSEdgeInsets(self.contentInset), MGLDurationInSeconds(duration)); @@ -2372,7 +2373,7 @@ public: - (void)_setVisibleCoordinates:(CLLocationCoordinate2D *)coordinates count:(NSUInteger)count edgePadding:(UIEdgeInsets)insets direction:(CLLocationDirection)direction duration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function completionHandler:(nullable void (^)(void))completion { _mbglMap->cancelTransitions(); - + [self willChangeValueForKey:@"visibleCoordinateBounds"]; mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(insets); padding += MGLEdgeInsetsFromNSEdgeInsets(self.contentInset); @@ -2382,13 +2383,13 @@ public: { latLngs.push_back({coordinates[i].latitude, coordinates[i].longitude}); } - + mbgl::CameraOptions cameraOptions = _mbglMap->cameraForLatLngs(latLngs, padding); if (direction >= 0) { cameraOptions.angle = MGLRadiansFromDegrees(-direction); } - + mbgl::AnimationOptions animationOptions; if (duration > 0) { @@ -2425,7 +2426,7 @@ public: { self.userTrackingMode = MGLUserTrackingModeFollow; } - + [self _setDirection:direction animated:animated]; } @@ -2435,7 +2436,7 @@ public: _mbglMap->cancelTransitions(); CGFloat duration = animated ? MGLAnimationDuration : 0; - + if (self.userTrackingMode == MGLUserTrackingModeNone) { _mbglMap->setBearing(direction, @@ -2510,7 +2511,7 @@ public: }); }; } - + [self willChangeValueForKey:@"camera"]; _mbglMap->easeTo(cameraOptions, animationOptions); [self didChangeValueForKey:@"camera"]; @@ -2529,7 +2530,7 @@ public: - (void)flyToCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration peakAltitude:(CLLocationDistance)peakAltitude completionHandler:(nullable void (^)(void))completion { self.userTrackingMode = MGLUserTrackingModeNone; - + [self _flyToCamera:camera edgePadding:self.contentInset withDuration:duration peakAltitude:peakAltitude completionHandler:completion]; } @@ -2562,7 +2563,7 @@ public: }); }; } - + [self willChangeValueForKey:@"camera"]; _mbglMap->flyTo(cameraOptions, animationOptions); [self didChangeValueForKey:@"camera"]; @@ -2666,7 +2667,7 @@ public: bounds.extend([self convertPoint:{ CGRectGetMaxX(rect), CGRectGetMinY(rect) } toLatLngFromView:view]); bounds.extend([self convertPoint:{ CGRectGetMaxX(rect), CGRectGetMaxY(rect) } toLatLngFromView:view]); bounds.extend([self convertPoint:{ CGRectGetMinX(rect), CGRectGetMaxY(rect) } toLatLngFromView:view]); - + // The world is wrapping if a point just outside the bounds is also within // the rect. mbgl::LatLng outsideLatLng; @@ -2684,14 +2685,14 @@ public: bounds.east() + 1, }; } - + // If the world is wrapping, extend the bounds to cover all longitudes. if (CGRectContainsPoint(rect, [self convertLatLng:outsideLatLng toPointToView:view])) { bounds.extend(mbgl::LatLng(bounds.south(), -180)); bounds.extend(mbgl::LatLng(bounds.south(), 180)); } - + return bounds; } @@ -2777,7 +2778,7 @@ public: { return nil; } - + // Map all the annotation tags to the annotations themselves. std::vector<id <MGLAnnotation>> annotations; std::transform(_annotationContextsByAnnotationTag.begin(), @@ -2787,11 +2788,11 @@ public: { return pair.second.annotation; }); - + annotations.erase(std::remove_if(annotations.begin(), annotations.end(), [](const id <MGLAnnotation> annotation) { return annotation == nullptr; }), annotations.end()); - + return [NSArray arrayWithObjects:&annotations[0] count:annotations.size()]; } @@ -2802,7 +2803,7 @@ public: { return nil; } - + MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag[tag]; return annotationContext.annotation; } @@ -2814,7 +2815,7 @@ public: { return MGLAnnotationTagNotFound; } - + for (auto &pair : _annotationContextsByAnnotationTag) { if (pair.second.annotation == annotation) @@ -2845,7 +2846,7 @@ public: BOOL delegateImplementsViewForAnnotation = [self.delegate respondsToSelector:@selector(mapView:viewForAnnotation:)]; BOOL delegateImplementsImageForPoint = [self.delegate respondsToSelector:@selector(mapView:imageForAnnotation:)]; - + NSMutableArray *newAnnotationViews = [[NSMutableArray alloc] initWithCapacity:annotations.count]; for (id <MGLAnnotation> annotation in annotations) @@ -2860,7 +2861,7 @@ public: { continue; } - + // The polyline or polygon knows how to style itself (with the map view’s help). MGLMultiPoint *multiPoint = (MGLMultiPoint *)annotation; if (!multiPoint.pointCount) { @@ -2881,7 +2882,7 @@ public: MGLAnnotationView *annotationView; NSString *symbolName; NSValue *annotationValue = [NSValue valueWithNonretainedObject:annotation]; - + if (delegateImplementsViewForAnnotation) { annotationView = [self annotationViewForAnnotation:annotation]; @@ -2891,7 +2892,7 @@ public: annotationView.annotation = annotation; annotationView.center = [self convertCoordinate:annotation.coordinate toPointToView:self]; [newAnnotationViews addObject:annotationView]; - + MGLAnnotationImage *annotationImage = self.invisibleAnnotationImage; symbolName = annotationImage.styleIconIdentifier; annotationImagesForAnnotation[annotationValue] = annotationImage; @@ -2901,10 +2902,10 @@ public: } } } - + if ( ! annotationView) { MGLAnnotationImage *annotationImage; - + if (delegateImplementsImageForPoint) { annotationImage = [self.delegate mapView:self imageForAnnotation:annotation]; @@ -2917,9 +2918,9 @@ public: { annotationImage = self.defaultAnnotationImage; } - + symbolName = annotationImage.styleIconIdentifier; - + if ( ! symbolName) { symbolName = [MGLAnnotationSpritePrefix stringByAppendingString:annotationImage.reuseIdentifier]; @@ -2929,7 +2930,7 @@ public: { [self installAnnotationImage:annotationImage]; } - + annotationImagesForAnnotation[annotationValue] = annotationImage; } @@ -2947,7 +2948,7 @@ public: context.annotationView = annotationView; context.viewReuseIdentifier = annotationView.reuseIdentifier; } - + _annotationContextsByAnnotationTag[annotationTag] = context; if ([annotation isKindOfClass:[NSObject class]]) { @@ -2958,21 +2959,21 @@ public: } [self updateAnnotationContainerViewWithAnnotationViews:newAnnotationViews]; - + [self didChangeValueForKey:@"annotations"]; - + if ([self.delegate respondsToSelector:@selector(mapView:didAddAnnotationViews:)]) { [self.delegate mapView:self didAddAnnotationViews:newAnnotationViews]; } - + UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil); } - (void)updateAnnotationContainerViewWithAnnotationViews:(NS_ARRAY_OF(MGLAnnotationView *) *)annotationViews { if (annotationViews.count == 0) return; - + MGLAnnotationContainerView *newAnnotationContainerView; if (self.annotationContainerView) { @@ -3008,7 +3009,7 @@ public: - (MGLAnnotationImage *)invisibleAnnotationImage { MGLAnnotationImage *annotationImage = [self dequeueReusableAnnotationImageWithIdentifier:MGLInvisibleStyleMarkerSymbolName]; - + if (!annotationImage) { UIGraphicsBeginImageContext(CGSizeMake(1, 1)); @@ -3018,27 +3019,27 @@ public: reuseIdentifier:MGLInvisibleStyleMarkerSymbolName]; annotationImage.styleIconIdentifier = [MGLAnnotationSpritePrefix stringByAppendingString:annotationImage.reuseIdentifier]; } - + return annotationImage; } - (MGLAnnotationView *)annotationViewForAnnotation:(id<MGLAnnotation>)annotation { MGLAnnotationView *annotationView = [self.delegate mapView:self viewForAnnotation:annotation]; - + if (annotationView) { annotationView.annotation = annotation; annotationView.mapView = self; CGRect bounds = UIEdgeInsetsInsetRect({ CGPointZero, annotationView.frame.size }, annotationView.alignmentRectInsets); - + _largestAnnotationViewSize = CGSizeMake(MAX(_largestAnnotationViewSize.width, CGRectGetWidth(bounds)), MAX(_largestAnnotationViewSize.height, CGRectGetHeight(bounds))); - + _unionedAnnotationRepresentationSize = CGSizeMake(MAX(_unionedAnnotationRepresentationSize.width, _largestAnnotationViewSize.width), MAX(_unionedAnnotationRepresentationSize.height, _largestAnnotationViewSize.height)); } - + return annotationView; } @@ -3046,7 +3047,7 @@ public: { MGLAnnotationTag annotationTag = [self annotationTagForAnnotation:annotation]; if (annotationTag == MGLAnnotationTagNotFound) return nil; - + MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(annotationTag); return annotationContext.annotationView; } @@ -3090,29 +3091,11 @@ public: NSString *iconIdentifier = annotationImage.styleIconIdentifier; self.annotationImagesByIdentifier[annotationImage.reuseIdentifier] = annotationImage; annotationImage.delegate = self; - - // retrieve pixels - CGImageRef image = annotationImage.image.CGImage; - size_t width = CGImageGetWidth(image); - size_t height = CGImageGetHeight(image); - CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); - mbgl::PremultipliedImage cPremultipliedImage(width, height); - size_t bytesPerPixel = 4; - size_t bytesPerRow = bytesPerPixel * width; - size_t bitsPerComponent = 8; - CGContextRef context = CGBitmapContextCreate(cPremultipliedImage.data.get(), width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast); - CGContextDrawImage(context, CGRectMake(0, 0, width, height), image); - CGContextRelease(context); - CGColorSpaceRelease(colorSpace); // add sprite - auto cSpriteImage = std::make_shared<mbgl::SpriteImage>( - std::move(cPremultipliedImage), - float(annotationImage.image.scale)); + std::shared_ptr<mbgl::SpriteImage> sprite(annotationImage.image.mgl_spriteImage); + _mbglMap->addAnnotationIcon(iconIdentifier.UTF8String, sprite); - // sprite upload - _mbglMap->addAnnotationIcon(iconIdentifier.UTF8String, cSpriteImage); - // Create a slop area with a “radius” equal in size to the annotation // image’s alignment rect, allowing the eventual tap to be on any point // within this image. Union this slop area with any existing slop areas. @@ -3158,9 +3141,9 @@ public: { [self deselectAnnotation:annotation animated:NO]; } - + _annotationContextsByAnnotationTag.erase(annotationTag); - + if ([annotation isKindOfClass:[NSObject class]] && ![annotation isKindOfClass:[MGLMultiPoint class]]) { [(NSObject *)annotation removeObserver:self forKeyPath:@"coordinate" context:(void *)(NSUInteger)annotationTag]; @@ -3222,7 +3205,7 @@ public: MGLAnnotationView *reusableView = annotationViewReuseQueue.firstObject; [reusableView prepareForReuse]; [annotationViewReuseQueue removeObject:reusableView]; - + return reusableView; } @@ -3249,14 +3232,14 @@ public: queryRect = CGRectInset(queryRect, -MGLAnnotationImagePaddingForHitTest, -MGLAnnotationImagePaddingForHitTest); std::vector<MGLAnnotationTag> nearbyAnnotations = [self annotationTagsInRect:queryRect]; - + if (nearbyAnnotations.size()) { // Assume that the user is fat-fingering an annotation. CGRect hitRect = CGRectInset({ point, CGSizeZero }, -MGLAnnotationImagePaddingForHitTest, -MGLAnnotationImagePaddingForHitTest); - + // Filter out any annotation whose image or view is unselectable or for which // hit testing fails. auto end = std::remove_if(nearbyAnnotations.begin(), nearbyAnnotations.end(), @@ -3264,10 +3247,10 @@ public: { id <MGLAnnotation> annotation = [self annotationWithTag:annotationTag]; NSAssert(annotation, @"Unknown annotation found nearby tap"); - + MGLAnnotationContext annotationContext = _annotationContextsByAnnotationTag[annotationTag]; CGRect annotationRect; - + MGLAnnotationView *annotationView = annotationContext.annotationView; if (annotationView) { @@ -3275,7 +3258,7 @@ public: { return true; } - + CGPoint calloutAnchorPoint = [self convertCoordinate:annotation.coordinate toPointToView:self]; CGRect frame = CGRectInset({ calloutAnchorPoint, CGSizeZero }, -CGRectGetWidth(annotationView.frame) / 2, -CGRectGetHeight(annotationView.frame) / 2); annotationRect = UIEdgeInsetsInsetRect(frame, annotationView.alignmentRectInsets); @@ -3287,28 +3270,28 @@ public: { return true; } - + MGLAnnotationImage *fallbackAnnotationImage = [self dequeueReusableAnnotationImageWithIdentifier:MGLDefaultStyleMarkerSymbolName]; UIImage *fallbackImage = fallbackAnnotationImage.image; - + annotationRect = [self frameOfImage:annotationImage.image ?: fallbackImage centeredAtCoordinate:annotation.coordinate]; } - + // Filter out the annotation if the fattened finger didn’t land // within the image’s alignment rect. return !!!CGRectIntersectsRect(annotationRect, hitRect); }); - + nearbyAnnotations.resize(std::distance(nearbyAnnotations.begin(), end)); } - + MGLAnnotationTag hitAnnotationTag = MGLAnnotationTagNotFound; if (nearbyAnnotations.size()) { // The annotation tags need to be stable in order to compare them with // the remembered tags. std::sort(nearbyAnnotations.begin(), nearbyAnnotations.end()); - + if (nearbyAnnotations == _annotationsNearbyLastTap) { // The first selection in the cycle should be the one nearest to the @@ -3323,7 +3306,7 @@ public: coordinateB.longitude - currentCoordinate.longitude); return deltaA < deltaB; }); - + // The last time we persisted a set of annotations, we had the same // set of annotations as we do now. Cycle through them. if (_selectedAnnotationTag == MGLAnnotationTagNotFound @@ -3361,7 +3344,7 @@ public: { _annotationsNearbyLastTap = nearbyAnnotations; } - + // Choose the first nearby annotation. if (nearbyAnnotations.size()) { @@ -3369,7 +3352,7 @@ public: } } } - + return hitAnnotationTag; } @@ -3441,7 +3424,7 @@ public: } [self deselectAnnotation:self.selectedAnnotation animated:NO]; - + // Add the annotation to the map if it hasn’t been added yet. MGLAnnotationTag annotationTag = [self annotationTagForAnnotation:annotation]; if (annotationTag == MGLAnnotationTagNotFound && annotation != self.userLocation) @@ -3450,29 +3433,29 @@ public: annotationTag = [self annotationTagForAnnotation:annotation]; if (annotationTag == MGLAnnotationTagNotFound) return; } - + // By default attempt to use the GL annotation image frame as the positioning rect. CGRect positioningRect = [self positioningRectForCalloutForAnnotationWithTag:annotationTag]; - + MGLAnnotationView *annotationView = nil; - + if (annotation != self.userLocation) { MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(annotationTag); - + annotationView = annotationContext.annotationView; - + if (annotationView && annotationView.enabled) { // Annotations represented by views use the view frame as the positioning rect. positioningRect = annotationView.frame; - + [annotationView.superview bringSubviewToFront:annotationView]; [annotationView setSelected:YES animated:animated]; } } - + // The client can request that any annotation be selected (even ones that are offscreen). // The annotation can’t be selected if no part of it is hittable. if ( ! CGRectIntersectsRect(positioningRect, self.bounds) && annotation != self.userLocation) @@ -3502,7 +3485,7 @@ public: if (_userLocationAnnotationIsSelected) { positioningRect = [self.userLocationAnnotationView.layer.presentationLayer frame]; - + CGRect implicitAnnotationFrame = [self.userLocationAnnotationView.layer.presentationLayer frame]; CGRect explicitAnnotationFrame = self.userLocationAnnotationView.frame; _initialImplicitCalloutViewOffset = CGPointMake(CGRectGetMinX(explicitAnnotationFrame) - CGRectGetMinX(implicitAnnotationFrame), @@ -3551,7 +3534,7 @@ public: { [self.delegate mapView:self didSelectAnnotation:annotation]; } - + if (annotationView && [self.delegate respondsToSelector:@selector(mapView:didSelectAnnotationView:)]) { [self.delegate mapView:self didSelectAnnotationView:annotationView]; @@ -3573,7 +3556,7 @@ public: - (CGRect)positioningRectForCalloutForAnnotationWithTag:(MGLAnnotationTag)annotationTag { MGLAnnotationContext annotationContext = _annotationContextsByAnnotationTag[annotationTag]; - + id <MGLAnnotation> annotation = [self annotationWithTag:annotationTag]; if ( ! annotation) { @@ -3588,10 +3571,10 @@ public: { return CGRectZero; } - + CGRect positioningRect = [self frameOfImage:image centeredAtCoordinate:annotation.coordinate]; positioningRect.origin.x -= 0.5; - + return CGRectInset(positioningRect, -MGLAnnotationImagePaddingForCallout, -MGLAnnotationImagePaddingForCallout); } @@ -3613,10 +3596,10 @@ public: { return nil; } - + NSString *customSymbol = _annotationContextsByAnnotationTag.at(annotationTag).imageReuseIdentifier; NSString *symbolName = customSymbol.length ? customSymbol : MGLDefaultStyleMarkerSymbolName; - + return [self dequeueReusableAnnotationImageWithIdentifier:symbolName]; } @@ -3628,11 +3611,11 @@ public: { // dismiss popup [self.calloutViewForSelectedAnnotation dismissCalloutAnimated:animated]; - + // deselect annotation view MGLAnnotationView *annotationView = nil; MGLAnnotationTag annotationTag = [self annotationTagForAnnotation:annotation]; - + if (annotationTag != MGLAnnotationTagNotFound) { MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(annotationTag); @@ -3649,7 +3632,7 @@ public: { [self.delegate mapView:self didDeselectAnnotation:annotation]; } - + if (annotationView && [self.delegate respondsToSelector:@selector(mapView:didDeselectAnnotationView:)]) { [self.delegate mapView:self didDeselectAnnotationView:annotationView]; @@ -3664,7 +3647,7 @@ public: { return; } - + // The user location callout view initially points to the user location // annotation’s implicit (visual) frame, which is offset from the // annotation’s explicit frame. Now the callout view needs to rendezvous @@ -3728,19 +3711,19 @@ public: NSString *iconIdentifier = annotationImage.styleIconIdentifier; NSString *fallbackReuseIdentifier = MGLDefaultStyleMarkerSymbolName; NSString *fallbackIconIdentifier = [MGLAnnotationSpritePrefix stringByAppendingString:fallbackReuseIdentifier]; - + // Remove the old icon from the style. if ( ! [iconIdentifier isEqualToString:fallbackIconIdentifier]) { _mbglMap->removeAnnotationIcon(iconIdentifier.UTF8String); } - + if (annotationImage.image) { // Add the new icon to the style. NSString *updatedIconIdentifier = [MGLAnnotationSpritePrefix stringByAppendingString:annotationImage.reuseIdentifier]; annotationImage.styleIconIdentifier = updatedIconIdentifier; [self installAnnotationImage:annotationImage]; - + if ([iconIdentifier isEqualToString:fallbackIconIdentifier]) { // Update any annotations associated with the annotation image. @@ -3755,7 +3738,7 @@ public: { [self installAnnotationImage:self.defaultAnnotationImage]; } - + // Update any annotations associated with the annotation image. [self applyIconIdentifier:fallbackIconIdentifier toAnnotationsWithImageReuseIdentifier:reuseIdentifier]; } @@ -3834,11 +3817,11 @@ public: { [self.delegate mapViewWillStartLocatingUser:self]; } - + self.userLocation = [[MGLUserLocation alloc] initWithMapView:self]; - + MGLUserLocationAnnotationView *userLocationAnnotationView; - + if ([self.delegate respondsToSelector:@selector(mapView:viewForAnnotation:)]) { userLocationAnnotationView = (MGLUserLocationAnnotationView *)[self.delegate mapView:self viewForAnnotation:self.userLocation]; @@ -3852,11 +3835,11 @@ public: userLocationAnnotationView = nil; } } - + self.userLocationAnnotationView = userLocationAnnotationView ?: [[MGLFaux3DUserLocationAnnotationView alloc] init]; self.userLocationAnnotationView.mapView = self; self.userLocationAnnotationView.userLocation = self.userLocation; - + self.userLocationAnnotationView.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin); @@ -3934,7 +3917,7 @@ public: case MGLUserTrackingModeNone: { self.userTrackingState = MGLUserTrackingStatePossible; - + [self.locationManager stopUpdatingHeading]; // Immediately update the annotation view; other cases update inside @@ -3965,7 +3948,7 @@ public: { self.userTrackingState = animated ? MGLUserTrackingStatePossible : MGLUserTrackingStateChanged; } - + self.showsUserLocation = YES; if (self.zoomLevel < self.currentMinimumZoom) @@ -4066,7 +4049,7 @@ public: duration = MIN([newLocation.timestamp timeIntervalSinceDate:oldLocation.timestamp], MGLUserLocationAnimationDuration); } [self updateUserLocationAnnotationViewAnimatedWithDuration:duration]; - + if (self.userTrackingMode == MGLUserTrackingModeNone && self.userLocationAnnotationView.accessibilityElementIsFocused && [UIApplication sharedApplication].applicationState == UIApplicationStateActive) @@ -4084,7 +4067,7 @@ public: { return; } - + // If the user location annotation is already where it’s supposed to be, // don’t change the viewport. CGPoint correctPoint = self.userLocationAnnotationViewCenter; @@ -4094,7 +4077,7 @@ public: { return; } - + if (self.userTrackingMode == MGLUserTrackingModeFollowWithCourse && CLLocationCoordinate2DIsValid(self.targetCoordinate)) { @@ -4135,7 +4118,7 @@ public: - (void)didUpdateLocationSignificantlyAnimated:(BOOL)animated { self.userTrackingState = MGLUserTrackingStateBegan; - + MGLMapCamera *camera = self.camera; camera.centerCoordinate = self.userLocation.location.coordinate; camera.heading = self.directionByFollowingWithCourse; @@ -4146,7 +4129,7 @@ public: camera.centerCoordinate.latitude, self.frame.size); } - + __weak MGLMapView *weakSelf = self; [self _flyToCamera:camera edgePadding:self.edgePaddingForFollowing @@ -4179,7 +4162,7 @@ public: } }; } - + CLLocationCoordinate2D foci[] = { self.userLocation.location.coordinate, self.targetCoordinate, @@ -4203,7 +4186,7 @@ public: { // Center on user location unless we're already centered there (or very close). CGPoint correctPoint = self.userLocationAnnotationViewCenter; - + // Shift the entire frame upward or downward to accommodate a shifted user // location annotation view. CGRect bounds = self.bounds; @@ -4245,7 +4228,7 @@ public: { direction = self.userLocation.location.course; } - + if (direction >= 0) { if (self.userLocationVerticalAlignment == MGLAnnotationVerticalAlignmentTop) @@ -4345,7 +4328,7 @@ public: - (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(CGPoint)point inStyleLayersWithIdentifiers:(NS_SET_OF(NSString *) *)styleLayerIdentifiers { mbgl::ScreenCoordinate screenCoordinate = { point.x, point.y }; - + mbgl::optional<std::vector<std::string>> optionalLayerIDs; if (styleLayerIdentifiers) { @@ -4357,7 +4340,7 @@ public: }]; optionalLayerIDs = layerIDs; } - + std::vector<mbgl::Feature> features = _mbglMap->queryRenderedFeatures(screenCoordinate, optionalLayerIDs); return MGLFeaturesFromMBGLFeatures(features); } @@ -4371,7 +4354,7 @@ public: { CGRectGetMinX(rect), CGRectGetMinY(rect) }, { CGRectGetMaxX(rect), CGRectGetMaxY(rect) }, }; - + mbgl::optional<std::vector<std::string>> optionalLayerIDs; if (styleLayerIdentifiers) { __block std::vector<std::string> layerIDs; @@ -4381,7 +4364,7 @@ public: }]; optionalLayerIDs = layerIDs; } - + std::vector<mbgl::Feature> features = _mbglMap->queryRenderedFeatures(screenBox, optionalLayerIDs); return MGLFeaturesFromMBGLFeatures(features); } @@ -4412,7 +4395,7 @@ public: && state != UIGestureRecognizerStateChanged) { [self unrotateIfNeededAnimated:YES]; - + // Snap to north. if ((self.direction < MGLToleranceForSnappingToNorth || self.direction > 360 - MGLToleranceForSnappingToNorth) @@ -4585,21 +4568,21 @@ public: - (void)updateAnnotationViews { BOOL delegateImplementsViewForAnnotation = [self.delegate respondsToSelector:@selector(mapView:viewForAnnotation:)]; - + if (!delegateImplementsViewForAnnotation) { return; } - + [CATransaction begin]; [CATransaction setDisableActions:YES]; - + for (auto &pair : _annotationContextsByAnnotationTag) { CGRect viewPort = CGRectInset(self.bounds, -_largestAnnotationViewSize.width / 2.0 - MGLAnnotationUpdateViewportOutset.width / 2.0, -_largestAnnotationViewSize.height / 2.0 - MGLAnnotationUpdateViewportOutset.width); - + MGLAnnotationContext &annotationContext = pair.second; MGLAnnotationView *annotationView = annotationContext.annotationView; @@ -4617,7 +4600,7 @@ public: annotationView.mapView = self; annotationView.center = [self convertCoordinate:annotationContext.annotation.coordinate toPointToView:self]; annotationContext.annotationView = annotationView; - + if (!annotationView.superview) { [self.annotationContainerView insertSubview:annotationView atIndex:0]; } @@ -4628,7 +4611,7 @@ public: continue; } } - + bool annotationViewIsVisible = CGRectContainsRect(viewPort, annotationView.frame); if (!annotationViewIsVisible && annotationContext.viewReuseIdentifier) { @@ -4639,18 +4622,18 @@ public: annotationView.center = [self convertCoordinate:annotationContext.annotation.coordinate toPointToView:self]; } } - + [CATransaction commit]; } - (void)enqueueAnnotationViewForAnnotationContext:(MGLAnnotationContext &)annotationContext { MGLAnnotationView *annotationView = annotationContext.annotationView; - + if (!annotationView) return; - + annotationView.annotation = nil; - + if (annotationContext.viewReuseIdentifier) { NSMutableArray *annotationViewReuseQueue = [self annotationViewReuseQueueForIdentifier:annotationContext.viewReuseIdentifier]; @@ -4680,7 +4663,7 @@ public: { userPoint = [self convertCoordinate:self.userLocation.coordinate toPointToView:self]; } - + if ( ! annotationView.superview) { [self.glView addSubview:annotationView]; @@ -4709,10 +4692,10 @@ public: annotationView.center = userPoint; } completion:NULL]; _userLocationAnimationCompletionDate = [NSDate dateWithTimeIntervalSinceNow:duration]; - + annotationView.hidden = NO; [annotationView update]; - + if (_userLocationAnnotationIsSelected) { // Ensure the callout view still points to its annotation. @@ -4731,7 +4714,7 @@ public: // User has moved far enough outside of the viewport that showing it or // its callout would be useless. annotationView.hidden = YES; - + if (_userLocationAnnotationIsSelected) { [self deselectAnnotation:self.selectedAnnotation animated:YES]; @@ -4749,7 +4732,7 @@ public: contentFrame = self.contentFrame; } CGPoint center = CGPointMake(CGRectGetMidX(contentFrame), CGRectGetMidY(contentFrame)); - + // When tracking course, it’s more important to see the road ahead, so // weight the user dot down towards the bottom. switch (self.userLocationVerticalAlignment) { @@ -4762,7 +4745,7 @@ public: center.y = CGRectGetMaxY(contentFrame); break; } - + return center; } @@ -4771,7 +4754,7 @@ public: CLLocationDirection direction = self.direction; CLLocationDirection plateDirection = mbgl::util::wrap(-direction, 0., 360.); self.compassView.transform = CGAffineTransformMakeRotation(MGLRadiansFromDegrees(plateDirection)); - + self.compassView.isAccessibilityElement = direction > 0; self.compassView.accessibilityValue = [_accessibilityCompassFormatter stringFromDirection:direction]; @@ -4811,7 +4794,7 @@ public: [NSException raise:@"Resource not found" format: @"The resource named “%@” could not be found in the Mapbox framework bundle.", imageName]; } - + return [UIImage imageWithContentsOfFile:path]; } @@ -4928,7 +4911,7 @@ public: { _annotationViewReuseQueueByIdentifier[identifier] = [NSMutableArray array]; } - + return _annotationViewReuseQueueByIdentifier[identifier]; } @@ -5130,7 +5113,7 @@ public: MGLCustomStyleLayerDrawingHandler d, MGLCustomStyleLayerCompletionHandler f) : prepare(p), draw(d), finish(f) {} - + MGLCustomStyleLayerPreparationHandler prepare; MGLCustomStyleLayerDrawingHandler draw; MGLCustomStyleLayerCompletionHandler finish; diff --git a/platform/ios/src/UIImage+MGLAdditions.h b/platform/ios/src/UIImage+MGLAdditions.h new file mode 100644 index 0000000000..411220c503 --- /dev/null +++ b/platform/ios/src/UIImage+MGLAdditions.h @@ -0,0 +1,9 @@ +#import <UIKit/UIKit.h> + +#include <mbgl/sprite/sprite_image.hpp> + +@interface UIImage (MGLAdditions) + +- (std::unique_ptr<mbgl::SpriteImage>)mgl_spriteImage; + +@end diff --git a/platform/ios/src/UIImage+MGLAdditions.mm b/platform/ios/src/UIImage+MGLAdditions.mm new file mode 100644 index 0000000000..8ec8f9e15f --- /dev/null +++ b/platform/ios/src/UIImage+MGLAdditions.mm @@ -0,0 +1,27 @@ +#import "UIImage+MGLAdditions.h" + +@implementation UIImage (MGLAdditions) + +- (std::unique_ptr<mbgl::SpriteImage>)mgl_spriteImage +{ + CGImageRef cgImage = self.CGImage; + size_t width = CGImageGetWidth(cgImage); + size_t height = CGImageGetHeight(cgImage); + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + mbgl::PremultipliedImage cPremultipliedImage(width, height); + size_t bytesPerPixel = 4; + size_t bytesPerRow = bytesPerPixel * width; + size_t bitsPerComponent = 8; + + CGContextRef context = CGBitmapContextCreate(cPremultipliedImage.data.get(), + width, height, bitsPerComponent, bytesPerRow, + colorSpace, kCGImageAlphaPremultipliedLast); + + CGContextDrawImage(context, CGRectMake(0, 0, width, height), cgImage); + CGContextRelease(context); + CGColorSpaceRelease(colorSpace); + + return std::make_unique<mbgl::SpriteImage>(std::move(cPremultipliedImage), float(self.scale)); +} + +@end |