Merge branch 'master' into libuv-0.10-headless-display
Conflicts: common/curl_request.cpp common/glfw_view.cpp common/glfw_view.hpp include/mbgl/platform/request.hpp ios/mapbox-gl-cocoa setup-libraries.sh src/map/map.cpp src/platform/request.cpp test/fixtures/fixture_request.cpp
This commit is contained in:
2
Makefile
2
Makefile
@@ -108,4 +108,4 @@ distclean: clean
|
||||
-rm -rf ./mapnik-packaging/osx/out/universal
|
||||
-find ./mapnik-packaging/osx/out/packages -type d ! -name 'packages' -maxdepth 1 -exec rm -rf {} \;
|
||||
|
||||
.PHONY: mbgl test linux
|
||||
.PHONY: mbgl test linux build/test/Makefile
|
||||
|
||||
112
common/Reachability.h
Normal file
112
common/Reachability.h
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
Copyright (c) 2011, Tony Million.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <SystemConfiguration/SystemConfiguration.h>
|
||||
|
||||
#import <sys/socket.h>
|
||||
#import <netinet/in.h>
|
||||
#import <netinet6/in6.h>
|
||||
#import <arpa/inet.h>
|
||||
#import <ifaddrs.h>
|
||||
#import <netdb.h>
|
||||
|
||||
/**
|
||||
* Does ARC support GCD objects?
|
||||
* It does if the minimum deployment target is iOS 6+ or Mac OS X 8+
|
||||
*
|
||||
* @see http://opensource.apple.com/source/libdispatch/libdispatch-228.18/os/object.h
|
||||
**/
|
||||
#if OS_OBJECT_USE_OBJC
|
||||
#define NEEDS_DISPATCH_RETAIN_RELEASE 0
|
||||
#else
|
||||
#define NEEDS_DISPATCH_RETAIN_RELEASE 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Create NS_ENUM macro if it does not exist on the targeted version of iOS or OS X.
|
||||
*
|
||||
* @see http://nshipster.com/ns_enum-ns_options/
|
||||
**/
|
||||
#ifndef NS_ENUM
|
||||
#define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
|
||||
#endif
|
||||
|
||||
extern NSString *const kReachabilityChangedNotification;
|
||||
|
||||
typedef NS_ENUM(NSInteger, NetworkStatus) {
|
||||
// Apple NetworkStatus Compatible Names.
|
||||
NotReachable = 0,
|
||||
ReachableViaWiFi = 2,
|
||||
ReachableViaWWAN = 1
|
||||
};
|
||||
|
||||
@class Reachability;
|
||||
|
||||
typedef void (^NetworkReachable)(Reachability * reachability);
|
||||
typedef void (^NetworkUnreachable)(Reachability * reachability);
|
||||
|
||||
@interface Reachability : NSObject
|
||||
|
||||
@property (nonatomic, copy) NetworkReachable reachableBlock;
|
||||
@property (nonatomic, copy) NetworkUnreachable unreachableBlock;
|
||||
|
||||
|
||||
@property (nonatomic, assign) BOOL reachableOnWWAN;
|
||||
|
||||
+(Reachability*)reachabilityWithHostname:(NSString*)hostname;
|
||||
// This is identical to the function above, but is here to maintain
|
||||
//compatibility with Apples original code. (see .m)
|
||||
+(Reachability*)reachabilityWithHostName:(NSString*)hostname;
|
||||
+(Reachability*)reachabilityForInternetConnection;
|
||||
+(Reachability*)reachabilityWithAddress:(const struct sockaddr_in*)hostAddress;
|
||||
+(Reachability*)reachabilityForLocalWiFi;
|
||||
|
||||
-(Reachability *)initWithReachabilityRef:(SCNetworkReachabilityRef)ref;
|
||||
|
||||
-(BOOL)startNotifier;
|
||||
-(void)stopNotifier;
|
||||
|
||||
-(BOOL)isReachable;
|
||||
-(BOOL)isReachableViaWWAN;
|
||||
-(BOOL)isReachableViaWiFi;
|
||||
|
||||
// WWAN may be available, but not active until a connection has been established.
|
||||
// WiFi may require a connection for VPN on Demand.
|
||||
-(BOOL)isConnectionRequired; // Identical DDG variant.
|
||||
-(BOOL)connectionRequired; // Apple's routine.
|
||||
// Dynamic, on demand connection?
|
||||
-(BOOL)isConnectionOnDemand;
|
||||
// Is user intervention required?
|
||||
-(BOOL)isInterventionRequired;
|
||||
|
||||
-(NetworkStatus)currentReachabilityStatus;
|
||||
-(SCNetworkReachabilityFlags)reachabilityFlags;
|
||||
-(NSString*)currentReachabilityString;
|
||||
-(NSString*)currentReachabilityFlags;
|
||||
|
||||
@end
|
||||
527
common/Reachability.m
Normal file
527
common/Reachability.m
Normal file
@@ -0,0 +1,527 @@
|
||||
/*
|
||||
Copyright (c) 2011, Tony Million.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import "Reachability.h"
|
||||
|
||||
|
||||
NSString *const kReachabilityChangedNotification = @"kReachabilityChangedNotification";
|
||||
|
||||
@interface Reachability ()
|
||||
|
||||
@property (nonatomic, assign) SCNetworkReachabilityRef reachabilityRef;
|
||||
|
||||
|
||||
#if NEEDS_DISPATCH_RETAIN_RELEASE
|
||||
@property (nonatomic, assign) dispatch_queue_t reachabilitySerialQueue;
|
||||
#else
|
||||
@property (nonatomic, strong) dispatch_queue_t reachabilitySerialQueue;
|
||||
#endif
|
||||
|
||||
|
||||
@property (nonatomic, strong) id reachabilityObject;
|
||||
|
||||
-(void)reachabilityChanged:(SCNetworkReachabilityFlags)flags;
|
||||
-(BOOL)isReachableWithFlags:(SCNetworkReachabilityFlags)flags;
|
||||
|
||||
@end
|
||||
|
||||
static NSString *reachabilityFlags(SCNetworkReachabilityFlags flags)
|
||||
{
|
||||
return [NSString stringWithFormat:@"%c%c %c%c%c%c%c%c%c",
|
||||
#if TARGET_OS_IPHONE
|
||||
(flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-',
|
||||
#else
|
||||
'X',
|
||||
#endif
|
||||
(flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-'];
|
||||
}
|
||||
|
||||
// Start listening for reachability notifications on the current run loop
|
||||
static void TMReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info)
|
||||
{
|
||||
#pragma unused (target)
|
||||
#if __has_feature(objc_arc)
|
||||
Reachability *reachability = ((__bridge Reachability*)info);
|
||||
#else
|
||||
Reachability *reachability = ((Reachability*)info);
|
||||
#endif
|
||||
|
||||
// We probably don't need an autoreleasepool here, as GCD docs state each queue has its own autorelease pool,
|
||||
// but what the heck eh?
|
||||
@autoreleasepool
|
||||
{
|
||||
[reachability reachabilityChanged:flags];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@implementation Reachability
|
||||
|
||||
@synthesize reachabilityRef;
|
||||
@synthesize reachabilitySerialQueue;
|
||||
|
||||
@synthesize reachableOnWWAN;
|
||||
|
||||
@synthesize reachableBlock;
|
||||
@synthesize unreachableBlock;
|
||||
|
||||
@synthesize reachabilityObject;
|
||||
|
||||
#pragma mark - Class Constructor Methods
|
||||
|
||||
+(Reachability*)reachabilityWithHostName:(NSString*)hostname
|
||||
{
|
||||
return [Reachability reachabilityWithHostname:hostname];
|
||||
}
|
||||
|
||||
+(Reachability*)reachabilityWithHostname:(NSString*)hostname
|
||||
{
|
||||
SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithName(NULL, [hostname UTF8String]);
|
||||
if (ref)
|
||||
{
|
||||
id reachability = [[self alloc] initWithReachabilityRef:ref];
|
||||
|
||||
#if __has_feature(objc_arc)
|
||||
return reachability;
|
||||
#else
|
||||
return [reachability autorelease];
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
+(Reachability *)reachabilityWithAddress:(const struct sockaddr_in *)hostAddress
|
||||
{
|
||||
SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)hostAddress);
|
||||
if (ref)
|
||||
{
|
||||
id reachability = [[self alloc] initWithReachabilityRef:ref];
|
||||
|
||||
#if __has_feature(objc_arc)
|
||||
return reachability;
|
||||
#else
|
||||
return [reachability autorelease];
|
||||
#endif
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
+(Reachability *)reachabilityForInternetConnection
|
||||
{
|
||||
struct sockaddr_in zeroAddress;
|
||||
bzero(&zeroAddress, sizeof(zeroAddress));
|
||||
zeroAddress.sin_len = sizeof(zeroAddress);
|
||||
zeroAddress.sin_family = AF_INET;
|
||||
|
||||
return [self reachabilityWithAddress:&zeroAddress];
|
||||
}
|
||||
|
||||
+(Reachability*)reachabilityForLocalWiFi
|
||||
{
|
||||
struct sockaddr_in localWifiAddress;
|
||||
bzero(&localWifiAddress, sizeof(localWifiAddress));
|
||||
localWifiAddress.sin_len = sizeof(localWifiAddress);
|
||||
localWifiAddress.sin_family = AF_INET;
|
||||
// IN_LINKLOCALNETNUM is defined in <netinet/in.h> as 169.254.0.0
|
||||
localWifiAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM);
|
||||
|
||||
return [self reachabilityWithAddress:&localWifiAddress];
|
||||
}
|
||||
|
||||
|
||||
// Initialization methods
|
||||
|
||||
-(Reachability *)initWithReachabilityRef:(SCNetworkReachabilityRef)ref
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
self.reachableOnWWAN = YES;
|
||||
self.reachabilityRef = ref;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void)dealloc
|
||||
{
|
||||
[self stopNotifier];
|
||||
|
||||
if(self.reachabilityRef)
|
||||
{
|
||||
CFRelease(self.reachabilityRef);
|
||||
self.reachabilityRef = nil;
|
||||
}
|
||||
|
||||
self.reachableBlock = nil;
|
||||
self.unreachableBlock = nil;
|
||||
|
||||
#if !(__has_feature(objc_arc))
|
||||
[super dealloc];
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
|
||||
#pragma mark - Notifier Methods
|
||||
|
||||
// Notifier
|
||||
// NOTE: This uses GCD to trigger the blocks - they *WILL NOT* be called on THE MAIN THREAD
|
||||
// - In other words DO NOT DO ANY UI UPDATES IN THE BLOCKS.
|
||||
// INSTEAD USE dispatch_async(dispatch_get_main_queue(), ^{UISTUFF}) (or dispatch_sync if you want)
|
||||
|
||||
-(BOOL)startNotifier
|
||||
{
|
||||
SCNetworkReachabilityContext context = { 0, NULL, NULL, NULL, NULL };
|
||||
|
||||
// this should do a retain on ourself, so as long as we're in notifier mode we shouldn't disappear out from under ourselves
|
||||
// woah
|
||||
self.reachabilityObject = self;
|
||||
|
||||
|
||||
|
||||
// First, we need to create a serial queue.
|
||||
// We allocate this once for the lifetime of the notifier.
|
||||
self.reachabilitySerialQueue = dispatch_queue_create("com.tonymillion.reachability", NULL);
|
||||
if(self.reachabilitySerialQueue == nil)
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
#if __has_feature(objc_arc)
|
||||
context.info = (__bridge void *)self;
|
||||
#else
|
||||
context.info = (void *)self;
|
||||
#endif
|
||||
|
||||
if (!SCNetworkReachabilitySetCallback(self.reachabilityRef, TMReachabilityCallback, &context))
|
||||
{
|
||||
#ifdef DEBUG
|
||||
NSLog(@"SCNetworkReachabilitySetCallback() failed: %s", SCErrorString(SCError()));
|
||||
#endif
|
||||
|
||||
// Clear out the dispatch queue
|
||||
if(self.reachabilitySerialQueue)
|
||||
{
|
||||
#if NEEDS_DISPATCH_RETAIN_RELEASE
|
||||
dispatch_release(self.reachabilitySerialQueue);
|
||||
#endif
|
||||
self.reachabilitySerialQueue = nil;
|
||||
}
|
||||
|
||||
self.reachabilityObject = nil;
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Set it as our reachability queue, which will retain the queue
|
||||
if(!SCNetworkReachabilitySetDispatchQueue(self.reachabilityRef, self.reachabilitySerialQueue))
|
||||
{
|
||||
#ifdef DEBUG
|
||||
NSLog(@"SCNetworkReachabilitySetDispatchQueue() failed: %s", SCErrorString(SCError()));
|
||||
#endif
|
||||
|
||||
// UH OH - FAILURE!
|
||||
|
||||
// First stop, any callbacks!
|
||||
SCNetworkReachabilitySetCallback(self.reachabilityRef, NULL, NULL);
|
||||
|
||||
// Then clear out the dispatch queue.
|
||||
if(self.reachabilitySerialQueue)
|
||||
{
|
||||
#if NEEDS_DISPATCH_RETAIN_RELEASE
|
||||
dispatch_release(self.reachabilitySerialQueue);
|
||||
#endif
|
||||
self.reachabilitySerialQueue = nil;
|
||||
}
|
||||
|
||||
self.reachabilityObject = nil;
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(void)stopNotifier
|
||||
{
|
||||
// First stop, any callbacks!
|
||||
SCNetworkReachabilitySetCallback(self.reachabilityRef, NULL, NULL);
|
||||
|
||||
// Unregister target from the GCD serial dispatch queue.
|
||||
SCNetworkReachabilitySetDispatchQueue(self.reachabilityRef, NULL);
|
||||
|
||||
if(self.reachabilitySerialQueue)
|
||||
{
|
||||
#if NEEDS_DISPATCH_RETAIN_RELEASE
|
||||
dispatch_release(self.reachabilitySerialQueue);
|
||||
#endif
|
||||
self.reachabilitySerialQueue = nil;
|
||||
}
|
||||
|
||||
self.reachabilityObject = nil;
|
||||
}
|
||||
|
||||
#pragma mark - reachability tests
|
||||
|
||||
// This is for the case where you flick the airplane mode;
|
||||
// you end up getting something like this:
|
||||
//Reachability: WR ct-----
|
||||
//Reachability: -- -------
|
||||
//Reachability: WR ct-----
|
||||
//Reachability: -- -------
|
||||
// We treat this as 4 UNREACHABLE triggers - really apple should do better than this
|
||||
|
||||
#define testcase (kSCNetworkReachabilityFlagsConnectionRequired | kSCNetworkReachabilityFlagsTransientConnection)
|
||||
|
||||
-(BOOL)isReachableWithFlags:(SCNetworkReachabilityFlags)flags
|
||||
{
|
||||
BOOL connectionUP = YES;
|
||||
|
||||
if(!(flags & kSCNetworkReachabilityFlagsReachable))
|
||||
connectionUP = NO;
|
||||
|
||||
if( (flags & testcase) == testcase )
|
||||
connectionUP = NO;
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
if(flags & kSCNetworkReachabilityFlagsIsWWAN)
|
||||
{
|
||||
// We're on 3G.
|
||||
if(!self.reachableOnWWAN)
|
||||
{
|
||||
// We don't want to connect when on 3G.
|
||||
connectionUP = NO;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return connectionUP;
|
||||
}
|
||||
|
||||
-(BOOL)isReachable
|
||||
{
|
||||
SCNetworkReachabilityFlags flags;
|
||||
|
||||
if(!SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags))
|
||||
return NO;
|
||||
|
||||
return [self isReachableWithFlags:flags];
|
||||
}
|
||||
|
||||
-(BOOL)isReachableViaWWAN
|
||||
{
|
||||
#if TARGET_OS_IPHONE
|
||||
|
||||
SCNetworkReachabilityFlags flags = 0;
|
||||
|
||||
if(SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
|
||||
{
|
||||
// Check we're REACHABLE
|
||||
if(flags & kSCNetworkReachabilityFlagsReachable)
|
||||
{
|
||||
// Now, check we're on WWAN
|
||||
if(flags & kSCNetworkReachabilityFlagsIsWWAN)
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
-(BOOL)isReachableViaWiFi
|
||||
{
|
||||
SCNetworkReachabilityFlags flags = 0;
|
||||
|
||||
if(SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
|
||||
{
|
||||
// Check we're reachable
|
||||
if((flags & kSCNetworkReachabilityFlagsReachable))
|
||||
{
|
||||
#if TARGET_OS_IPHONE
|
||||
// Check we're NOT on WWAN
|
||||
if((flags & kSCNetworkReachabilityFlagsIsWWAN))
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
#endif
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
// WWAN may be available, but not active until a connection has been established.
|
||||
// WiFi may require a connection for VPN on Demand.
|
||||
-(BOOL)isConnectionRequired
|
||||
{
|
||||
return [self connectionRequired];
|
||||
}
|
||||
|
||||
-(BOOL)connectionRequired
|
||||
{
|
||||
SCNetworkReachabilityFlags flags;
|
||||
|
||||
if(SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
|
||||
{
|
||||
return (flags & kSCNetworkReachabilityFlagsConnectionRequired);
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Dynamic, on demand connection?
|
||||
-(BOOL)isConnectionOnDemand
|
||||
{
|
||||
SCNetworkReachabilityFlags flags;
|
||||
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
|
||||
{
|
||||
return ((flags & kSCNetworkReachabilityFlagsConnectionRequired) &&
|
||||
(flags & (kSCNetworkReachabilityFlagsConnectionOnTraffic | kSCNetworkReachabilityFlagsConnectionOnDemand)));
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Is user intervention required?
|
||||
-(BOOL)isInterventionRequired
|
||||
{
|
||||
SCNetworkReachabilityFlags flags;
|
||||
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
|
||||
{
|
||||
return ((flags & kSCNetworkReachabilityFlagsConnectionRequired) &&
|
||||
(flags & kSCNetworkReachabilityFlagsInterventionRequired));
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - reachability status stuff
|
||||
|
||||
-(NetworkStatus)currentReachabilityStatus
|
||||
{
|
||||
if([self isReachable])
|
||||
{
|
||||
if([self isReachableViaWiFi])
|
||||
return ReachableViaWiFi;
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
return ReachableViaWWAN;
|
||||
#endif
|
||||
}
|
||||
|
||||
return NotReachable;
|
||||
}
|
||||
|
||||
-(SCNetworkReachabilityFlags)reachabilityFlags
|
||||
{
|
||||
SCNetworkReachabilityFlags flags = 0;
|
||||
|
||||
if(SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
|
||||
{
|
||||
return flags;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
-(NSString*)currentReachabilityString
|
||||
{
|
||||
NetworkStatus temp = [self currentReachabilityStatus];
|
||||
|
||||
if(temp == reachableOnWWAN)
|
||||
{
|
||||
// Updated for the fact that we have CDMA phones now!
|
||||
return NSLocalizedString(@"Cellular", @"");
|
||||
}
|
||||
if (temp == ReachableViaWiFi)
|
||||
{
|
||||
return NSLocalizedString(@"WiFi", @"");
|
||||
}
|
||||
|
||||
return NSLocalizedString(@"No Connection", @"");
|
||||
}
|
||||
|
||||
-(NSString*)currentReachabilityFlags
|
||||
{
|
||||
return reachabilityFlags([self reachabilityFlags]);
|
||||
}
|
||||
|
||||
#pragma mark - Callback function calls this method
|
||||
|
||||
-(void)reachabilityChanged:(SCNetworkReachabilityFlags)flags
|
||||
{
|
||||
if([self isReachableWithFlags:flags])
|
||||
{
|
||||
if(self.reachableBlock)
|
||||
{
|
||||
self.reachableBlock(self);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(self.unreachableBlock)
|
||||
{
|
||||
self.unreachableBlock(self);
|
||||
}
|
||||
}
|
||||
|
||||
// this makes sure the change notification happens on the MAIN THREAD
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kReachabilityChangedNotification
|
||||
object:self];
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark - Debug Description
|
||||
|
||||
- (NSString *) description
|
||||
{
|
||||
NSString *description = [NSString stringWithFormat:@"<%@: %#x>",
|
||||
NSStringFromClass([self class]), (unsigned int) self];
|
||||
return description;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1 +0,0 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
@@ -1,115 +0,0 @@
|
||||
#import "foundation_request.h"
|
||||
|
||||
#include "TargetConditionals.h"
|
||||
#if TARGET_OS_IPHONE
|
||||
#import <UIKit/UIKit.h>
|
||||
#include <atomic>
|
||||
#endif
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <mbgl/platform/request.hpp>
|
||||
#include <mbgl/platform/platform.hpp>
|
||||
#include <mbgl/util/std.hpp>
|
||||
#include <mbgl/util/uv.hpp>
|
||||
|
||||
dispatch_once_t request_initialize = 0;
|
||||
NSURLSession *session = nullptr;
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
std::atomic<int> active_tasks;
|
||||
#endif
|
||||
|
||||
|
||||
// We're using a child class to make sure ARC is working correctly, as well as to add activity
|
||||
// indicators on iOS.
|
||||
class FoundationRequest : public mbgl::platform::Request {
|
||||
public:
|
||||
FoundationRequest(const std::string &url,
|
||||
std::function<void(mbgl::platform::Response *)> callback,
|
||||
std::shared_ptr<uv::loop> loop)
|
||||
: Request(url, callback, loop) {
|
||||
#if TARGET_OS_IPHONE
|
||||
active_tasks++;
|
||||
dispatch_async(dispatch_get_main_queue(), ^(void) {
|
||||
[[UIApplication sharedApplication]
|
||||
setNetworkActivityIndicatorVisible:(active_tasks > 0)];
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
~FoundationRequest() {
|
||||
#if TARGET_OS_IPHONE
|
||||
active_tasks--;
|
||||
dispatch_async(dispatch_get_main_queue(), ^(void) {
|
||||
[[UIApplication sharedApplication]
|
||||
setNetworkActivityIndicatorVisible:(active_tasks > 0)];
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
NSURLSessionDataTask *task = nullptr;
|
||||
};
|
||||
|
||||
std::shared_ptr<mbgl::platform::Request>
|
||||
mbgl::platform::request_http(const std::string &url,
|
||||
std::function<void(Response *)> callback,
|
||||
std::shared_ptr<uv::loop> loop) {
|
||||
dispatch_once(&request_initialize, ^{
|
||||
NSURLSessionConfiguration *sessionConfig =
|
||||
[NSURLSessionConfiguration defaultSessionConfiguration];
|
||||
sessionConfig.timeoutIntervalForResource = 30;
|
||||
sessionConfig.HTTPMaximumConnectionsPerHost = 8;
|
||||
sessionConfig.requestCachePolicy = NSURLRequestUseProtocolCachePolicy;
|
||||
|
||||
session = [NSURLSession sessionWithConfiguration:sessionConfig];
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
active_tasks = 0;
|
||||
#endif
|
||||
});
|
||||
|
||||
std::shared_ptr<FoundationRequest> req =
|
||||
std::make_shared<FoundationRequest>(url, callback, loop);
|
||||
|
||||
// Note that we are creating a new shared_ptr pointer(!) to make sure there is at least one
|
||||
// shared_ptr in existence while the NSURLSession is loading our data. We are making sure in the
|
||||
// callback that this pointer gets destroyed again.
|
||||
std::shared_ptr<Request> *req_ptr = new std::shared_ptr<Request>(req);
|
||||
|
||||
NSURLSessionDataTask *task = [session
|
||||
dataTaskWithURL:[NSURL URLWithString:@(url.c_str())]
|
||||
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
|
||||
if ([error code] == NSURLErrorCancelled) {
|
||||
// We intentionally cancelled this request. Make sure we clear the shared_ptr to resolve
|
||||
// the circular reference. We're referencing this shared_ptr by value so that the object
|
||||
// stays around until this completion handler is invoked.
|
||||
delete req_ptr;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!error && [response isKindOfClass:[NSHTTPURLResponse class]]) {
|
||||
(*req_ptr)->res->code = [(NSHTTPURLResponse *)response statusCode];
|
||||
(*req_ptr)->res->body = {(const char *)[data bytes], [data length]};
|
||||
} else {
|
||||
(*req_ptr)->res->error_message = [[error localizedDescription] UTF8String];
|
||||
}
|
||||
|
||||
(*req_ptr)->complete();
|
||||
|
||||
delete req_ptr;
|
||||
}];
|
||||
|
||||
req->task = task;
|
||||
|
||||
[task resume];
|
||||
return req;
|
||||
}
|
||||
|
||||
void mbgl::platform::cancel_request_http(const std::shared_ptr<Request> &req) {
|
||||
if (req) {
|
||||
[((FoundationRequest *)(req.get()))->task cancel];
|
||||
}
|
||||
}
|
||||
@@ -186,7 +186,9 @@ int GLFWView::run() {
|
||||
glfwWaitEvents();
|
||||
}
|
||||
|
||||
map->stop();
|
||||
map->stop([](void *) {
|
||||
glfwWaitEvents();
|
||||
});
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -199,6 +201,10 @@ void GLFWView::make_inactive() {
|
||||
glfwMakeContextCurrent(nullptr);
|
||||
}
|
||||
|
||||
void GLFWView::notify() {
|
||||
glfwPostEmptyEvent();
|
||||
}
|
||||
|
||||
void GLFWView::swap() {
|
||||
glfwPostEmptyEvent();
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ public:
|
||||
void swap();
|
||||
void make_active();
|
||||
void make_inactive();
|
||||
void notify();
|
||||
void notify_map_change(mbgl::MapChange change, mbgl::timestamp delay = 0);
|
||||
|
||||
static void key(GLFWwindow *window, int key, int scancode, int action, int mods);
|
||||
|
||||
@@ -161,6 +161,10 @@ HeadlessView::~HeadlessView() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void HeadlessView::notify() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
void HeadlessView::notify_map_change(mbgl::MapChange /*change*/, mbgl::timestamp /*delay*/) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ public:
|
||||
void resize(uint16_t width, uint16_t height, float pixelRatio);
|
||||
const std::unique_ptr<uint32_t[]> readPixels();
|
||||
|
||||
void notify();
|
||||
void notify_map_change(MapChange change, timestamp delay = 0);
|
||||
void make_active();
|
||||
void make_inactive();
|
||||
|
||||
149
common/http_request_baton_cocoa.mm
Normal file
149
common/http_request_baton_cocoa.mm
Normal file
@@ -0,0 +1,149 @@
|
||||
#include <mbgl/storage/http_request_baton.hpp>
|
||||
#include <mbgl/util/std.hpp>
|
||||
#include <mbgl/util/parsedate.h>
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include <mbgl/util/uv.hpp>
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#include <ctime>
|
||||
#include <xlocale.h>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
dispatch_once_t request_initialize = 0;
|
||||
NSURLSession *session = nullptr;
|
||||
|
||||
void HTTPRequestBaton::start(const util::ptr<HTTPRequestBaton> &ptr) {
|
||||
assert(uv_thread_self() == ptr->thread_id);
|
||||
|
||||
// Starts the request.
|
||||
util::ptr<HTTPRequestBaton> baton = ptr;
|
||||
|
||||
// Create a C locale
|
||||
static locale_t locale = newlocale(LC_ALL_MASK, nullptr, nullptr);
|
||||
|
||||
dispatch_once(&request_initialize, ^{
|
||||
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
|
||||
sessionConfig.timeoutIntervalForResource = 30;
|
||||
sessionConfig.HTTPMaximumConnectionsPerHost = 8;
|
||||
sessionConfig.requestCachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
|
||||
sessionConfig.URLCache = nil;
|
||||
|
||||
session = [NSURLSession sessionWithConfiguration:sessionConfig];
|
||||
});
|
||||
|
||||
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@(baton->path.c_str())]];
|
||||
if (baton->response) {
|
||||
if (!baton->response->etag.empty()) {
|
||||
[request addValue:@(baton->response->etag.c_str()) forHTTPHeaderField:@"If-None-Match"];
|
||||
} else if (baton->response->modified) {
|
||||
const time_t modified = baton->response->modified;
|
||||
struct tm *timeinfo = std::gmtime(&modified);
|
||||
char buffer[32];
|
||||
strftime_l(buffer, 32, "%a, %d %b %Y %H:%M:%S GMT", timeinfo, locale);
|
||||
[request addValue:@(buffer) forHTTPHeaderField:@"If-Modified-Since"];
|
||||
}
|
||||
}
|
||||
|
||||
NSURLSessionDataTask *task = [session dataTaskWithRequest:request
|
||||
completionHandler:^(NSData *data, NSURLResponse *res, NSError *error) {
|
||||
if (error) {
|
||||
if ([error code] == NSURLErrorCancelled) {
|
||||
// The response code remains at 0 to indicate cancelation.
|
||||
// In addition, we don't need any response object.
|
||||
baton->response.reset();
|
||||
baton->type = HTTPResponseType::Canceled;
|
||||
} else {
|
||||
// TODO: Use different codes for host not found, timeout, invalid URL etc.
|
||||
// These can be categorized in temporary and permanent errors.
|
||||
baton->response = std::make_unique<Response>();
|
||||
baton->response->code = [(NSHTTPURLResponse *)res statusCode];
|
||||
baton->response->message = [[error localizedDescription] UTF8String];
|
||||
|
||||
switch ([error code]) {
|
||||
case NSURLErrorBadServerResponse: // 5xx errors
|
||||
baton->type = HTTPResponseType::TemporaryError;
|
||||
break;
|
||||
|
||||
case NSURLErrorTimedOut:
|
||||
case NSURLErrorUserCancelledAuthentication:
|
||||
baton->type = HTTPResponseType::SingularError; // retry immediately
|
||||
break;
|
||||
|
||||
case NSURLErrorNetworkConnectionLost:
|
||||
case NSURLErrorCannotFindHost:
|
||||
case NSURLErrorCannotConnectToHost:
|
||||
case NSURLErrorDNSLookupFailed:
|
||||
case NSURLErrorNotConnectedToInternet:
|
||||
case NSURLErrorInternationalRoamingOff:
|
||||
case NSURLErrorCallIsActive:
|
||||
case NSURLErrorDataNotAllowed:
|
||||
baton->type = HTTPResponseType::ConnectionError;
|
||||
break;
|
||||
|
||||
default:
|
||||
baton->type = HTTPResponseType::PermanentError;
|
||||
}
|
||||
}
|
||||
} else if ([res isKindOfClass:[NSHTTPURLResponse class]]) {
|
||||
const long code = [(NSHTTPURLResponse *)res statusCode];
|
||||
if (code == 304) {
|
||||
// Assume a Response object already exists.
|
||||
assert(baton->response);
|
||||
} else {
|
||||
baton->response = std::make_unique<Response>();
|
||||
baton->response->code = code;
|
||||
baton->response->data = {(const char *)[data bytes], [data length]};
|
||||
}
|
||||
|
||||
if (code == 304) {
|
||||
baton->type = HTTPResponseType::NotModified;
|
||||
} else if (code == 200) {
|
||||
baton->type = HTTPResponseType::Successful;
|
||||
} else {
|
||||
baton->type = HTTPResponseType::PermanentError;
|
||||
}
|
||||
|
||||
NSDictionary *headers = [(NSHTTPURLResponse *)res allHeaderFields];
|
||||
NSString *cache_control = [headers objectForKey:@"Cache-Control"];
|
||||
if (cache_control) {
|
||||
baton->response->expires = Response::parseCacheControl([cache_control UTF8String]);
|
||||
}
|
||||
|
||||
NSString *last_modified = [headers objectForKey:@"Last-Modified"];
|
||||
if (last_modified) {
|
||||
baton->response->modified = parse_date([last_modified UTF8String]);
|
||||
}
|
||||
|
||||
NSString *etag = [headers objectForKey:@"ETag"];
|
||||
if (etag) {
|
||||
baton->response->etag = [etag UTF8String];
|
||||
}
|
||||
} else {
|
||||
// This should never happen.
|
||||
baton->type = HTTPResponseType::PermanentError;
|
||||
baton->response = std::make_unique<Response>();
|
||||
baton->response->code = -1;
|
||||
baton->response->message = "response class is not NSHTTPURLResponse";
|
||||
}
|
||||
|
||||
uv_async_send(baton->async);
|
||||
}];
|
||||
|
||||
[task resume];
|
||||
|
||||
baton->ptr = const_cast<void *>(CFBridgingRetain(task));
|
||||
}
|
||||
|
||||
void HTTPRequestBaton::stop(const util::ptr<HTTPRequestBaton> &ptr) {
|
||||
assert(uv_thread_self() == ptr->thread_id);
|
||||
assert(ptr->ptr);
|
||||
|
||||
NSURLSessionDataTask *task = CFBridgingRelease(ptr->ptr);
|
||||
ptr->ptr = nullptr;
|
||||
[task cancel];
|
||||
}
|
||||
|
||||
}
|
||||
465
common/http_request_baton_curl.cpp
Normal file
465
common/http_request_baton_curl.cpp
Normal file
@@ -0,0 +1,465 @@
|
||||
#include <mbgl/storage/http_request_baton.hpp>
|
||||
#include <mbgl/util/uv-messenger.h>
|
||||
#include <mbgl/util/std.hpp>
|
||||
#include <mbgl/util/ptr.hpp>
|
||||
|
||||
#include <uv.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include <queue>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <xlocale.h>
|
||||
|
||||
// This file contains code from http://curl.haxx.se/libcurl/c/multi-uv.html:
|
||||
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at http://curl.haxx.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/* Example application code using the multi socket interface to download
|
||||
multiple files at once, but instead of using curl_multi_perform and
|
||||
curl_multi_wait, which uses select(), we use libuv.
|
||||
It supports epoll, kqueue, etc. on unixes and fast IO completion ports on
|
||||
Windows, which means, it should be very fast on all platforms..
|
||||
|
||||
Written by Clemens Gruber, based on an outdated example from uvbook and
|
||||
some tests from libuv.
|
||||
|
||||
Requires libuv and (of course) libcurl.
|
||||
|
||||
See http://nikhilm.github.com/uvbook/ for more information on libuv.
|
||||
*/
|
||||
|
||||
// Handles the request thread + messaging to the thread.
|
||||
static uv_once_t once;
|
||||
static uv_loop_t loop;
|
||||
static uv_messenger_t start_messenger;
|
||||
static uv_messenger_t stop_messenger;
|
||||
static uv_thread_t thread;
|
||||
static unsigned long thread_id;
|
||||
|
||||
// Used as the CURL timer function to periodically check for socket updates.
|
||||
static uv_timer_t timeout;
|
||||
|
||||
// CURL multi handle that we use to request multiple URLs at the same time, without having to block
|
||||
// and spawn threads.
|
||||
static CURLM *multi = nullptr;
|
||||
|
||||
// CURL share handles are used for sharing session state (e.g.)
|
||||
static uv_mutex_t share_mutex;
|
||||
static CURLSH *share = nullptr;
|
||||
|
||||
// A queue that we use for storing resuable CURL easy handles to avoid creating and destroying them
|
||||
// all the time.
|
||||
static std::queue<CURL *> handles;
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
struct CURLContext {
|
||||
util::ptr<HTTPRequestBaton> baton;
|
||||
uv_poll_t *poll_handle = nullptr;
|
||||
curl_socket_t sockfd = 0;
|
||||
curl_slist *headers = nullptr;
|
||||
|
||||
CURLContext(const util::ptr<HTTPRequestBaton> &baton_) : baton(baton_) {
|
||||
}
|
||||
|
||||
~CURLContext() {
|
||||
// We are destructing the poll handle in a CURL callback already.
|
||||
assert(!poll_handle);
|
||||
|
||||
// Once the CURLContext gets destroyed, CURL doesn't need any headers anymore.
|
||||
if (headers) {
|
||||
curl_slist_free_all(headers);
|
||||
headers = nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Locks the CURL share handle
|
||||
void curl_share_lock(CURL *, curl_lock_data, curl_lock_access, void *) {
|
||||
uv_mutex_lock(&share_mutex);
|
||||
}
|
||||
|
||||
// Unlocks the CURL share handle
|
||||
void curl_share_unlock(CURL *, curl_lock_data, void *) {
|
||||
uv_mutex_unlock(&share_mutex);
|
||||
}
|
||||
|
||||
// This function must run in the CURL thread.
|
||||
// It is either called when the request is completed, or when we try to cancel the request.
|
||||
void finish_request(const util::ptr<HTTPRequestBaton> &baton) {
|
||||
assert(uv_thread_self() == thread_id);
|
||||
if (baton->ptr) {
|
||||
CURL *handle = (CURL *)baton->ptr;
|
||||
CURLMcode error = curl_multi_remove_handle(multi, handle);
|
||||
if (error != CURLM_OK) {
|
||||
baton->response = std::make_unique<Response>();
|
||||
baton->response->code = -1;
|
||||
baton->response->message = curl_multi_strerror(error);
|
||||
}
|
||||
|
||||
// Destroy the shared pointer. We still have one pointing to it
|
||||
CURLContext *context = nullptr;
|
||||
curl_easy_getinfo(handle, CURLINFO_PRIVATE, (char *)&context);
|
||||
curl_easy_setopt(handle, CURLOPT_PRIVATE, nullptr);
|
||||
delete context;
|
||||
|
||||
// TODO: delete the headers object again.
|
||||
|
||||
curl_easy_reset(handle);
|
||||
handles.push(handle);
|
||||
baton->ptr = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void curl_perform(uv_poll_t *req, int, int events) {
|
||||
int running_handles;
|
||||
int flags = 0;
|
||||
CURLContext *context = (CURLContext *)req->data;
|
||||
CURLMsg *message;
|
||||
int pending;
|
||||
|
||||
uv_timer_stop(&timeout);
|
||||
|
||||
if (events & UV_READABLE) {
|
||||
flags |= CURL_CSELECT_IN;
|
||||
}
|
||||
if (events & UV_WRITABLE) {
|
||||
flags |= CURL_CSELECT_OUT;
|
||||
}
|
||||
|
||||
curl_multi_socket_action(multi, context->sockfd, flags, &running_handles);
|
||||
|
||||
while ((message = curl_multi_info_read(multi, &pending))) {
|
||||
switch (message->msg) {
|
||||
case CURLMSG_DONE: {
|
||||
CURLContext *context = nullptr;
|
||||
curl_easy_getinfo(message->easy_handle, CURLINFO_PRIVATE, (char *)&context);
|
||||
|
||||
// Make a copy so that the Baton stays around even after we are calling finish_request
|
||||
util::ptr<HTTPRequestBaton> baton = context->baton;
|
||||
|
||||
// Add human-readable error code
|
||||
if (message->data.result != CURLE_OK) {
|
||||
baton->response->message = curl_easy_strerror(message->data.result);
|
||||
baton->response->code = -1;
|
||||
|
||||
switch (message->data.result) {
|
||||
case CURLE_COULDNT_RESOLVE_PROXY:
|
||||
case CURLE_COULDNT_RESOLVE_HOST:
|
||||
case CURLE_COULDNT_CONNECT:
|
||||
baton->type = HTTPResponseType::ConnectionError;
|
||||
break;
|
||||
|
||||
case CURLE_OPERATION_TIMEDOUT:
|
||||
baton->type = HTTPResponseType::TemporaryError;
|
||||
break;
|
||||
|
||||
default:
|
||||
baton->type = HTTPResponseType::PermanentError;
|
||||
}
|
||||
} else {
|
||||
long code = 0;
|
||||
curl_easy_getinfo(message->easy_handle, CURLINFO_RESPONSE_CODE, &code);
|
||||
|
||||
if (code != 304) {
|
||||
baton->response->code = code;
|
||||
}
|
||||
|
||||
if (code == 304) {
|
||||
baton->type = HTTPResponseType::NotModified;
|
||||
} else if (code == 200) {
|
||||
baton->type = HTTPResponseType::Successful;
|
||||
} else if (code >= 500 && code < 600) {
|
||||
baton->type = HTTPResponseType::TemporaryError;
|
||||
} else if (code >= 400 && code < 500) {
|
||||
baton->type = HTTPResponseType::PermanentError;
|
||||
} else {
|
||||
assert(!"code must be either 200 or 304");
|
||||
}
|
||||
}
|
||||
|
||||
// We're currently in the CURL request thread.
|
||||
finish_request(baton);
|
||||
|
||||
if (baton->async) {
|
||||
uv_async_send(baton->async);
|
||||
baton->async = nullptr;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
// This should never happen, because there are no other message types.
|
||||
throw std::runtime_error("CURLMSG returned unknown message type");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int handle_socket(CURL *handle, curl_socket_t sockfd, int action, void *, void *socketp) {
|
||||
CURLContext *context = nullptr;
|
||||
curl_easy_getinfo(handle, CURLINFO_PRIVATE, (char *)&context);
|
||||
|
||||
if (!socketp && action != CURL_POLL_REMOVE) {
|
||||
// We haven't initialized the socket yet, so we need to do this now.
|
||||
assert(context->sockfd == 0);
|
||||
context->sockfd = sockfd;
|
||||
assert(!context->poll_handle);
|
||||
context->poll_handle = new uv_poll_t;
|
||||
uv_poll_init_socket(&loop, context->poll_handle, sockfd);
|
||||
context->poll_handle->data = context;
|
||||
curl_multi_assign(multi, sockfd, context);
|
||||
}
|
||||
|
||||
if (context) {
|
||||
if (action == CURL_POLL_IN || action == CURL_POLL_INOUT) {
|
||||
uv_poll_start(context->poll_handle, UV_READABLE, curl_perform);
|
||||
}
|
||||
if (action == CURL_POLL_OUT || action == CURL_POLL_INOUT) {
|
||||
uv_poll_start(context->poll_handle, UV_WRITABLE, curl_perform);
|
||||
}
|
||||
if (action == CURL_POLL_REMOVE && socketp) {
|
||||
uv_poll_stop(context->poll_handle);
|
||||
uv_close((uv_handle_t *)context->poll_handle, [](uv_handle_t *handle) {
|
||||
delete (uv_poll_t *)handle;
|
||||
});
|
||||
context->poll_handle = nullptr;
|
||||
curl_multi_assign(multi, sockfd, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void on_timeout(uv_timer_t *) {
|
||||
int running_handles;
|
||||
CURLMcode error = curl_multi_socket_action(multi, CURL_SOCKET_TIMEOUT, 0, &running_handles);
|
||||
if (error != CURLM_OK) {
|
||||
throw std::runtime_error(std::string("CURL multi error: ") + curl_multi_strerror(error));
|
||||
}
|
||||
}
|
||||
|
||||
void start_timeout(CURLM *, long timeout_ms, void *) {
|
||||
if (timeout_ms <= 0) {
|
||||
on_timeout(&timeout);
|
||||
} else {
|
||||
uv_timer_start(&timeout, on_timeout, timeout_ms, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void thread_init(void *) {
|
||||
#ifdef __APPLE__
|
||||
pthread_setname_np("CURL");
|
||||
#endif
|
||||
thread_id = uv_thread_self();
|
||||
|
||||
uv_timer_init(&loop, &timeout);
|
||||
|
||||
CURLSHcode share_error;
|
||||
share = curl_share_init();
|
||||
|
||||
share_error = curl_share_setopt(share, CURLSHOPT_LOCKFUNC, curl_share_lock);
|
||||
if (share_error != CURLSHE_OK) {
|
||||
throw std::runtime_error(std::string("CURL share error: ") + curl_share_strerror(share_error));
|
||||
}
|
||||
|
||||
share_error = curl_share_setopt(share, CURLSHOPT_UNLOCKFUNC, curl_share_unlock);
|
||||
if (share_error != CURLSHE_OK) {
|
||||
throw std::runtime_error(std::string("CURL share error: ") + curl_share_strerror(share_error));
|
||||
}
|
||||
|
||||
|
||||
CURLMcode multi_error;
|
||||
multi = curl_multi_init();
|
||||
|
||||
multi_error = curl_multi_setopt(multi, CURLMOPT_SOCKETFUNCTION, handle_socket);
|
||||
if (multi_error != CURLM_OK) {
|
||||
throw std::runtime_error(std::string("CURL multi error: ") + curl_multi_strerror(multi_error));
|
||||
}
|
||||
multi_error = curl_multi_setopt(multi, CURLMOPT_TIMERFUNCTION, start_timeout);
|
||||
if (multi_error != CURLM_OK) {
|
||||
throw std::runtime_error(std::string("CURL multi error: ") + curl_multi_strerror(multi_error));
|
||||
|
||||
}
|
||||
|
||||
// Main event loop. This will not return until the request loop is terminated.
|
||||
uv_run(&loop, UV_RUN_DEFAULT);
|
||||
|
||||
curl_multi_cleanup(multi);
|
||||
multi = nullptr;
|
||||
|
||||
curl_share_cleanup(share);
|
||||
share = nullptr;
|
||||
|
||||
thread_id = -1;
|
||||
}
|
||||
|
||||
// This function is called when we have new data for a request. We just append it to the string
|
||||
// containing the previous data.
|
||||
size_t curl_write_cb(void *const contents, const size_t size, const size_t nmemb, void *const userp) {
|
||||
((std::string *)userp)->append((char *)contents, size * nmemb);
|
||||
return size * nmemb;
|
||||
}
|
||||
|
||||
// Compares the beginning of the (non-zero-terminated!) data buffer with the (zero-terminated!)
|
||||
// header string. If the data buffer contains the header string at the beginning, it returns
|
||||
// the length of the header string == begin of the value, otherwise it returns npos.
|
||||
// The comparison of the header is ASCII-case-insensitive.
|
||||
size_t header_matches(const char *const header, const char *const buffer, const size_t length) {
|
||||
const size_t header_length = strlen(header);
|
||||
if (length < header_length) return std::string::npos;
|
||||
size_t i = 0;
|
||||
while (i < length && i < header_length && std::tolower(buffer[i]) == header[i]) {
|
||||
i++;
|
||||
}
|
||||
return i == header_length ? i : std::string::npos;
|
||||
}
|
||||
|
||||
size_t curl_header_cb(char * const buffer, const size_t size, const size_t nmemb, void *const userp) {
|
||||
const size_t length = size * nmemb;
|
||||
|
||||
Response *response = static_cast<Response *>(userp);
|
||||
|
||||
size_t begin = std::string::npos;
|
||||
if ((begin = header_matches("last-modified: ", buffer, length)) != std::string::npos) {
|
||||
// Always overwrite the modification date; We might already have a value here from the
|
||||
// Date header, but this one is more accurate.
|
||||
const std::string value { buffer + begin, length - begin - 2 }; // remove \r\n
|
||||
response->modified = curl_getdate(value.c_str(), nullptr);
|
||||
} else if ((begin = header_matches("etag: ", buffer, length)) != std::string::npos) {
|
||||
response->etag = { buffer + begin, length - begin - 2 }; // remove \r\n
|
||||
} else if ((begin = header_matches("cache-control: ", buffer, length)) != std::string::npos) {
|
||||
const std::string value { buffer + begin, length - begin - 2 }; // remove \r\n
|
||||
response->expires = Response::parseCacheControl(value.c_str());
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
// This function must run in the CURL thread.
|
||||
void start_request(void *const ptr) {
|
||||
assert(uv_thread_self() == thread_id);
|
||||
std::unique_ptr<util::ptr<HTTPRequestBaton>> baton_guard { (util::ptr<HTTPRequestBaton> *)ptr };
|
||||
util::ptr<HTTPRequestBaton> &baton = *baton_guard.get();
|
||||
assert(baton);
|
||||
|
||||
// Create a C locale
|
||||
static locale_t locale = newlocale(LC_ALL_MASK, nullptr, nullptr);
|
||||
|
||||
CURL *handle = nullptr;
|
||||
if (!handles.empty()) {
|
||||
handle = handles.front();
|
||||
handles.pop();
|
||||
} else {
|
||||
handle = curl_easy_init();
|
||||
}
|
||||
|
||||
baton->ptr = handle;
|
||||
|
||||
// Wrap this in a unique_ptr for now so that it destructs until we assign it the the CURL handle.
|
||||
std::unique_ptr<CURLContext> context = std::make_unique<CURLContext>(baton);
|
||||
|
||||
if (baton->response) {
|
||||
if (!baton->response->etag.empty()) {
|
||||
const std::string header = std::string("If-None-Match: ") + baton->response->etag;
|
||||
context->headers = curl_slist_append(context->headers, header.c_str());
|
||||
} else if (baton->response->modified) {
|
||||
const time_t modified = baton->response->modified;
|
||||
struct tm *timeinfo = std::gmtime(&modified);
|
||||
char buffer[64];
|
||||
strftime_l(buffer, 64, "If-Modified-Since: %a, %d %b %Y %H:%M:%S GMT", timeinfo, locale);
|
||||
context->headers = curl_slist_append(context->headers, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
if (context->headers) {
|
||||
curl_easy_setopt(handle, CURLOPT_HTTPHEADER, context->headers);
|
||||
}
|
||||
|
||||
if (!baton->response) {
|
||||
baton->response = std::make_unique<Response>();
|
||||
}
|
||||
|
||||
// Carry on the shared pointer in the private information of the CURL handle.
|
||||
curl_easy_setopt(handle, CURLOPT_PRIVATE, context.release());
|
||||
curl_easy_setopt(handle, CURLOPT_CAINFO, "ca-bundle.crt");
|
||||
curl_easy_setopt(handle, CURLOPT_URL, baton->path.c_str());
|
||||
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, curl_write_cb);
|
||||
curl_easy_setopt(handle, CURLOPT_WRITEDATA, &baton->response->data);
|
||||
curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, curl_header_cb);
|
||||
curl_easy_setopt(handle, CURLOPT_HEADERDATA, baton->response.get());
|
||||
curl_easy_setopt(handle, CURLOPT_ACCEPT_ENCODING, "gzip, deflate");
|
||||
curl_easy_setopt(handle, CURLOPT_SHARE, share);
|
||||
|
||||
// Start requesting the information.
|
||||
curl_multi_add_handle(multi, handle);
|
||||
}
|
||||
|
||||
// This function must run in the CURL thread.
|
||||
void stop_request(void *const ptr) {
|
||||
assert(uv_thread_self() == thread_id);
|
||||
std::unique_ptr<util::ptr<HTTPRequestBaton>> baton_guard { (util::ptr<HTTPRequestBaton> *)ptr };
|
||||
util::ptr<HTTPRequestBaton> &baton = *baton_guard.get();
|
||||
assert(baton);
|
||||
|
||||
if (baton->async) {
|
||||
baton->type = HTTPResponseType::Canceled;
|
||||
|
||||
// We can still stop the request because it is still in progress.
|
||||
finish_request(baton);
|
||||
|
||||
uv_async_send(baton->async);
|
||||
baton->async = nullptr;
|
||||
} else {
|
||||
// If the async handle is gone, it means that the actual request has been completed before
|
||||
// we got a chance to cancel it. In this case, this is a no-op. It is likely that
|
||||
// the pointer below is the last lifeline of the HTTPRequestBaton. This means we're going
|
||||
// to delete the HTTPRequestBaton in the current (CURL) thread.
|
||||
}
|
||||
}
|
||||
|
||||
void create_thread() {
|
||||
uv_mutex_init(&share_mutex);
|
||||
uv_loop_init(&loop);
|
||||
uv_messenger_init(&loop, &start_messenger, start_request);
|
||||
uv_messenger_init(&loop, &stop_messenger, stop_request);
|
||||
uv_thread_create(&thread, thread_init, nullptr);
|
||||
}
|
||||
|
||||
// This function must be run from the main thread (== where the HTTPRequestBaton was created)
|
||||
void HTTPRequestBaton::start(const util::ptr<HTTPRequestBaton> &ptr) {
|
||||
assert(uv_thread_self() == ptr->thread_id);
|
||||
uv_once(&once, create_thread);
|
||||
uv_messenger_send(&start_messenger, new util::ptr<HTTPRequestBaton>(ptr));
|
||||
}
|
||||
|
||||
// This function must be run from the main thread (== where the HTTPRequestBaton was created)
|
||||
void HTTPRequestBaton::stop(const util::ptr<HTTPRequestBaton> &ptr) {
|
||||
assert(uv_thread_self() == ptr->thread_id);
|
||||
uv_once(&once, create_thread);
|
||||
uv_messenger_send(&stop_messenger, new util::ptr<HTTPRequestBaton>(ptr));
|
||||
}
|
||||
|
||||
}
|
||||
21
common/ios.mm
Normal file
21
common/ios.mm
Normal file
@@ -0,0 +1,21 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#include <mbgl/platform/platform.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace platform {
|
||||
|
||||
// Returns the path to the default cache database on this system.
|
||||
std::string defaultCacheDatabase() {
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
|
||||
if ([paths count] == 0) {
|
||||
// Disable the cache if we don't have a location to write.
|
||||
return "";
|
||||
}
|
||||
|
||||
NSString *libraryDirectory = [paths objectAtIndex:0];
|
||||
return [[libraryDirectory stringByAppendingPathComponent:@"cache.db"] UTF8String];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
12
common/linux.cpp
Normal file
12
common/linux.cpp
Normal file
@@ -0,0 +1,12 @@
|
||||
#include <mbgl/platform/platform.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace platform {
|
||||
|
||||
// Returns the path to the default cache database on this system.
|
||||
std::string defaultCacheDatabase() {
|
||||
return "/tmp/mbgl-cache.db";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
31
common/osx.mm
Normal file
31
common/osx.mm
Normal file
@@ -0,0 +1,31 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#include <mbgl/platform/platform.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace platform {
|
||||
|
||||
// Returns the path to the default cache database on this system.
|
||||
std::string defaultCacheDatabase() {
|
||||
NSArray *paths =
|
||||
NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
|
||||
if ([paths count] == 0) {
|
||||
// Disable the cache if we don't have a location to write.
|
||||
return "";
|
||||
}
|
||||
|
||||
NSString *path = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"Mapbox GL"];
|
||||
|
||||
if (![[NSFileManager defaultManager] createDirectoryAtPath:path
|
||||
withIntermediateDirectories:YES
|
||||
attributes:nil
|
||||
error:nil]) {
|
||||
// Disable the cache if we couldn't create the directory.
|
||||
return "";
|
||||
}
|
||||
|
||||
return [[path stringByAppendingPathComponent:@"cache.db"] UTF8String];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
9
configure
vendored
9
configure
vendored
@@ -107,6 +107,14 @@ def configure_curl(o):
|
||||
o['variables']['curl_libraries'] = ret[0].split()
|
||||
o['variables']['curl_cflags'] = ret[1].split()
|
||||
|
||||
def configure_sqlite3(o):
|
||||
ret = pkg_config('sqlite3', options.pkgconfig_root)
|
||||
if not ret:
|
||||
sys.stderr.write('could not find sqlite3 with pkg-config')
|
||||
sys.exit(-1)
|
||||
o['variables']['sqlite3_libraries'] = ret[0].split()
|
||||
o['variables']['sqlite3_cflags'] = ret[1].split()
|
||||
|
||||
def write(filename, data):
|
||||
filename = os.path.join(root_dir, filename)
|
||||
print "creating ", filename
|
||||
@@ -129,6 +137,7 @@ if __name__ == '__main__':
|
||||
configure_uv(output)
|
||||
configure_png(output)
|
||||
configure_curl(output)
|
||||
configure_sqlite3(output)
|
||||
pprint.pprint(output, indent=2)
|
||||
|
||||
write('config.gypi', "# Do not edit. Generated by the configure script.\n" +
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
#include <mbgl/util/time.hpp>
|
||||
#include <mbgl/util/uv.hpp>
|
||||
#include <mbgl/util/ptr.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <atomic>
|
||||
#include <iosfwd>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
@@ -31,21 +31,31 @@ class FileSource;
|
||||
class View;
|
||||
|
||||
class Map : private util::noncopyable {
|
||||
typedef void (*stop_callback)(void *);
|
||||
|
||||
public:
|
||||
explicit Map(View &view);
|
||||
~Map();
|
||||
|
||||
// Start/stop the map render thread
|
||||
// Start the map render thread. It is asynchronous.
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
// Runs the map event loop.
|
||||
// Stop the map render thread. This call will block until the map rendering thread stopped.
|
||||
// The optional callback function will be invoked repeatedly until the map thread is stopped.
|
||||
// The callback function should wait until it is woken up again by view.notify(), otherwise
|
||||
// this will be a busy waiting loop. The optional data parameter will be passed to the callback
|
||||
// function.
|
||||
void stop(stop_callback cb = nullptr, void *data = nullptr);
|
||||
|
||||
// Runs the map event loop. ONLY run this function when you want to get render a single frame
|
||||
// with this map object. It will *not* spawn a separate thread and instead block until the
|
||||
// frame is completely rendered.
|
||||
void run();
|
||||
|
||||
// Triggers a lazy rerender: only performs a render when the map is not clean.
|
||||
void rerender();
|
||||
|
||||
void renderLayer(std::shared_ptr<StyleLayer> layer_desc, RenderPass pass, const Tile::ID* id = nullptr, const mat4* matrix = nullptr);
|
||||
void renderLayer(util::ptr<StyleLayer> layer_desc, RenderPass pass, const Tile::ID* id = nullptr, const mat4* matrix = nullptr);
|
||||
|
||||
// Forces a map update: always triggers a rerender.
|
||||
void update();
|
||||
@@ -65,7 +75,7 @@ public:
|
||||
void resize(uint16_t width, uint16_t height, float ratio, uint16_t fb_width, uint16_t fb_height);
|
||||
|
||||
// Styling
|
||||
const std::set<std::shared_ptr<StyleSource>> getActiveSources() const;
|
||||
const std::set<util::ptr<StyleSource>> getActiveSources() const;
|
||||
void setAppliedClasses(const std::vector<std::string> &classes);
|
||||
void toggleClass(const std::string &name);
|
||||
const std::vector<std::string> &getAppliedClasses() const;
|
||||
@@ -116,16 +126,20 @@ public:
|
||||
void toggleDebug();
|
||||
bool getDebug() const;
|
||||
|
||||
// Call this when the network reachability changed.
|
||||
void setReachability(bool status);
|
||||
|
||||
public:
|
||||
inline const TransformState &getState() const { return state; }
|
||||
inline std::shared_ptr<FileSource> getFileSource() const { return fileSource; }
|
||||
inline std::shared_ptr<Style> getStyle() const { return style; }
|
||||
inline std::shared_ptr<GlyphAtlas> getGlyphAtlas() { return glyphAtlas; }
|
||||
inline std::shared_ptr<GlyphStore> getGlyphStore() { return glyphStore; }
|
||||
inline std::shared_ptr<SpriteAtlas> getSpriteAtlas() { return spriteAtlas; }
|
||||
std::shared_ptr<Sprite> getSprite();
|
||||
inline std::shared_ptr<Texturepool> getTexturepool() { return texturepool; }
|
||||
inline std::shared_ptr<uv::loop> getLoop() { return loop; }
|
||||
inline util::ptr<FileSource> getFileSource() const { return fileSource; }
|
||||
inline util::ptr<Style> getStyle() const { return style; }
|
||||
inline util::ptr<GlyphAtlas> getGlyphAtlas() { return glyphAtlas; }
|
||||
inline util::ptr<GlyphStore> getGlyphStore() { return glyphStore; }
|
||||
inline util::ptr<SpriteAtlas> getSpriteAtlas() { return spriteAtlas; }
|
||||
util::ptr<Sprite> getSprite();
|
||||
inline util::ptr<Texturepool> getTexturepool() { return texturepool; }
|
||||
inline util::ptr<uv::loop> getLoop() { return loop; }
|
||||
uv::worker &getWorker();
|
||||
inline timestamp getAnimationTime() const { return animationTime; }
|
||||
inline timestamp getTime() const { return animationTime; }
|
||||
void updateTiles();
|
||||
@@ -141,7 +155,7 @@ private:
|
||||
void setup();
|
||||
|
||||
void updateSources();
|
||||
void updateSources(const std::shared_ptr<StyleLayerGroup> &group);
|
||||
void updateSources(const util::ptr<StyleLayerGroup> &group);
|
||||
|
||||
void updateRenderState();
|
||||
|
||||
@@ -154,15 +168,16 @@ private:
|
||||
|
||||
// Unconditionally performs a render with the current map state.
|
||||
void render();
|
||||
void renderLayers(std::shared_ptr<StyleLayerGroup> group);
|
||||
void renderLayers(util::ptr<StyleLayerGroup> group);
|
||||
|
||||
private:
|
||||
bool async = false;
|
||||
std::shared_ptr<uv::loop> loop;
|
||||
util::ptr<uv::loop> loop;
|
||||
std::unique_ptr<uv::worker> workers;
|
||||
std::unique_ptr<uv::thread> thread;
|
||||
uv_async_t *async_terminate = nullptr;
|
||||
uv_async_t *async_render = nullptr;
|
||||
uv_async_t *async_cleanup = nullptr;
|
||||
std::unique_ptr<uv_async_t> async_terminate;
|
||||
std::unique_ptr<uv_async_t> async_render;
|
||||
std::unique_ptr<uv_async_t> async_cleanup;
|
||||
|
||||
private:
|
||||
// If cleared, the next time the render thread attempts to render the map, it will *actually*
|
||||
@@ -177,24 +192,33 @@ private:
|
||||
// ready for rendering.
|
||||
std::atomic_flag is_rendered = ATOMIC_FLAG_INIT;
|
||||
|
||||
// Stores whether the map thread has been stopped already.
|
||||
std::atomic_bool is_stopped;
|
||||
|
||||
public:
|
||||
View &view;
|
||||
|
||||
private:
|
||||
#ifndef NDEBUG
|
||||
const unsigned long main_thread;
|
||||
unsigned long map_thread = -1;
|
||||
#endif
|
||||
|
||||
Transform transform;
|
||||
TransformState state;
|
||||
|
||||
std::shared_ptr<FileSource> fileSource;
|
||||
util::ptr<FileSource> fileSource;
|
||||
|
||||
std::shared_ptr<Style> style;
|
||||
std::shared_ptr<GlyphAtlas> glyphAtlas;
|
||||
std::shared_ptr<GlyphStore> glyphStore;
|
||||
std::shared_ptr<SpriteAtlas> spriteAtlas;
|
||||
std::shared_ptr<Sprite> sprite;
|
||||
std::shared_ptr<Texturepool> texturepool;
|
||||
util::ptr<Style> style;
|
||||
util::ptr<GlyphAtlas> glyphAtlas;
|
||||
util::ptr<GlyphStore> glyphStore;
|
||||
util::ptr<SpriteAtlas> spriteAtlas;
|
||||
util::ptr<Sprite> sprite;
|
||||
util::ptr<Texturepool> texturepool;
|
||||
|
||||
Painter painter;
|
||||
|
||||
std::string styleURL;
|
||||
std::string styleJSON = "";
|
||||
std::string accessToken = "";
|
||||
|
||||
@@ -203,7 +227,7 @@ private:
|
||||
|
||||
int indent = 0;
|
||||
|
||||
std::set<std::shared_ptr<StyleSource>> activeSources;
|
||||
std::set<util::ptr<StyleSource>> activeSources;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
#include <mbgl/map/tile_data.hpp>
|
||||
#include <mbgl/renderer/raster_bucket.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class Map;
|
||||
@@ -18,12 +16,12 @@ class RasterTileData : public TileData {
|
||||
friend class TileParser;
|
||||
|
||||
public:
|
||||
RasterTileData(Tile::ID id, Map &map, const SourceInfo &source);
|
||||
RasterTileData(Tile::ID id, Map &map, const util::ptr<SourceInfo> &source);
|
||||
~RasterTileData();
|
||||
|
||||
virtual void parse();
|
||||
virtual void render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc, const mat4 &matrix);
|
||||
virtual bool hasData(std::shared_ptr<StyleLayer> layer_desc) const;
|
||||
virtual void render(Painter &painter, util::ptr<StyleLayer> layer_desc, const mat4 &matrix);
|
||||
virtual bool hasData(util::ptr<StyleLayer> layer_desc) const;
|
||||
|
||||
protected:
|
||||
StyleBucketRaster properties;
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
#include <mbgl/util/time.hpp>
|
||||
#include <mbgl/util/mat4.hpp>
|
||||
#include <mbgl/util/ptr.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <forward_list>
|
||||
#include <iosfwd>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
@@ -25,7 +25,7 @@ struct box;
|
||||
|
||||
class Source : public std::enable_shared_from_this<Source>, private util::noncopyable {
|
||||
public:
|
||||
Source(SourceInfo& info);
|
||||
Source(const util::ptr<SourceInfo>& info);
|
||||
|
||||
void load(Map &map);
|
||||
|
||||
@@ -33,8 +33,8 @@ public:
|
||||
void updateMatrices(const mat4 &projMatrix, const TransformState &transform);
|
||||
void drawClippingMasks(Painter &painter);
|
||||
size_t getTileCount() const;
|
||||
void render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc);
|
||||
void render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID &id, const mat4 &matrix);
|
||||
void render(Painter &painter, util::ptr<StyleLayer> layer_desc);
|
||||
void render(Painter &painter, util::ptr<StyleLayer> layer_desc, const Tile::ID &id, const mat4 &matrix);
|
||||
void finishRender(Painter &painter);
|
||||
|
||||
std::forward_list<Tile::ID> getIDs() const;
|
||||
@@ -54,7 +54,7 @@ private:
|
||||
|
||||
double getZoom(const TransformState &state) const;
|
||||
|
||||
SourceInfo& info;
|
||||
util::ptr<SourceInfo> info;
|
||||
bool loaded = false;
|
||||
|
||||
// Stores the time when this source was most recently updated.
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
|
||||
#include <mbgl/util/image.hpp>
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
#include <mbgl/util/ptr.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <atomic>
|
||||
#include <iosfwd>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <future>
|
||||
@@ -34,11 +34,11 @@ public:
|
||||
class Sprite : public std::enable_shared_from_this<Sprite>, private util::noncopyable {
|
||||
private:
|
||||
struct Key {};
|
||||
void load(const std::shared_ptr<FileSource> &fileSource);
|
||||
void load(const util::ptr<FileSource> &fileSource);
|
||||
|
||||
public:
|
||||
Sprite(const Key &, const std::string& base_url, float pixelRatio);
|
||||
static std::shared_ptr<Sprite> Create(const std::string& base_url, float pixelRatio, const std::shared_ptr<FileSource> &fileSource);
|
||||
static util::ptr<Sprite> Create(const std::string& base_url, float pixelRatio, const util::ptr<FileSource> &fileSource);
|
||||
|
||||
const SpritePosition &getSpritePosition(const std::string& name) const;
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <mbgl/util/mat4.hpp>
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
#include <mbgl/util/ptr.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <bitset>
|
||||
@@ -10,7 +11,6 @@
|
||||
#include <cstdint>
|
||||
#include <forward_list>
|
||||
#include <iosfwd>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace mbgl {
|
||||
@@ -78,7 +78,7 @@ public:
|
||||
const Tile::ID id;
|
||||
ClipID clip;
|
||||
mat4 matrix;
|
||||
std::shared_ptr<TileData> data;
|
||||
util::ptr<TileData> data;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
#include <mbgl/geometry/debug_font_buffer.hpp>
|
||||
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
#include <mbgl/util/ptr.hpp>
|
||||
|
||||
#include <atomic>
|
||||
#include <exception>
|
||||
#include <iosfwd>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace mbgl {
|
||||
@@ -19,8 +19,7 @@ class Map;
|
||||
class Painter;
|
||||
class SourceInfo;
|
||||
class StyleLayer;
|
||||
|
||||
namespace platform { class Request; }
|
||||
class Request;
|
||||
|
||||
class TileData : public std::enable_shared_from_this<TileData>,
|
||||
private util::noncopyable {
|
||||
@@ -29,7 +28,7 @@ public:
|
||||
struct geometry_too_long_exception : exception {};
|
||||
|
||||
public:
|
||||
typedef std::shared_ptr<TileData> Ptr;
|
||||
typedef util::ptr<TileData> Ptr;
|
||||
|
||||
enum class State {
|
||||
invalid,
|
||||
@@ -41,7 +40,7 @@ public:
|
||||
};
|
||||
|
||||
public:
|
||||
TileData(Tile::ID id, Map &map, const SourceInfo &source);
|
||||
TileData(Tile::ID id, Map &map, const util::ptr<SourceInfo> &source);
|
||||
~TileData();
|
||||
|
||||
void request();
|
||||
@@ -57,8 +56,8 @@ public:
|
||||
virtual void beforeParse();
|
||||
virtual void parse() = 0;
|
||||
virtual void afterParse();
|
||||
virtual void render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc, const mat4 &matrix) = 0;
|
||||
virtual bool hasData(std::shared_ptr<StyleLayer> layer_desc) const = 0;
|
||||
virtual void render(Painter &painter, util::ptr<StyleLayer> layer_desc, const mat4 &matrix) = 0;
|
||||
virtual bool hasData(util::ptr<StyleLayer> layer_desc) const = 0;
|
||||
|
||||
|
||||
public:
|
||||
@@ -69,10 +68,10 @@ protected:
|
||||
Map ↦
|
||||
|
||||
public:
|
||||
const SourceInfo &source;
|
||||
util::ptr<SourceInfo> source;
|
||||
|
||||
protected:
|
||||
std::weak_ptr<platform::Request> req;
|
||||
std::unique_ptr<Request> req;
|
||||
std::string data;
|
||||
|
||||
// Contains the tile ID string for painting debug information.
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
#include <mbgl/map/vector_tile.hpp>
|
||||
#include <mbgl/style/filter_expression.hpp>
|
||||
#include <mbgl/text/glyph.hpp>
|
||||
#include <mbgl/util/ptr.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <iosfwd>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace mbgl {
|
||||
@@ -32,11 +32,11 @@ class Collision;
|
||||
class TileParser {
|
||||
public:
|
||||
TileParser(const std::string &data, VectorTileData &tile,
|
||||
const std::shared_ptr<const Style> &style,
|
||||
const std::shared_ptr<GlyphAtlas> &glyphAtlas,
|
||||
const std::shared_ptr<GlyphStore> &glyphStore,
|
||||
const std::shared_ptr<SpriteAtlas> &spriteAtlas,
|
||||
const std::shared_ptr<Sprite> &sprite);
|
||||
const util::ptr<const Style> &style,
|
||||
const util::ptr<GlyphAtlas> &glyphAtlas,
|
||||
const util::ptr<GlyphStore> &glyphStore,
|
||||
const util::ptr<SpriteAtlas> &spriteAtlas,
|
||||
const util::ptr<Sprite> &sprite);
|
||||
~TileParser();
|
||||
|
||||
public:
|
||||
@@ -44,11 +44,11 @@ public:
|
||||
|
||||
private:
|
||||
bool obsolete() const;
|
||||
void parseStyleLayers(std::shared_ptr<StyleLayerGroup> group);
|
||||
std::unique_ptr<Bucket> createBucket(std::shared_ptr<StyleBucket> bucket_desc);
|
||||
void parseStyleLayers(util::ptr<StyleLayerGroup> group);
|
||||
std::unique_ptr<Bucket> createBucket(util::ptr<StyleBucket> bucket_desc);
|
||||
|
||||
std::unique_ptr<Bucket> createFillBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketFill &fill);
|
||||
std::unique_ptr<Bucket> createRasterBucket(const std::shared_ptr<Texturepool> &texturepool, const StyleBucketRaster &raster);
|
||||
std::unique_ptr<Bucket> createRasterBucket(const util::ptr<Texturepool> &texturepool, const StyleBucketRaster &raster);
|
||||
std::unique_ptr<Bucket> createLineBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketLine &line);
|
||||
std::unique_ptr<Bucket> createSymbolBucket(const VectorTileLayer& layer, const FilterExpression &filter, const StyleBucketSymbol &symbol);
|
||||
|
||||
@@ -59,12 +59,12 @@ private:
|
||||
VectorTileData& tile;
|
||||
|
||||
// Cross-thread shared data.
|
||||
std::shared_ptr<const Style> style;
|
||||
std::shared_ptr<GlyphAtlas> glyphAtlas;
|
||||
std::shared_ptr<GlyphStore> glyphStore;
|
||||
std::shared_ptr<SpriteAtlas> spriteAtlas;
|
||||
std::shared_ptr<Sprite> sprite;
|
||||
std::shared_ptr<Texturepool> texturePool;
|
||||
util::ptr<const Style> style;
|
||||
util::ptr<GlyphAtlas> glyphAtlas;
|
||||
util::ptr<GlyphStore> glyphStore;
|
||||
util::ptr<SpriteAtlas> spriteAtlas;
|
||||
util::ptr<Sprite> sprite;
|
||||
util::ptr<Texturepool> texturePool;
|
||||
|
||||
std::unique_ptr<Collision> collision;
|
||||
};
|
||||
|
||||
@@ -98,10 +98,10 @@ private:
|
||||
// cache values for spherical mercator math
|
||||
double Bc, Cc;
|
||||
|
||||
std::forward_list<std::shared_ptr<util::transition>> transitions;
|
||||
std::shared_ptr<util::transition> scale_timeout;
|
||||
std::shared_ptr<util::transition> rotate_timeout;
|
||||
std::shared_ptr<util::transition> pan_timeout;
|
||||
std::forward_list<util::ptr<util::transition>> transitions;
|
||||
util::ptr<util::transition> scale_timeout;
|
||||
util::ptr<util::transition> rotate_timeout;
|
||||
util::ptr<util::transition> pan_timeout;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -26,14 +26,14 @@ class VectorTileData : public TileData {
|
||||
friend class TileParser;
|
||||
|
||||
public:
|
||||
VectorTileData(Tile::ID id, Map &map, const SourceInfo &source);
|
||||
VectorTileData(Tile::ID id, Map &map, const util::ptr<SourceInfo> &source);
|
||||
~VectorTileData();
|
||||
|
||||
virtual void beforeParse();
|
||||
virtual void parse();
|
||||
virtual void afterParse();
|
||||
virtual void render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc, const mat4 &matrix);
|
||||
virtual bool hasData(std::shared_ptr<StyleLayer> layer_desc) const;
|
||||
virtual void render(Painter &painter, util::ptr<StyleLayer> layer_desc, const mat4 &matrix);
|
||||
virtual bool hasData(util::ptr<StyleLayer> layer_desc) const;
|
||||
|
||||
protected:
|
||||
// Holds the actual geometries in this tile.
|
||||
|
||||
@@ -45,6 +45,8 @@ public:
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual void notify() = 0;
|
||||
|
||||
// Notifies a watcher of map x/y/scale/rotation changes.
|
||||
// Must only be called from the same thread that caused the change.
|
||||
// Must not be called from the render thread.
|
||||
|
||||
@@ -29,6 +29,7 @@ enum class Event : uint8_t {
|
||||
ParseStyle,
|
||||
ParseTile,
|
||||
Render,
|
||||
Database,
|
||||
HttpRequest,
|
||||
Sprite,
|
||||
};
|
||||
@@ -40,6 +41,7 @@ MBGL_DEFINE_ENUM_CLASS(EventClass, Event, {
|
||||
{ Event::ParseStyle, "ParseStyle" },
|
||||
{ Event::ParseTile, "ParseTile" },
|
||||
{ Event::Render, "Render" },
|
||||
{ Event::Database, "Database" },
|
||||
{ Event::HttpRequest, "HttpRequest" },
|
||||
{ Event::Sprite, "Sprite" },
|
||||
{ Event(-1), "Unknown" },
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include <mbgl/util/uv.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
namespace mbgl {
|
||||
@@ -12,30 +11,14 @@ namespace platform {
|
||||
|
||||
class Request;
|
||||
|
||||
struct Response {
|
||||
Response(std::function<void(Response *)> callback) : callback(callback) {}
|
||||
int16_t code = -1;
|
||||
std::string body;
|
||||
std::string error_message;
|
||||
std::function<void(Response *)> callback;
|
||||
};
|
||||
|
||||
// Makes an HTTP request of a URL, preferrably on a background thread, and calls a function with the
|
||||
// results in the original thread (which runs the libuv loop).
|
||||
// If the loop pointer is NULL, the callback function will be called on an arbitrary thread.
|
||||
// Returns a cancellable request.
|
||||
std::shared_ptr<Request> request_http(const std::string &url,
|
||||
std::function<void(Response *)> callback,
|
||||
std::shared_ptr<uv::loop> loop = nullptr);
|
||||
|
||||
// Uppercase a string, potentially using platform-specific routines.
|
||||
std::string uppercase(const std::string &string);
|
||||
|
||||
// Lowercase a string, potentially using platform-specific routines.
|
||||
std::string lowercase(const std::string &string);
|
||||
|
||||
// Cancels an HTTP request.
|
||||
void cancel_request_http(const std::shared_ptr<Request> &req);
|
||||
// Returns the path to the default cache database on this system.
|
||||
std::string defaultCacheDatabase();
|
||||
|
||||
// Shows an alpha image with the specified dimensions in a named window.
|
||||
void show_debug_image(std::string name, const char *data, size_t width, size_t height);
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
#ifndef MBGL_PLATFORM_REQUEST
|
||||
#define MBGL_PLATFORM_REQUEST
|
||||
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
#include <mbgl/util/uv.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace platform {
|
||||
|
||||
struct Response;
|
||||
|
||||
class Request : public std::enable_shared_from_this<Request>, private util::noncopyable {
|
||||
public:
|
||||
Request(const std::string &url,
|
||||
std::function<void(Response *)> callback,
|
||||
std::shared_ptr<uv::loop> loop);
|
||||
~Request();
|
||||
|
||||
void complete();
|
||||
|
||||
private:
|
||||
static void complete(uv_async_t *async, int status);
|
||||
|
||||
public:
|
||||
const std::string url;
|
||||
std::unique_ptr<Response> res;
|
||||
std::atomic<bool> cancelled;
|
||||
|
||||
public:
|
||||
uv_async_t *async = nullptr;
|
||||
std::shared_ptr<uv::loop> loop;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,11 +1,11 @@
|
||||
#ifndef MBGL_RENDERER_BUCKET
|
||||
#define MBGL_RENDERER_BUCKET
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <mbgl/map/tile.hpp>
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class Painter;
|
||||
@@ -13,7 +13,7 @@ class StyleLayer;
|
||||
|
||||
class Bucket : private util::noncopyable {
|
||||
public:
|
||||
virtual void render(Painter& painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix) = 0;
|
||||
virtual void render(Painter& painter, util::ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix) = 0;
|
||||
virtual bool hasData() const = 0;
|
||||
virtual ~Bucket() {}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include <mbgl/geometry/vao.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#ifndef BUFFER_OFFSET
|
||||
#define BUFFER_OFFSET(i) ((char *)nullptr + (i))
|
||||
@@ -20,7 +19,7 @@ class DebugBucket : public Bucket {
|
||||
public:
|
||||
DebugBucket(DebugFontBuffer& fontBuffer);
|
||||
|
||||
virtual void render(Painter& painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix);
|
||||
virtual void render(Painter& painter, util::ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix);
|
||||
virtual bool hasData() const;
|
||||
|
||||
void drawLines(PlainShader& shader);
|
||||
|
||||
@@ -44,7 +44,7 @@ public:
|
||||
const StyleBucketFill& properties);
|
||||
~FillBucket();
|
||||
|
||||
virtual void render(Painter& painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix);
|
||||
virtual void render(Painter& painter, util::ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix);
|
||||
virtual bool hasData() const;
|
||||
|
||||
void addGeometry(pbf& data);
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
#ifndef MBGL_RENDERER_LINEBUCKET
|
||||
#define MBGL_RENDERER_LINEBUCKET
|
||||
|
||||
#include "bucket.hpp"
|
||||
#include <mbgl/renderer/bucket.hpp>
|
||||
#include <mbgl/geometry/vao.hpp>
|
||||
#include <mbgl/geometry/elements_buffer.hpp>
|
||||
#include <mbgl/geometry/line_buffer.hpp>
|
||||
#include <mbgl/style/style_bucket.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace mbgl {
|
||||
@@ -30,7 +29,7 @@ public:
|
||||
PointElementsBuffer& pointElementsBuffer,
|
||||
const StyleBucketLine& properties);
|
||||
|
||||
virtual void render(Painter& painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix);
|
||||
virtual void render(Painter& painter, util::ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix);
|
||||
virtual bool hasData() const;
|
||||
|
||||
void addGeometry(pbf& data);
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <mbgl/shader/gaussian_shader.hpp>
|
||||
|
||||
#include <mbgl/map/transform_state.hpp>
|
||||
#include <mbgl/util/ptr.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
@@ -73,7 +74,7 @@ public:
|
||||
void changeMatrix();
|
||||
|
||||
// Renders a particular layer from a tile.
|
||||
void renderTileLayer(const Tile& tile, std::shared_ptr<StyleLayer> layer_desc, const mat4 &matrix);
|
||||
void renderTileLayer(const Tile& tile, util::ptr<StyleLayer> layer_desc, const mat4 &matrix);
|
||||
|
||||
// Renders debug information for a tile.
|
||||
void renderTileDebug(const Tile& tile);
|
||||
@@ -83,11 +84,11 @@ public:
|
||||
|
||||
void renderDebugText(DebugBucket& bucket, const mat4 &matrix);
|
||||
void renderDebugText(const std::vector<std::string> &strings);
|
||||
void renderFill(FillBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix);
|
||||
void renderLine(LineBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix);
|
||||
void renderSymbol(SymbolBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix);
|
||||
void renderRaster(RasterBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix);
|
||||
void renderBackground(std::shared_ptr<StyleLayer> layer_desc);
|
||||
void renderFill(FillBucket& bucket, util::ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix);
|
||||
void renderLine(LineBucket& bucket, util::ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix);
|
||||
void renderSymbol(SymbolBucket& bucket, util::ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix);
|
||||
void renderRaster(RasterBucket& bucket, util::ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix);
|
||||
void renderBackground(util::ptr<StyleLayer> layer_desc);
|
||||
|
||||
float saturationFactor(float saturation);
|
||||
float contrastFactor(float contrast);
|
||||
@@ -97,7 +98,7 @@ public:
|
||||
|
||||
void renderPrerenderedTexture(RasterBucket &bucket, const mat4 &matrix, const RasterProperties& properties);
|
||||
|
||||
void createPrerendered(RasterBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id);
|
||||
void createPrerendered(RasterBucket& bucket, util::ptr<StyleLayer> layer_desc, const Tile::ID& id);
|
||||
|
||||
void resize();
|
||||
|
||||
@@ -111,7 +112,7 @@ public:
|
||||
// Configures the painter strata that is used for early z-culling of fragments.
|
||||
void setStrata(float strata);
|
||||
|
||||
void drawClippingMasks(const std::set<std::shared_ptr<StyleSource>> &sources);
|
||||
void drawClippingMasks(const std::set<util::ptr<StyleSource>> &sources);
|
||||
void drawClippingMask(const mat4& matrix, const ClipID& clip);
|
||||
|
||||
void resetFramebuffer();
|
||||
|
||||
@@ -16,9 +16,9 @@ class VertexArrayObject;
|
||||
|
||||
class RasterBucket : public Bucket {
|
||||
public:
|
||||
RasterBucket(const std::shared_ptr<Texturepool> &texturepool, const StyleBucketRaster& properties);
|
||||
RasterBucket(const util::ptr<Texturepool> &texturepool, const StyleBucketRaster& properties);
|
||||
|
||||
virtual void render(Painter& painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix);
|
||||
virtual void render(Painter& painter, util::ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix);
|
||||
virtual bool hasData() const;
|
||||
|
||||
bool setImage(const std::string &data);
|
||||
|
||||
@@ -56,7 +56,7 @@ class SymbolBucket : public Bucket {
|
||||
public:
|
||||
SymbolBucket(const StyleBucketSymbol &properties, Collision &collision);
|
||||
|
||||
virtual void render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID &id, const mat4 &matrix);
|
||||
virtual void render(Painter &painter, util::ptr<StyleLayer> layer_desc, const Tile::ID &id, const mat4 &matrix);
|
||||
virtual bool hasData() const;
|
||||
virtual bool hasTextData() const;
|
||||
virtual bool hasIconData() const;
|
||||
|
||||
62
include/mbgl/storage/base_request.hpp
Normal file
62
include/mbgl/storage/base_request.hpp
Normal file
@@ -0,0 +1,62 @@
|
||||
#ifndef MBGL_STORAGE_BASE_REQUEST
|
||||
#define MBGL_STORAGE_BASE_REQUEST
|
||||
|
||||
#include <mbgl/storage/request_callback.hpp>
|
||||
#include <mbgl/util/ptr.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <forward_list>
|
||||
#include <functional>
|
||||
|
||||
|
||||
typedef struct uv_loop_s uv_loop_t;
|
||||
typedef struct uv_async_s uv_async_t;
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class Response;
|
||||
class Request;
|
||||
|
||||
class BaseRequest {
|
||||
private:
|
||||
// Make noncopyable and immovable
|
||||
BaseRequest(const BaseRequest &) = delete;
|
||||
BaseRequest(BaseRequest &&) = delete;
|
||||
BaseRequest& operator=(const BaseRequest &) = delete;
|
||||
BaseRequest& operator=(BaseRequest &&) = delete;
|
||||
|
||||
public:
|
||||
BaseRequest(const std::string &path);
|
||||
virtual ~BaseRequest();
|
||||
|
||||
Callback *add(Callback &&callback, const util::ptr<BaseRequest> &request);
|
||||
void remove(Callback *callback);
|
||||
|
||||
// Must be called by subclasses when a valid Response object is available. It will notify
|
||||
// all listeners.
|
||||
void notify();
|
||||
|
||||
// This function is called when the request ought to be stopped. Any subclass must make sure this
|
||||
// is also called in its destructor. Calling this function repeatedly must be safe.
|
||||
// This function must call notify().
|
||||
virtual void cancel() = 0;
|
||||
|
||||
// This function is called when the request should be reattempted immediately. This is typically
|
||||
// reaction to a network status change.
|
||||
virtual void retryImmediately();
|
||||
|
||||
public:
|
||||
const unsigned long thread_id;
|
||||
const std::string path;
|
||||
std::unique_ptr<Response> response;
|
||||
|
||||
protected:
|
||||
// This object may hold a shared_ptr to itself. It does this to prevent destruction of this object
|
||||
// while a request is in progress.
|
||||
util::ptr<BaseRequest> self;
|
||||
std::forward_list<std::unique_ptr<Callback>> callbacks;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
27
include/mbgl/storage/file_request.hpp
Normal file
27
include/mbgl/storage/file_request.hpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef MBGL_STORAGE_FILE_REQUEST
|
||||
#define MBGL_STORAGE_FILE_REQUEST
|
||||
|
||||
#include <mbgl/storage/base_request.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
typedef struct uv_loop_s uv_loop_t;
|
||||
|
||||
struct FileRequestBaton;
|
||||
|
||||
class FileRequest : public BaseRequest {
|
||||
public:
|
||||
FileRequest(const std::string &path, uv_loop_t *loop);
|
||||
~FileRequest();
|
||||
|
||||
void cancel();
|
||||
|
||||
private:
|
||||
FileRequestBaton *ptr = nullptr;
|
||||
|
||||
friend struct FileRequestBaton;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
35
include/mbgl/storage/file_request_baton.hpp
Normal file
35
include/mbgl/storage/file_request_baton.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef MBGL_STORAGE_FILE_REQUEST_BATON
|
||||
#define MBGL_STORAGE_FILE_REQUEST_BATON
|
||||
|
||||
#include <mbgl/storage/file_request.hpp>
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
struct FileRequestBaton {
|
||||
FileRequestBaton(FileRequest *request_, const std::string &path, uv_loop_t *loop);
|
||||
~FileRequestBaton();
|
||||
|
||||
void cancel();
|
||||
static void file_opened(uv_fs_t *req);
|
||||
static void file_stated(uv_fs_t *req);
|
||||
static void file_read(uv_fs_t *req);
|
||||
static void file_closed(uv_fs_t *req);
|
||||
static void notify_error(uv_fs_t *req);
|
||||
static void cleanup(uv_fs_t *req);
|
||||
|
||||
const unsigned long thread_id;
|
||||
FileRequest *request = nullptr;
|
||||
uv_fs_t req;
|
||||
uv_file fd = -1;
|
||||
bool canceled = false;
|
||||
std::string body;
|
||||
uv_buf_t buffer;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
55
include/mbgl/storage/file_source.hpp
Normal file
55
include/mbgl/storage/file_source.hpp
Normal file
@@ -0,0 +1,55 @@
|
||||
#ifndef MBGL_STORAGE_FILE_SOURCE
|
||||
#define MBGL_STORAGE_FILE_SOURCE
|
||||
|
||||
#include <mbgl/storage/resource_type.hpp>
|
||||
#include <mbgl/storage/request.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
|
||||
typedef struct uv_loop_s uv_loop_t;
|
||||
typedef struct uv_messenger_s uv_messenger_t;
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class BaseRequest;
|
||||
class SQLiteStore;
|
||||
|
||||
class FileSource {
|
||||
private:
|
||||
FileSource(const FileSource &) = delete;
|
||||
FileSource(FileSource &&) = delete;
|
||||
FileSource& operator=(const FileSource &) = delete;
|
||||
FileSource& operator=(FileSource &&) = delete;
|
||||
|
||||
public:
|
||||
FileSource(uv_loop_t *loop, const std::string &path);
|
||||
~FileSource();
|
||||
|
||||
public:
|
||||
// Stores and retrieves the base path/URL for relative requests
|
||||
void setBase(const std::string &value);
|
||||
const std::string &getBase() const;
|
||||
|
||||
std::unique_ptr<Request> request(ResourceType type, const std::string &url);
|
||||
|
||||
void prepare(std::function<void()> fn);
|
||||
|
||||
void retryAllPending();
|
||||
|
||||
private:
|
||||
const unsigned long thread_id;
|
||||
|
||||
// Stores a URL that is used as a base for loading resources with relative path.
|
||||
std::string base;
|
||||
|
||||
std::unordered_map<std::string, std::weak_ptr<BaseRequest>> pending;
|
||||
util::ptr<SQLiteStore> store;
|
||||
uv_loop_t *loop = nullptr;
|
||||
uv_messenger_t *queue = nullptr;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
57
include/mbgl/storage/http_request.hpp
Normal file
57
include/mbgl/storage/http_request.hpp
Normal file
@@ -0,0 +1,57 @@
|
||||
#ifndef MBGL_STORAGE_HTTP_REQUEST
|
||||
#define MBGL_STORAGE_HTTP_REQUEST
|
||||
|
||||
#include <mbgl/storage/resource_type.hpp>
|
||||
#include <mbgl/storage/base_request.hpp>
|
||||
#include <mbgl/storage/http_request_baton.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <cassert>
|
||||
|
||||
typedef struct uv_loop_s uv_loop_t;
|
||||
typedef struct uv_timer_s uv_timer_t;
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
struct CacheRequestBaton;
|
||||
struct HTTPRequestBaton;
|
||||
struct CacheEntry;
|
||||
class SQLiteStore;
|
||||
|
||||
class HTTPRequest : public BaseRequest {
|
||||
public:
|
||||
HTTPRequest(ResourceType type, const std::string &path, uv_loop_t *loop, util::ptr<SQLiteStore> store);
|
||||
~HTTPRequest();
|
||||
|
||||
void cancel();
|
||||
void retryImmediately();
|
||||
|
||||
private:
|
||||
void startCacheRequest();
|
||||
void handleCacheResponse(std::unique_ptr<Response> &&response);
|
||||
void startHTTPRequest(std::unique_ptr<Response> &&res);
|
||||
void handleHTTPResponse(HTTPResponseType responseType, std::unique_ptr<Response> &&response);
|
||||
|
||||
void retryHTTPRequest(std::unique_ptr<Response> &&res, uint64_t timeout);
|
||||
|
||||
void removeCacheBaton();
|
||||
void removeHTTPBaton();
|
||||
void removeBackoffTimer();
|
||||
|
||||
private:
|
||||
const unsigned long thread_id;
|
||||
uv_loop_t *const loop;
|
||||
CacheRequestBaton *cache_baton = nullptr;
|
||||
util::ptr<HTTPRequestBaton> http_baton;
|
||||
uv_timer_t *backoff_timer = nullptr;
|
||||
util::ptr<SQLiteStore> store;
|
||||
const ResourceType type;
|
||||
uint8_t attempts = 0;
|
||||
|
||||
friend struct HTTPRequestBaton;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
73
include/mbgl/storage/http_request_baton.hpp
Normal file
73
include/mbgl/storage/http_request_baton.hpp
Normal file
@@ -0,0 +1,73 @@
|
||||
#ifndef MBGL_STORAGE_HTTP_REQUEST_BATON
|
||||
#define MBGL_STORAGE_HTTP_REQUEST_BATON
|
||||
|
||||
#include <mbgl/storage/response.hpp>
|
||||
#include <mbgl/util/ptr.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
typedef struct uv_async_s uv_async_t;
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class HTTPRequest;
|
||||
|
||||
enum class HTTPResponseType : int8_t {
|
||||
// This error probably won't be resolved by retrying anytime soon. We are giving up.
|
||||
PermanentError = -5,
|
||||
|
||||
// This error might be resolved by waiting some time (e.g. server issues).
|
||||
// We are going to do an exponential back-off and will try again in a few seconds.
|
||||
TemporaryError = -4,
|
||||
|
||||
// This error was caused by a temporary error and it is likely that it will be resolved
|
||||
// immediately. We are going to try again right away. This is like the TemporaryError, except
|
||||
// that we will not perform exponential back-off.
|
||||
SingularError = -3,
|
||||
|
||||
// This error might be resolved once the network reachability status changes.
|
||||
// We are going to watch the network status for changes and will retry as soon as the operating
|
||||
// system notifies us of a network status change.
|
||||
ConnectionError = -2,
|
||||
|
||||
// The request was canceled programatically.
|
||||
Canceled = -1,
|
||||
|
||||
// The request is still in progress.
|
||||
Unknown = 0,
|
||||
|
||||
// The request returned data successfully. We retrieved and decoded the data successfully.
|
||||
Successful = 1,
|
||||
|
||||
// The request confirmed that the data wasn't changed. We already have the data.
|
||||
NotModified = 2,
|
||||
};
|
||||
|
||||
struct HTTPRequestBaton {
|
||||
HTTPRequestBaton(const std::string &path);
|
||||
~HTTPRequestBaton();
|
||||
|
||||
const unsigned long thread_id;
|
||||
const std::string path;
|
||||
|
||||
HTTPRequest *request = nullptr;
|
||||
uv_async_t *async = nullptr;
|
||||
|
||||
HTTPResponseType type = HTTPResponseType::Unknown;
|
||||
std::unique_ptr<Response> response;
|
||||
|
||||
// Implementation specific use.
|
||||
void *ptr = nullptr;
|
||||
|
||||
// IMPLEMENT THESE 3 PLATFORM SPECIFIC FUNCTIONS:
|
||||
|
||||
// Begin the HTTP request. Platform-specific implementation.
|
||||
static void start(const util::ptr<HTTPRequestBaton> &ptr);
|
||||
|
||||
// This will be called to stop/cancel the HTTP request (if possible). Platform-specific implementation.
|
||||
static void stop(const util::ptr<HTTPRequestBaton> &ptr);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
39
include/mbgl/storage/request.hpp
Normal file
39
include/mbgl/storage/request.hpp
Normal file
@@ -0,0 +1,39 @@
|
||||
#ifndef MBGL_STORAGE_REQUEST
|
||||
#define MBGL_STORAGE_REQUEST
|
||||
|
||||
#include <mbgl/storage/request_callback.hpp>
|
||||
#include <mbgl/storage/response.hpp>
|
||||
#include <mbgl/util/ptr.hpp>
|
||||
|
||||
#include <forward_list>
|
||||
|
||||
typedef struct uv_loop_s uv_loop_t;
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class BaseRequest;
|
||||
|
||||
class Request {
|
||||
private:
|
||||
Request(const Request &) = delete;
|
||||
Request(Request &&) = delete;
|
||||
Request& operator=(const Request &) = delete;
|
||||
Request& operator=(Request &&) = delete;
|
||||
|
||||
public:
|
||||
Request(const util::ptr<BaseRequest> &base);
|
||||
~Request();
|
||||
|
||||
void onload(CompletedCallback cb);
|
||||
void oncancel(AbortedCallback cb);
|
||||
void cancel();
|
||||
|
||||
private:
|
||||
const unsigned long thread_id;
|
||||
util::ptr<BaseRequest> base;
|
||||
std::forward_list<Callback *> callbacks;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
22
include/mbgl/storage/request_callback.hpp
Normal file
22
include/mbgl/storage/request_callback.hpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#ifndef MBGL_STORAGE_REQUEST_CALLBACK
|
||||
#define MBGL_STORAGE_REQUEST_CALLBACK
|
||||
|
||||
#include <mbgl/util/variant.hpp>
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class Response;
|
||||
|
||||
using CompletedCallback = std::function<void(const Response &)>;
|
||||
using AbortedCallback = std::function<void()>;
|
||||
|
||||
using Callback = mapbox::util::variant<
|
||||
CompletedCallback,
|
||||
AbortedCallback
|
||||
>;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
18
include/mbgl/storage/resource_type.hpp
Normal file
18
include/mbgl/storage/resource_type.hpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef MBGL_STORAGE_RESOURCE_TYPE
|
||||
#define MBGL_STORAGE_RESOURCE_TYPE
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
enum class ResourceType : uint8_t {
|
||||
Unknown = 0,
|
||||
Tile = 1,
|
||||
Glyphs = 2,
|
||||
Image = 3,
|
||||
JSON = 4
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
26
include/mbgl/storage/response.hpp
Normal file
26
include/mbgl/storage/response.hpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef MBGL_STORAGE_RESPONSE
|
||||
#define MBGL_STORAGE_RESPONSE
|
||||
|
||||
#include <string>
|
||||
#include <ctime>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
|
||||
|
||||
class Response {
|
||||
public:
|
||||
long code = 0;
|
||||
int64_t modified = 0;
|
||||
int64_t expires = 0;
|
||||
std::string etag;
|
||||
std::string data;
|
||||
|
||||
std::string message;
|
||||
|
||||
static int64_t parseCacheControl(const char *value);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
47
include/mbgl/storage/sqlite_store.hpp
Normal file
47
include/mbgl/storage/sqlite_store.hpp
Normal file
@@ -0,0 +1,47 @@
|
||||
#ifndef MBGL_STORAGE_SQLITE_STORE
|
||||
#define MBGL_STORAGE_SQLITE_STORE
|
||||
|
||||
#include <mbgl/storage/file_source.hpp>
|
||||
#include <mbgl/storage/response.hpp>
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
typedef struct uv_worker_s uv_worker_t;
|
||||
|
||||
namespace mapbox {
|
||||
namespace sqlite {
|
||||
class Database;
|
||||
}
|
||||
}
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class SQLiteStore {
|
||||
public:
|
||||
SQLiteStore(uv_loop_t *loop, const std::string &path);
|
||||
~SQLiteStore();
|
||||
|
||||
typedef void (*GetCallback)(std::unique_ptr<Response> &&entry, void *ptr);
|
||||
|
||||
void get(const std::string &path, GetCallback cb, void *ptr);
|
||||
void put(const std::string &path, ResourceType type, const Response &entry);
|
||||
void updateExpiration(const std::string &path, int64_t expires);
|
||||
|
||||
private:
|
||||
void createSchema();
|
||||
void closeDatabase();
|
||||
static void runGet(uv_work_t *req);
|
||||
static void runPut(uv_work_t *req);
|
||||
static void deliverResult(uv_work_t *req, int status);
|
||||
|
||||
private:
|
||||
const unsigned long thread_id;
|
||||
util::ptr<mapbox::sqlite::Database> db;
|
||||
uv_worker_t *worker = nullptr;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <mbgl/util/time.hpp>
|
||||
#include <mbgl/util/uv.hpp>
|
||||
#include <mbgl/util/ptr.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
@@ -13,7 +14,6 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <memory>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
@@ -49,7 +49,7 @@ public:
|
||||
const std::string &getSpriteURL() const;
|
||||
|
||||
public:
|
||||
std::shared_ptr<StyleLayerGroup> layers;
|
||||
util::ptr<StyleLayerGroup> layers;
|
||||
std::vector<std::string> appliedClasses;
|
||||
std::string glyph_url;
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
#include <mbgl/util/vec.hpp>
|
||||
#include <mbgl/util/variant.hpp>
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
#include <mbgl/util/ptr.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <forward_list>
|
||||
|
||||
namespace mbgl {
|
||||
@@ -93,12 +93,12 @@ typedef mapbox::util::variant<StyleBucketFill, StyleBucketLine, StyleBucketSymbo
|
||||
|
||||
class StyleBucket {
|
||||
public:
|
||||
typedef std::shared_ptr<StyleBucket> Ptr;
|
||||
typedef util::ptr<StyleBucket> Ptr;
|
||||
|
||||
StyleBucket(StyleLayerType type);
|
||||
|
||||
std::string name;
|
||||
std::shared_ptr<StyleSource> style_source;
|
||||
util::ptr<StyleSource> style_source;
|
||||
std::string source_layer;
|
||||
FilterExpression filter;
|
||||
StyleBucketRender render = std::false_type();
|
||||
|
||||
@@ -6,8 +6,9 @@
|
||||
#include <mbgl/style/style_properties.hpp>
|
||||
#include <mbgl/style/applied_class_properties.hpp>
|
||||
|
||||
#include <mbgl/util/ptr.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <set>
|
||||
@@ -64,7 +65,7 @@ public:
|
||||
|
||||
// Bucket information, telling the renderer how to generate the geometries
|
||||
// for this layer (feature property filters, tessellation instructions, ...).
|
||||
std::shared_ptr<StyleBucket> bucket;
|
||||
util::ptr<StyleBucket> bucket;
|
||||
|
||||
// Contains all style classes that can be applied to this layer.
|
||||
const std::map<ClassID, ClassProperties> styles;
|
||||
@@ -80,7 +81,7 @@ public:
|
||||
StyleProperties properties;
|
||||
|
||||
// Child layer array (if this layer has child layers).
|
||||
std::shared_ptr<StyleLayerGroup> layers;
|
||||
util::ptr<StyleLayerGroup> layers;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ public:
|
||||
|
||||
bool hasTransitions() const;
|
||||
public:
|
||||
std::vector<std::shared_ptr<StyleLayer>> layers;
|
||||
std::vector<util::ptr<StyleLayer>> layers;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ public:
|
||||
|
||||
void parse(JSVal document);
|
||||
|
||||
std::shared_ptr<StyleLayerGroup> getLayers() {
|
||||
util::ptr<StyleLayerGroup> getLayers() {
|
||||
return root;
|
||||
}
|
||||
|
||||
@@ -46,14 +46,14 @@ private:
|
||||
void parseSources(JSVal value);
|
||||
|
||||
std::unique_ptr<StyleLayerGroup> createLayers(JSVal value);
|
||||
std::shared_ptr<StyleLayer> createLayer(JSVal value);
|
||||
util::ptr<StyleLayer> createLayer(JSVal value);
|
||||
void parseLayers();
|
||||
void parseLayer(std::pair<JSVal, std::shared_ptr<StyleLayer>> &pair);
|
||||
void parseLayer(std::pair<JSVal, util::ptr<StyleLayer>> &pair);
|
||||
void parseStyles(JSVal value, std::map<ClassID, ClassProperties> &styles);
|
||||
void parseStyle(JSVal, ClassProperties &properties);
|
||||
void parseReference(JSVal value, std::shared_ptr<StyleLayer> &layer);
|
||||
void parseBucket(JSVal value, std::shared_ptr<StyleLayer> &layer);
|
||||
void parseRender(JSVal value, std::shared_ptr<StyleLayer> &layer);
|
||||
void parseReference(JSVal value, util::ptr<StyleLayer> &layer);
|
||||
void parseBucket(JSVal value, util::ptr<StyleLayer> &layer);
|
||||
void parseRender(JSVal value, util::ptr<StyleLayer> &layer);
|
||||
void parseSprite(JSVal value);
|
||||
void parseGlyphURL(JSVal value);
|
||||
|
||||
@@ -94,13 +94,13 @@ private:
|
||||
private:
|
||||
std::unordered_map<std::string, const rapidjson::Value *> constants;
|
||||
|
||||
std::unordered_map<std::string, const std::shared_ptr<StyleSource>> sources;
|
||||
std::unordered_map<std::string, const util::ptr<StyleSource>> sources;
|
||||
|
||||
// This stores the root layer.
|
||||
std::shared_ptr<StyleLayerGroup> root;
|
||||
util::ptr<StyleLayerGroup> root;
|
||||
|
||||
// This maps ids to Layer objects, with all items being at the root level.
|
||||
std::unordered_map<std::string, std::pair<JSVal, std::shared_ptr<StyleLayer>>> layers;
|
||||
std::unordered_map<std::string, std::pair<JSVal, util::ptr<StyleLayer>>> layers;
|
||||
|
||||
// Store a stack of layers we're parsing right now. This is to prevent reference cycles.
|
||||
std::forward_list<StyleLayer *> stack;
|
||||
|
||||
@@ -2,18 +2,18 @@
|
||||
#define MBGL_STYLE_STYLE_SOURCE
|
||||
|
||||
#include <mbgl/style/types.hpp>
|
||||
#include <mbgl/util/ptr.hpp>
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
#include <rapidjson/document.h>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class Source;
|
||||
|
||||
class SourceInfo {
|
||||
class SourceInfo : private util::noncopyable {
|
||||
public:
|
||||
SourceType type = SourceType::Vector;
|
||||
std::string url;
|
||||
@@ -31,12 +31,12 @@ public:
|
||||
|
||||
class StyleSource : public std::enable_shared_from_this<StyleSource> {
|
||||
public:
|
||||
SourceInfo info;
|
||||
util::ptr<SourceInfo> info;
|
||||
|
||||
bool enabled = false;
|
||||
std::shared_ptr<Source> source;
|
||||
util::ptr<Source> source;
|
||||
|
||||
StyleSource(const SourceInfo &info)
|
||||
StyleSource(const util::ptr<SourceInfo> &info)
|
||||
: info(info)
|
||||
{}
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <mbgl/text/glyph.hpp>
|
||||
#include <mbgl/util/pbf.hpp>
|
||||
#include <mbgl/util/vec.hpp>
|
||||
#include <mbgl/util/ptr.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
@@ -47,8 +48,15 @@ private:
|
||||
|
||||
class GlyphPBF {
|
||||
public:
|
||||
GlyphPBF(const std::string &glyphURL, const std::string &fontStack, GlyphRange glyphRange, const std::shared_ptr<FileSource> &fileSource);
|
||||
GlyphPBF(const std::string &glyphURL, const std::string &fontStack, GlyphRange glyphRange, const util::ptr<FileSource> &fileSource);
|
||||
|
||||
private:
|
||||
GlyphPBF(const GlyphPBF &) = delete;
|
||||
GlyphPBF(GlyphPBF &&) = delete;
|
||||
GlyphPBF &operator=(const GlyphPBF &) = delete;
|
||||
GlyphPBF &operator=(GlyphPBF &&) = delete;
|
||||
|
||||
public:
|
||||
void parse(FontStack &stack);
|
||||
|
||||
std::shared_future<GlyphPBF &> getFuture();
|
||||
@@ -63,7 +71,7 @@ private:
|
||||
// Manages Glyphrange PBF loading.
|
||||
class GlyphStore {
|
||||
public:
|
||||
GlyphStore(const std::shared_ptr<FileSource> &fileSource);
|
||||
GlyphStore(const util::ptr<FileSource> &fileSource);
|
||||
|
||||
// Block until all specified GlyphRanges of the specified font stack are loaded.
|
||||
void waitForGlyphRanges(const std::string &fontStack, const std::set<GlyphRange> &glyphRanges);
|
||||
@@ -82,7 +90,7 @@ public:
|
||||
std::string glyphURL;
|
||||
|
||||
private:
|
||||
const std::shared_ptr<FileSource> fileSource;
|
||||
const util::ptr<FileSource> fileSource;
|
||||
std::unordered_map<std::string, std::map<GlyphRange, std::unique_ptr<GlyphPBF>>> ranges;
|
||||
std::unordered_map<std::string, std::unique_ptr<FontStack>> stacks;
|
||||
std::mutex mtx;
|
||||
|
||||
15
include/mbgl/util/compression.hpp
Normal file
15
include/mbgl/util/compression.hpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef MBGL_UTIL_COMPRESSION
|
||||
#define MBGL_UTIL_COMPRESSION
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace mbgl {
|
||||
namespace util {
|
||||
|
||||
std::string compress(const std::string &raw);
|
||||
std::string decompress(const std::string &raw);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,43 +0,0 @@
|
||||
#ifndef MBGL_UTIL_FILESOURCE
|
||||
#define MBGL_UTIL_FILESOURCE
|
||||
|
||||
#include <mbgl/util/uv.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
namespace platform {
|
||||
struct Response;
|
||||
}
|
||||
|
||||
enum class ResourceType : uint8_t {
|
||||
Unknown,
|
||||
Tile,
|
||||
Glyphs,
|
||||
Image,
|
||||
JSON
|
||||
};
|
||||
|
||||
class FileSource {
|
||||
public:
|
||||
FileSource();
|
||||
|
||||
void setBase(const std::string &value);
|
||||
const std::string &getBase() const;
|
||||
|
||||
void load(ResourceType type, const std::string &url, std::function<void(platform::Response *)> callback, const std::shared_ptr<uv::loop> loop = nullptr);
|
||||
|
||||
private:
|
||||
// Stores a URL that is used as a base for loading resources with relative path.
|
||||
std::string base;
|
||||
|
||||
// Stores the absolute path to the cache directory.
|
||||
const std::string cache;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef MBGL_UTIL_INTERPOLATE
|
||||
#define MBGL_UTIL_INTERPOLATE
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace mbgl {
|
||||
namespace util {
|
||||
|
||||
|
||||
38
include/mbgl/util/parsedate.h
Normal file
38
include/mbgl/util/parsedate.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef HEADER_PARSEDATE_H
|
||||
#define HEADER_PARSEDATE_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at http://curl.haxx.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
|
||||
time_t parse_date(const char *p);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_PARSEDATE_H */
|
||||
29
include/mbgl/util/ptr.hpp
Normal file
29
include/mbgl/util/ptr.hpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#ifndef MBGL_UTIL_PTR
|
||||
#define MBGL_UTIL_PTR
|
||||
|
||||
#include <memory>
|
||||
#include <cassert>
|
||||
|
||||
namespace mbgl {
|
||||
namespace util {
|
||||
|
||||
template <typename T>
|
||||
class ptr : public ::std::shared_ptr<T> {
|
||||
public:
|
||||
template <typename... Args>
|
||||
inline ptr(Args &&... args)
|
||||
: ::std::shared_ptr<T>(::std::forward<Args>(args)...) {}
|
||||
|
||||
inline auto operator->() const -> decltype(this->::std::shared_ptr<T>::operator->()) {
|
||||
assert(*this);
|
||||
return ::std::shared_ptr<T>::operator->();
|
||||
}
|
||||
inline auto operator*() const -> decltype(this->::std::shared_ptr<T>::operator*()) {
|
||||
assert(*this);
|
||||
return ::std::shared_ptr<T>::operator*();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
92
include/mbgl/util/queue.h
Normal file
92
include/mbgl/util/queue.h
Normal file
@@ -0,0 +1,92 @@
|
||||
/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QUEUE_H_
|
||||
#define QUEUE_H_
|
||||
|
||||
typedef void *QUEUE[2];
|
||||
|
||||
/* Private macros. */
|
||||
#define QUEUE_NEXT(q) (*(QUEUE **) &((*(q))[0]))
|
||||
#define QUEUE_PREV(q) (*(QUEUE **) &((*(q))[1]))
|
||||
#define QUEUE_PREV_NEXT(q) (QUEUE_NEXT(QUEUE_PREV(q)))
|
||||
#define QUEUE_NEXT_PREV(q) (QUEUE_PREV(QUEUE_NEXT(q)))
|
||||
|
||||
/* Public macros. */
|
||||
#define QUEUE_DATA(ptr, type, field) \
|
||||
((type *) ((char *) (ptr) - ((char *) &((type *) 0)->field)))
|
||||
|
||||
#define QUEUE_FOREACH(q, h) \
|
||||
for ((q) = QUEUE_NEXT(h); (q) != (h); (q) = QUEUE_NEXT(q))
|
||||
|
||||
#define QUEUE_EMPTY(q) \
|
||||
((const QUEUE *) (q) == (const QUEUE *) QUEUE_NEXT(q))
|
||||
|
||||
#define QUEUE_HEAD(q) \
|
||||
(QUEUE_NEXT(q))
|
||||
|
||||
#define QUEUE_INIT(q) \
|
||||
do { \
|
||||
QUEUE_NEXT(q) = (q); \
|
||||
QUEUE_PREV(q) = (q); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define QUEUE_ADD(h, n) \
|
||||
do { \
|
||||
QUEUE_PREV_NEXT(h) = QUEUE_NEXT(n); \
|
||||
QUEUE_NEXT_PREV(n) = QUEUE_PREV(h); \
|
||||
QUEUE_PREV(h) = QUEUE_PREV(n); \
|
||||
QUEUE_PREV_NEXT(h) = (h); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define QUEUE_SPLIT(h, q, n) \
|
||||
do { \
|
||||
QUEUE_PREV(n) = QUEUE_PREV(h); \
|
||||
QUEUE_PREV_NEXT(n) = (n); \
|
||||
QUEUE_NEXT(n) = (q); \
|
||||
QUEUE_PREV(h) = QUEUE_PREV(q); \
|
||||
QUEUE_PREV_NEXT(h) = (h); \
|
||||
QUEUE_PREV(q) = (n); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define QUEUE_INSERT_HEAD(h, q) \
|
||||
do { \
|
||||
QUEUE_NEXT(q) = QUEUE_NEXT(h); \
|
||||
QUEUE_PREV(q) = (h); \
|
||||
QUEUE_NEXT_PREV(q) = (q); \
|
||||
QUEUE_NEXT(h) = (q); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define QUEUE_INSERT_TAIL(h, q) \
|
||||
do { \
|
||||
QUEUE_NEXT(q) = (h); \
|
||||
QUEUE_PREV(q) = QUEUE_PREV(h); \
|
||||
QUEUE_PREV_NEXT(q) = (q); \
|
||||
QUEUE_PREV(h) = (q); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define QUEUE_REMOVE(q) \
|
||||
do { \
|
||||
QUEUE_PREV_NEXT(q) = QUEUE_NEXT(q); \
|
||||
QUEUE_NEXT_PREV(q) = QUEUE_PREV(q); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#endif /* QUEUE_H_ */
|
||||
@@ -4,11 +4,11 @@
|
||||
#include <mbgl/util/transition.hpp>
|
||||
#include <mbgl/util/texturepool.hpp>
|
||||
#include <mbgl/util/image.hpp>
|
||||
#include <mbgl/util/ptr.hpp>
|
||||
#include <mbgl/renderer/prerendered_texture.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
|
||||
typedef struct uv_loop_s uv_loop_t;
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace mbgl {
|
||||
class Raster : public std::enable_shared_from_this<Raster> {
|
||||
|
||||
public:
|
||||
Raster(const std::shared_ptr<Texturepool> &texturepool);
|
||||
Raster(const util::ptr<Texturepool> &texturepool);
|
||||
~Raster();
|
||||
|
||||
// load image data
|
||||
@@ -57,7 +57,7 @@ private:
|
||||
bool loaded = false;
|
||||
|
||||
// shared texture pool
|
||||
std::shared_ptr<Texturepool> texturepool;
|
||||
util::ptr<Texturepool> texturepool;
|
||||
|
||||
// min/mag filter
|
||||
uint32_t filter = 0;
|
||||
@@ -66,7 +66,7 @@ private:
|
||||
std::unique_ptr<util::Image> img;
|
||||
|
||||
// fade in transition
|
||||
std::shared_ptr<util::transition> fade_transition = nullptr;
|
||||
util::ptr<util::transition> fade_transition = nullptr;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
74
include/mbgl/util/sqlite3.hpp
Normal file
74
include/mbgl/util/sqlite3.hpp
Normal file
@@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
typedef struct sqlite3 sqlite3;
|
||||
typedef struct sqlite3_stmt sqlite3_stmt;
|
||||
|
||||
namespace mapbox {
|
||||
namespace sqlite {
|
||||
|
||||
enum OpenFlag : int {
|
||||
ReadOnly = 0x00000001,
|
||||
ReadWrite = 0x00000002,
|
||||
Create = 0x00000004,
|
||||
NoMutex = 0x00008000,
|
||||
FullMutex = 0x00010000,
|
||||
SharedCache = 0x00020000,
|
||||
PrivateCache = 0x00040000,
|
||||
};
|
||||
|
||||
struct Exception : std::runtime_error {
|
||||
inline Exception(int err, const char *msg) : std::runtime_error(msg), code(err) {}
|
||||
const int code = 0;
|
||||
};
|
||||
|
||||
class Statement;
|
||||
|
||||
class Database {
|
||||
private:
|
||||
Database(const Database &) = delete;
|
||||
Database &operator=(const Database &) = delete;
|
||||
|
||||
public:
|
||||
Database(const std::string &filename, int flags = 0);
|
||||
Database(Database &&);
|
||||
~Database();
|
||||
Database &operator=(Database &&);
|
||||
|
||||
operator bool() const;
|
||||
|
||||
void exec(const std::string &sql);
|
||||
Statement prepare(const char *query);
|
||||
|
||||
private:
|
||||
sqlite3 *db = nullptr;
|
||||
};
|
||||
|
||||
class Statement {
|
||||
private:
|
||||
Statement(const Statement &) = delete;
|
||||
Statement &operator=(const Statement &) = delete;
|
||||
|
||||
public:
|
||||
Statement(sqlite3 *db, const char *sql);
|
||||
Statement(Statement &&);
|
||||
~Statement();
|
||||
Statement &operator=(Statement &&);
|
||||
|
||||
operator bool() const;
|
||||
|
||||
template <typename T> void bind(int offset, T value);
|
||||
void bind(int offset, const std::string &value, bool retain = true);
|
||||
template <typename T> T get(int offset);
|
||||
|
||||
bool run();
|
||||
void reset();
|
||||
|
||||
private:
|
||||
sqlite3_stmt *stmt = nullptr;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
29
include/mbgl/util/uv-channel.h
Normal file
29
include/mbgl/util/uv-channel.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#ifndef MBGL_UTIL_UV_CHANNEL
|
||||
#define MBGL_UTIL_UV_CHANNEL
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
// Taken from http://navaneeth.github.io/blog/2013/08/02/channels-in-libuv/
|
||||
|
||||
typedef struct uv_chan_s uv_chan_t;
|
||||
|
||||
struct uv_chan_s {
|
||||
uv_mutex_t mutex;
|
||||
uv_cond_t cond;
|
||||
void *q[2];
|
||||
};
|
||||
|
||||
int uv_chan_init(uv_chan_t *chan);
|
||||
void uv_chan_send(uv_chan_t *chan, void *data);
|
||||
void *uv_chan_receive(uv_chan_t *chan);
|
||||
void uv_chan_destroy(uv_chan_t *chan);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
32
include/mbgl/util/uv-messenger.h
Normal file
32
include/mbgl/util/uv-messenger.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef MBGL_UTIL_UV_MESSENGER
|
||||
#define MBGL_UTIL_UV_MESSENGER
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
typedef struct uv_messenger_s uv_messenger_t;
|
||||
typedef void (*uv_messenger_cb)(void *arg);
|
||||
typedef void (*uv_messenger_stop_cb)(uv_messenger_t *msgr);
|
||||
|
||||
struct uv_messenger_s {
|
||||
uv_mutex_t mutex;
|
||||
uv_async_t async;
|
||||
uv_messenger_cb callback;
|
||||
void *data;
|
||||
void *queue[2];
|
||||
};
|
||||
|
||||
int uv_messenger_init(uv_loop_t *loop, uv_messenger_t *msgr, uv_messenger_cb callback);
|
||||
void uv_messenger_send(uv_messenger_t *msgr, void *arg);
|
||||
void uv_messenger_stop(uv_messenger_t *msgr);
|
||||
void uv_messenger_ref(uv_messenger_t *msgr);
|
||||
void uv_messenger_unref(uv_messenger_t *msgr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
42
include/mbgl/util/uv-worker.h
Normal file
42
include/mbgl/util/uv-worker.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#ifndef MBGL_UTIL_UV_WORKER
|
||||
#define MBGL_UTIL_UV_WORKER
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct uv_messenger_s uv_messenger_t;
|
||||
|
||||
#include <mbgl/util/uv-channel.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct uv_worker_s uv_worker_t;
|
||||
|
||||
typedef void (*uv_worker_cb)(void *data);
|
||||
typedef void (*uv_worker_after_cb)(void *data);
|
||||
typedef void (*uv_worker_close_cb)(uv_worker_t *worker);
|
||||
|
||||
struct uv_worker_s {
|
||||
#ifndef NDEBUG
|
||||
unsigned long thread_id;
|
||||
#endif
|
||||
uv_loop_t *loop;
|
||||
uv_messenger_t *msgr;
|
||||
uv_chan_t chan;
|
||||
const char *name;
|
||||
int count;
|
||||
uv_worker_close_cb close_cb;
|
||||
unsigned int active_items;
|
||||
};
|
||||
|
||||
int uv_worker_init(uv_worker_t *worker, uv_loop_t *loop, int count, const char *name);
|
||||
void uv_worker_send(uv_worker_t *worker, void *data, uv_worker_cb work_cb,
|
||||
uv_worker_after_cb after_work_cb);
|
||||
void uv_worker_close(uv_worker_t *worker, uv_worker_close_cb close_cb);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <string>
|
||||
|
||||
typedef struct uv_async_s uv_async_t;
|
||||
typedef struct uv_timer_s uv_timer_t;
|
||||
typedef struct uv_handle_s uv_handle_t;
|
||||
typedef struct uv_loop_s uv_loop_t;
|
||||
|
||||
@@ -11,9 +12,15 @@ namespace uv {
|
||||
|
||||
std::string cwd();
|
||||
|
||||
struct deleter {
|
||||
void operator()(uv_async_t *async);
|
||||
void operator()(uv_timer_t *timer);
|
||||
};
|
||||
|
||||
class thread;
|
||||
class rwlock;
|
||||
class loop;
|
||||
class worker;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +1,13 @@
|
||||
#ifndef MBGL_UTIL_UV_DETAIL
|
||||
#define MBGL_UTIL_UV_DETAIL
|
||||
|
||||
#include <mbgl/util/ptr.hpp>
|
||||
#include <mbgl/util/uv-worker.h>
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include <functional>
|
||||
#include <cassert>
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunused-parameter"
|
||||
#endif
|
||||
|
||||
#include <boost/lockfree/queue.hpp>
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
@@ -112,6 +104,24 @@ private:
|
||||
uv_once_t o = UV_ONCE_INIT;
|
||||
};
|
||||
|
||||
class worker {
|
||||
public:
|
||||
inline worker(uv_loop_t *loop, unsigned int count, const char *name = nullptr) : w(new uv_worker_t) {
|
||||
uv_worker_init(w, loop, count, name);
|
||||
}
|
||||
inline ~worker() {
|
||||
uv_worker_close(w, [](uv_worker_t *worker) {
|
||||
delete worker;
|
||||
});
|
||||
}
|
||||
inline void add(void *data, uv_worker_cb work_cb, uv_worker_after_cb after_work_cb) {
|
||||
uv_worker_send(w, data, work_cb, after_work_cb);
|
||||
}
|
||||
|
||||
private:
|
||||
uv_worker_t *w;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class work {
|
||||
public:
|
||||
@@ -119,30 +129,26 @@ public:
|
||||
typedef void (*after_work_callback)(T &object);
|
||||
|
||||
template<typename... Args>
|
||||
work(const std::shared_ptr<loop> &loop, work_callback work_cb, after_work_callback after_work_cb, Args&&... args)
|
||||
: loop(loop),
|
||||
data(std::forward<Args>(args)...),
|
||||
work(worker &worker, work_callback work_cb, after_work_callback after_work_cb, Args&&... args)
|
||||
: data(std::forward<Args>(args)...),
|
||||
work_cb(work_cb),
|
||||
after_work_cb(after_work_cb) {
|
||||
req.data = this;
|
||||
uv_queue_work(**loop, &req, do_work, after_work);
|
||||
worker.add(this, do_work, after_work);
|
||||
}
|
||||
|
||||
private:
|
||||
static void do_work(uv_work_t *req) {
|
||||
work<T> *w = static_cast<work<T> *>(req->data);
|
||||
static void do_work(void *data) {
|
||||
work<T> *w = reinterpret_cast<work<T> *>(data);
|
||||
w->work_cb(w->data);
|
||||
}
|
||||
|
||||
static void after_work(uv_work_t *req, int) {
|
||||
work<T> *w = static_cast<work<T> *>(req->data);
|
||||
static void after_work(void *data) {
|
||||
work<T> *w = reinterpret_cast<work<T> *>(data);
|
||||
w->after_work_cb(w->data);
|
||||
delete w;
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<uv::loop> loop;
|
||||
uv_work_t req;
|
||||
T data;
|
||||
work_callback work_cb;
|
||||
after_work_callback after_work_cb;
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
'../common/platform_default.cpp',
|
||||
'../common/glfw_view.hpp',
|
||||
'../common/glfw_view.cpp',
|
||||
'../common/curl_request.cpp',
|
||||
'../common/http_request_baton_curl.cpp',
|
||||
'../common/linux.cpp',
|
||||
'../common/stderr_log.hpp',
|
||||
'../common/stderr_log.cpp',
|
||||
],
|
||||
@@ -32,7 +33,6 @@
|
||||
],
|
||||
'OTHER_LDFLAGS': [
|
||||
'<@(glfw3_libraries)',
|
||||
'<@(curl_libraries)',
|
||||
],
|
||||
}
|
||||
},
|
||||
@@ -46,7 +46,6 @@
|
||||
'link_settings': {
|
||||
'libraries': [
|
||||
'<@(glfw3_libraries)',
|
||||
'<@(curl_libraries)',
|
||||
'-lboost_regex'
|
||||
],
|
||||
},
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
#include "../common/settings_nsuserdefaults.hpp"
|
||||
#include "../common/glfw_view.hpp"
|
||||
#include "../common/nslog_log.hpp"
|
||||
#include "../common/Reachability.h"
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
@interface URLHandler : NSObject
|
||||
@property (nonatomic) mbgl::Map *map;
|
||||
|
||||
@@ -68,16 +71,25 @@
|
||||
@end
|
||||
|
||||
int main() {
|
||||
fprintf(stderr, "main thread: 0x%lx\n", uv_thread_self());
|
||||
mbgl::Log::Set<mbgl::NSLogBackend>();
|
||||
|
||||
GLFWView view;
|
||||
mbgl::Map map(view);
|
||||
mbgl::Map *map_ptr = ↦
|
||||
|
||||
URLHandler *handler = [[URLHandler alloc] init];
|
||||
[handler setMap:&map];
|
||||
NSAppleEventManager *appleEventManager = [NSAppleEventManager sharedAppleEventManager];
|
||||
[appleEventManager setEventHandler:handler andSelector:@selector(handleGetURLEvent:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL];
|
||||
|
||||
// Notify map object when network reachability status changes.
|
||||
Reachability* reachability = [Reachability reachabilityForInternetConnection];
|
||||
reachability.reachableBlock = ^(Reachability *reachability) {
|
||||
map_ptr->setReachability(true);
|
||||
};
|
||||
[reachability startNotifier];
|
||||
|
||||
// Load settings
|
||||
mbgl::Settings_NSUserDefaults settings;
|
||||
map.setLonLatZoom(settings.longitude, settings.latitude, settings.zoom);
|
||||
@@ -97,6 +109,8 @@ int main() {
|
||||
|
||||
int ret = view.run();
|
||||
|
||||
[reachability stopNotifier];
|
||||
|
||||
// Save settings
|
||||
map.getLonLatZoom(settings.longitude, settings.latitude, settings.zoom);
|
||||
settings.bearing = map.getBearing();
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
'../common/platform_nsstring.mm',
|
||||
'../common/glfw_view.hpp',
|
||||
'../common/glfw_view.cpp',
|
||||
'../common/foundation_request.h',
|
||||
'../common/foundation_request.mm',
|
||||
'../common/reachability.h',
|
||||
'../common/reachability.m',
|
||||
'../common/http_request_baton_cocoa.mm',
|
||||
'../common/osx.mm',
|
||||
'../common/nslog_log.hpp',
|
||||
'../common/nslog_log.mm',
|
||||
],
|
||||
@@ -33,6 +35,7 @@
|
||||
],
|
||||
'OTHER_LDFLAGS': [
|
||||
'<@(glfw3_libraries)',
|
||||
'-framework SystemConfiguration',
|
||||
],
|
||||
'SDKROOT': 'macosx',
|
||||
'INFOPLIST_FILE': 'Info.plist',
|
||||
|
||||
161
mapboxgl.gyp
161
mapboxgl.gyp
@@ -31,7 +31,7 @@
|
||||
'<(SHARED_INTERMEDIATE_DIR)/src/shader/shaders_gl.cpp',
|
||||
'<(SHARED_INTERMEDIATE_DIR)/src/shader/shaders_gles2.cpp'
|
||||
],
|
||||
'include_dirs':[
|
||||
'include_dirs': [
|
||||
'<(SHARED_INTERMEDIATE_DIR)/include/',
|
||||
]
|
||||
}
|
||||
@@ -126,53 +126,70 @@
|
||||
'<!@(find src -name "*.glsl")',
|
||||
'bin/style.json'
|
||||
],
|
||||
'xcode_settings': {
|
||||
'SDKROOT': 'macosx',
|
||||
'SUPPORTED_PLATFORMS':['macosx'],
|
||||
'MACOSX_DEPLOYMENT_TARGET':'10.9',
|
||||
'PUBLIC_HEADERS_FOLDER_PATH': 'include',
|
||||
'OTHER_CPLUSPLUSFLAGS':[
|
||||
'<@(png_cflags)',
|
||||
'<@(uv_cflags)',
|
||||
'-I<(boost_root)/include',
|
||||
]
|
||||
},
|
||||
'include_dirs':[
|
||||
'./include'
|
||||
'include_dirs': [
|
||||
'./include'
|
||||
],
|
||||
'cflags': [
|
||||
'<@(png_cflags)',
|
||||
'-I<(boost_root)/include',
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'include_dirs':[
|
||||
'./include',
|
||||
],
|
||||
'cflags': [
|
||||
'conditions': [
|
||||
['OS == "mac"', {
|
||||
'xcode_settings': {
|
||||
'SDKROOT': 'macosx',
|
||||
'SUPPORTED_PLATFORMS': ['macosx'],
|
||||
'MACOSX_DEPLOYMENT_TARGET': '10.9',
|
||||
'PUBLIC_HEADERS_FOLDER_PATH': 'include',
|
||||
'OTHER_CPLUSPLUSFLAGS': [
|
||||
'<@(png_cflags)',
|
||||
'<@(uv_cflags)',
|
||||
],
|
||||
'xcode_settings': {
|
||||
'OTHER_CPLUSPLUSFLAGS':[
|
||||
'<@(png_cflags)',
|
||||
'<@(uv_cflags)',
|
||||
]
|
||||
'<@(curl_cflags)',
|
||||
'<@(sqlite3_cflags)',
|
||||
'-I<(boost_root)/include',
|
||||
],
|
||||
'OTHER_CFLAGS': [
|
||||
'<@(uv_cflags)',
|
||||
],
|
||||
},
|
||||
'conditions': [
|
||||
['OS == "mac"', {
|
||||
'xcode_settings': {
|
||||
'OTHER_LDFLAGS': [
|
||||
'<@(png_libraries)',
|
||||
'<@(uv_libraries)',
|
||||
]
|
||||
}
|
||||
}, {
|
||||
'libraries': [
|
||||
}, {
|
||||
'cflags': [
|
||||
'<@(png_cflags)',
|
||||
'<@(uv_cflags)',
|
||||
'<@(curl_cflags)',
|
||||
'<@(sqlite3_cflags)',
|
||||
'-I<(boost_root)/include',
|
||||
],
|
||||
}]
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'include_dirs': [
|
||||
'./include',
|
||||
],
|
||||
'conditions': [
|
||||
['OS == "mac"', {
|
||||
'xcode_settings': {
|
||||
'OTHER_CPLUSPLUSFLAGS': [
|
||||
'<@(uv_cflags)',
|
||||
'<@(curl_cflags)',
|
||||
'-I<(boost_root)/include',
|
||||
],
|
||||
'OTHER_LDFLAGS': [
|
||||
'<@(png_libraries)',
|
||||
'<@(uv_libraries)',
|
||||
'<@(curl_libraries)',
|
||||
'<@(sqlite3_libraries)',
|
||||
]
|
||||
}]
|
||||
]
|
||||
}
|
||||
}, {
|
||||
'cflags': [
|
||||
'<@(uv_cflags)',
|
||||
'<@(curl_cflags)',
|
||||
'-I<(boost_root)/include',
|
||||
],
|
||||
'libraries': [
|
||||
'<@(png_libraries)',
|
||||
'<@(uv_libraries)',
|
||||
'<@(curl_libraries)',
|
||||
'<@(sqlite3_libraries)',
|
||||
]
|
||||
}]
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -181,7 +198,7 @@
|
||||
'type': 'static_library',
|
||||
'hard_dependency': 1,
|
||||
'dependencies': [
|
||||
'shaders',
|
||||
'shaders',
|
||||
],
|
||||
'sources': [
|
||||
'<!@(find src/ \( -name "*.cpp" ! -name shaders.hpp ! -name shaders_gles2.cpp ! -name shaders_gl.cpp \))',
|
||||
@@ -195,56 +212,42 @@
|
||||
],
|
||||
'xcode_settings': {
|
||||
'SDKROOT': 'iphoneos',
|
||||
'SUPPORTED_PLATFORMS':['iphonesimulator','iphoneos'],
|
||||
'SUPPORTED_PLATFORMS': ['iphonesimulator','iphoneos'],
|
||||
'ARCHS': [ "armv7", "armv7s", "arm64", "i386", "x86_64" ],
|
||||
'TARGETED_DEVICE_FAMILY': '1,2',
|
||||
'CODE_SIGN_IDENTITY': 'iPhone Developer',
|
||||
'IPHONEOS_DEPLOYMENT_TARGET': '7.0',
|
||||
'PUBLIC_HEADERS_FOLDER_PATH': 'include',
|
||||
'GCC_INPUT_FILETYPE':'sourcecode.cpp.cpp',
|
||||
'OTHER_CPLUSPLUSFLAGS':[
|
||||
'GCC_INPUT_FILETYPE': 'sourcecode.cpp.cpp',
|
||||
'OTHER_CPLUSPLUSFLAGS': [
|
||||
'<@(png_cflags)',
|
||||
'<@(uv_cflags)',
|
||||
'<@(curl_cflags)',
|
||||
'<@(sqlite3_cflags)',
|
||||
'-I<(boost_root)/include',
|
||||
]
|
||||
],
|
||||
},
|
||||
'include_dirs':[
|
||||
'./include'
|
||||
],
|
||||
'cflags': [
|
||||
'<@(png_cflags)',
|
||||
'<@(uv_cflags)',
|
||||
'-I<(boost_root)/include',
|
||||
'include_dirs': [
|
||||
'./include'
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'include_dirs':[
|
||||
'./include'
|
||||
'include_dirs': [
|
||||
'./include',
|
||||
],
|
||||
'xcode_settings': {
|
||||
'OTHER_LDFLAGS': [
|
||||
'<@(png_libraries)',
|
||||
'<@(uv_libraries)',
|
||||
'<@(curl_libraries)',
|
||||
'<@(sqlite3_libraries)',
|
||||
],
|
||||
'cflags': [
|
||||
'<@(png_cflags)',
|
||||
'<@(uv_cflags)',
|
||||
'OTHER_CPLUSPLUSFLAGS': [
|
||||
'<@(uv_cflags)',
|
||||
],
|
||||
'xcode_settings': {
|
||||
'OTHER_CPLUSPLUSFLAGS':[
|
||||
'<@(png_cflags)',
|
||||
'<@(uv_cflags)',
|
||||
]
|
||||
},
|
||||
'conditions': [
|
||||
['OS == "mac"', {
|
||||
'xcode_settings': {
|
||||
'OTHER_LDFLAGS': [
|
||||
'<@(png_libraries)',
|
||||
'<@(uv_libraries)',
|
||||
]
|
||||
}
|
||||
}, {
|
||||
'libraries': [
|
||||
'<@(png_libraries)',
|
||||
'<@(uv_libraries)'
|
||||
]
|
||||
}]
|
||||
]
|
||||
'OTHER_CFLAGS': [
|
||||
'<@(uv_cflags)',
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -16,12 +16,12 @@ if [[ ${TRAVIS_OS_NAME} == "linux" ]]; then
|
||||
# some limited coverage
|
||||
if [[ ${BUILDTYPE} == "Debug" ]]; then
|
||||
if [[ ${CXX} == "g++" ]]; then
|
||||
export CXXFLAGS="-fsanitize=address ${CXXFLAGS}"
|
||||
export CFLAGS="-fsanitize=address ${CFLAGS}"
|
||||
export CXXFLAGS="-fsanitize=address -g ${CXXFLAGS}"
|
||||
export CFLAGS="-fsanitize=address -g ${CFLAGS}"
|
||||
export LDFLAGS="-fsanitize=address ${LDFLAGS}"
|
||||
elif [[ ${CXX} == "clang++" ]]; then
|
||||
export CXXFLAGS="-fsanitize=thread -fPIC ${CXXFLAGS}"
|
||||
export CFLAGS="-fsanitize=thread ${CFLAGS}"
|
||||
export CXXFLAGS="-fsanitize=thread -g -fPIC ${CXXFLAGS}"
|
||||
export CFLAGS="-fsanitize=thread -g ${CFLAGS}"
|
||||
export LDFLAGS="-fsanitize=thread -pie ${LDFLAGS}"
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -53,6 +53,7 @@ NPM=$(which npm)
|
||||
|
||||
MP_HASH="e82e6c00ea5a0cda147e4c121a3c7751cae69ff8"
|
||||
DIR_HASH=$(echo `pwd` | git hash-object --stdin)
|
||||
|
||||
if [ ! -d 'mapnik-packaging/' ]; then
|
||||
git clone https://github.com/mapnik/mapnik-packaging.git
|
||||
fi
|
||||
@@ -66,7 +67,7 @@ export CXX11=true
|
||||
|
||||
if [ ${UNAME} = 'Darwin' ]; then
|
||||
|
||||
if [ ! -z "${TRAVIS:-}" ]; then
|
||||
if [[ $TRAVIS ]]; then
|
||||
if aws s3 cp s3://${AWS_S3_BUCKET}/dependencies/build-cpp11-libcpp-osx_${MP_HASH}_${DIR_HASH}.tar.gz ./out/ ; then
|
||||
if aws s3 cp s3://${AWS_S3_BUCKET}/dependencies/build-cpp11-libcpp-ios_${MP_HASH}_${DIR_HASH}.tar.gz ./out/ ; then
|
||||
rm -rf out/build-cpp11-libcpp-x86_64-macosx
|
||||
@@ -83,30 +84,40 @@ source iPhoneOS.sh
|
||||
export LIBUV_VERSION=0.10.28
|
||||
if [ ! -f out/build-cpp11-libcpp-armv7-iphoneos/lib/libpng.a ] ; then ./scripts/build_png.sh ; fi
|
||||
if [ ! -f out/build-cpp11-libcpp-armv7-iphoneos/lib/libuv.a ] ; then ./scripts/build_libuv.sh ; fi
|
||||
if [ ! -f out/build-cpp11-libcpp-armv7-iphoneos/lib/libcurl.a ] ; then ./scripts/build_curl.sh ; fi
|
||||
if [ ! -f out/build-cpp11-libcpp-armv7-iphoneos/lib/libsqlite3.a ] ; then ./scripts/build_sqlite.sh ; fi
|
||||
echo ' ...done'
|
||||
|
||||
source iPhoneOSs.sh
|
||||
export LIBUV_VERSION=0.10.28
|
||||
if [ ! -f out/build-cpp11-libcpp-armv7s-iphoneoss/lib/libpng.a ] ; then ./scripts/build_png.sh ; fi
|
||||
if [ ! -f out/build-cpp11-libcpp-armv7s-iphoneoss/lib/libuv.a ] ; then ./scripts/build_libuv.sh ; fi
|
||||
if [ ! -f out/build-cpp11-libcpp-armv7s-iphoneoss/lib/libcurl.a ] ; then ./scripts/build_curl.sh ; fi
|
||||
if [ ! -f out/build-cpp11-libcpp-armv7s-iphoneoss/lib/libsqlite3.a ] ; then ./scripts/build_sqlite.sh ; fi
|
||||
echo ' ...done'
|
||||
|
||||
source iPhoneOS64.sh
|
||||
export LIBUV_VERSION=0.10.28
|
||||
if [ ! -f out/build-cpp11-libcpp-arm64-iphoneos64/lib/libpng.a ] ; then ./scripts/build_png.sh ; fi
|
||||
if [ ! -f out/build-cpp11-libcpp-arm64-iphoneos64/lib/libuv.a ] ; then ./scripts/build_libuv.sh ; fi
|
||||
if [ ! -f out/build-cpp11-libcpp-arm64-iphoneos64/lib/libcurl.a ] ; then ./scripts/build_curl.sh ; fi
|
||||
if [ ! -f out/build-cpp11-libcpp-arm64-iphoneos64/lib/libsqlite3.a ] ; then ./scripts/build_sqlite.sh ; fi
|
||||
echo ' ...done'
|
||||
|
||||
source iPhoneSimulator.sh
|
||||
export LIBUV_VERSION=0.10.28
|
||||
if [ ! -f out/build-cpp11-libcpp-i386-iphonesimulator/lib/libpng.a ] ; then ./scripts/build_png.sh ; fi
|
||||
if [ ! -f out/build-cpp11-libcpp-i386-iphonesimulator/lib/libuv.a ] ; then ./scripts/build_libuv.sh ; fi
|
||||
if [ ! -f out/build-cpp11-libcpp-i386-iphonesimulator/lib/libcurl.a ] ; then ./scripts/build_curl.sh ; fi
|
||||
if [ ! -f out/build-cpp11-libcpp-i386-iphonesimulator/lib/libsqlite3.a ] ; then ./scripts/build_sqlite.sh ; fi
|
||||
echo ' ...done'
|
||||
|
||||
source iPhoneSimulator64.sh
|
||||
export LIBUV_VERSION=0.10.28
|
||||
if [ ! -f out/build-cpp11-libcpp-x86_64-iphonesimulator/lib/libpng.a ] ; then ./scripts/build_png.sh ; fi
|
||||
if [ ! -f out/build-cpp11-libcpp-x86_64-iphonesimulator/lib/libuv.a ] ; then ./scripts/build_libuv.sh ; fi
|
||||
if [ ! -f out/build-cpp11-libcpp-x86_64-iphonesimulator/lib/libcurl.a ] ; then ./scripts/build_curl.sh ; fi
|
||||
if [ ! -f out/build-cpp11-libcpp-x86_64-iphonesimulator/lib/libsqlite3.a ] ; then ./scripts/build_sqlite.sh ; fi
|
||||
echo ' ...done'
|
||||
|
||||
source MacOSX.sh
|
||||
@@ -114,6 +125,7 @@ export LIBUV_VERSION=0.10.28
|
||||
if [ ! -f out/build-cpp11-libcpp-x86_64-macosx/lib/libpng.a ] ; then ./scripts/build_png.sh ; fi
|
||||
if [ ! -f out/build-cpp11-libcpp-x86_64-macosx/lib/libglfw3.a ] ; then ./scripts/build_glfw.sh ; fi
|
||||
if [ ! -f out/build-cpp11-libcpp-x86_64-macosx/lib/libuv.a ] ; then ./scripts/build_libuv.sh ; fi
|
||||
if [ ! -f out/build-cpp11-libcpp-x86_64-macosx/lib/libsqlite3.a ] ; then ./scripts/build_sqlite.sh ; fi
|
||||
if [ ! -f out/build-cpp11-libcpp-x86_64-macosx/lib/libssl.a ] ; then ./scripts/build_openssl.sh ; fi
|
||||
if [ ! -f out/build-cpp11-libcpp-x86_64-macosx/lib/libcurl.a ] ; then ./scripts/build_curl.sh ; fi
|
||||
if [ ! -d out/build-cpp11-libcpp-x86_64-macosx/include/boost ] ; then ./scripts/build_boost.sh `pwd`/../../src/ `pwd`/../../include/ `pwd`/../../linux/ `pwd`/../../common/ ; fi
|
||||
@@ -121,8 +133,10 @@ export LIBUV_VERSION=0.10.28
|
||||
|
||||
# setup iOS universal libs
|
||||
./scripts/make_universal.sh
|
||||
patch -p0 --forward < patches/curl-ios.diff || true
|
||||
echo "NOTE: One patch FAILURE is expected. The other should have been applied or ignored."
|
||||
|
||||
if [ ! -z "${TRAVIS:-}" ] && [ ! -z "${AWS_ACCESS_KEY_ID}" ] && [ ! -z "${AWS_SECRET_ACCESS_KEY}" ] ; then
|
||||
if [[ $TRAVIS && $AWS_ACCESS_KEY_ID && $AWS_SECRET_ACCESS_KEY ]] ; then
|
||||
tar -zcf out/build-cpp11-libcpp-ios_${MP_HASH}_${DIR_HASH}.tar.gz out/build-cpp11-libcpp-universal
|
||||
aws s3 cp --acl public-read out/build-cpp11-libcpp-ios_${MP_HASH}_${DIR_HASH}.tar.gz s3://${AWS_S3_BUCKET}/dependencies/
|
||||
tar -zcf out/build-cpp11-libcpp-osx_${MP_HASH}_${DIR_HASH}.tar.gz out/build-cpp11-libcpp-x86_64-macosx
|
||||
@@ -138,7 +152,7 @@ cd ../../
|
||||
|
||||
elif [ ${UNAME} = 'Linux' ]; then
|
||||
|
||||
if [ ! -z "${TRAVIS:-}" ]; then
|
||||
if [[ $TRAVIS ]]; then
|
||||
if aws s3 cp s3://${AWS_S3_BUCKET}/dependencies/build-cpp11-libstdcpp-gcc-x86_64-linux_${MP_HASH}_${DIR_HASH}.tar.gz ./out/ ; then
|
||||
rm -rf out/build-cpp11-libstdcpp-gcc-x86_64-linux
|
||||
tar -xzf out/build-cpp11-libstdcpp-gcc-x86_64-linux_${MP_HASH}_${DIR_HASH}.tar.gz
|
||||
@@ -150,11 +164,12 @@ export LIBUV_VERSION=0.10.28
|
||||
if [ ! -f out/build-cpp11-libstdcpp-gcc-x86_64-linux/lib/libglfw3.a ] ; then ./scripts/build_glfw.sh ; fi
|
||||
if [ ! -f out/build-cpp11-libstdcpp-gcc-x86_64-linux/lib/libpng.a ] ; then ./scripts/build_png.sh ; fi
|
||||
if [ ! -f out/build-cpp11-libstdcpp-gcc-x86_64-linux/lib/libuv.a ] ; then ./scripts/build_libuv.sh ; fi
|
||||
if [ ! -f out/build-cpp11-libstdcpp-gcc-x86_64-linux/lib/libsqlite3.a ] ; then ./scripts/build_sqlite.sh ; fi
|
||||
if [ ! -f out/build-cpp11-libstdcpp-gcc-x86_64-linux/lib/libssl.a ] ; then ./scripts/build_openssl.sh ; fi
|
||||
if [ ! -f out/build-cpp11-libstdcpp-gcc-x86_64-linux/lib/libcurl.a ] ; then ./scripts/build_curl.sh ; fi
|
||||
if [ ! -f out/build-cpp11-libstdcpp-gcc-x86_64-linux/lib/libboost_regex.a ] ; then ./scripts/build_boost.sh --with-regex ; fi
|
||||
|
||||
if [ ! -z "${TRAVIS:-}" ] && [ ! -z "${AWS_ACCESS_KEY_ID}" ] && [ ! -z "${AWS_SECRET_ACCESS_KEY}" ] ; then
|
||||
if [[ $TRAVIS && $AWS_ACCESS_KEY_ID && $AWS_SECRET_ACCESS_KEY ]] ; then
|
||||
if ! tar --compare -zf out/build-cpp11-libstdcpp-gcc-x86_64-linux.tar.gz ; then
|
||||
tar -zcf out/build-cpp11-libstdcpp-gcc-x86_64-linux_${MP_HASH}_${DIR_HASH}.tar.gz out/build-cpp11-libstdcpp-gcc-x86_64-linux
|
||||
aws s3 cp --acl public-read out/build-cpp11-libstdcpp-gcc-x86_64-linux_${MP_HASH}_${DIR_HASH}.tar.gz s3://${AWS_S3_BUCKET}/dependencies/
|
||||
|
||||
219
src/map/map.cpp
219
src/map/map.cpp
@@ -19,11 +19,10 @@
|
||||
#include <mbgl/style/style_bucket.hpp>
|
||||
#include <mbgl/util/texturepool.hpp>
|
||||
#include <mbgl/geometry/sprite_atlas.hpp>
|
||||
#include <mbgl/util/filesource.hpp>
|
||||
#include <mbgl/storage/file_source.hpp>
|
||||
#include <mbgl/platform/log.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
@@ -34,12 +33,15 @@ using namespace mbgl;
|
||||
Map::Map(View& view)
|
||||
: loop(std::make_shared<uv::loop>()),
|
||||
thread(std::make_unique<uv::thread>()),
|
||||
async_terminate(new uv_async_t()),
|
||||
async_render(new uv_async_t()),
|
||||
async_cleanup(new uv_async_t()),
|
||||
view(view),
|
||||
#ifndef NDEBUG
|
||||
main_thread(uv_thread_self()),
|
||||
#endif
|
||||
transform(view),
|
||||
fileSource(std::make_shared<FileSource>()),
|
||||
style(std::make_shared<Style>()),
|
||||
glyphAtlas(std::make_shared<GlyphAtlas>(1024, 1024)),
|
||||
glyphStore(std::make_shared<GlyphStore>(fileSource)),
|
||||
spriteAtlas(std::make_shared<SpriteAtlas>(512, 512)),
|
||||
texturepool(std::make_shared<Texturepool>()),
|
||||
painter(*this) {
|
||||
@@ -53,49 +55,93 @@ Map::Map(View& view)
|
||||
}
|
||||
|
||||
Map::~Map() {
|
||||
// Clear the style first before the rest of the constructor deletes members of this object.
|
||||
// This is required because members of the style reference the Map object in their destructors.
|
||||
style.reset();
|
||||
|
||||
if (async) {
|
||||
stop();
|
||||
}
|
||||
|
||||
// Explicitly reset all pointers.
|
||||
texturepool.reset();
|
||||
sprite.reset();
|
||||
spriteAtlas.reset();
|
||||
glyphStore.reset();
|
||||
glyphAtlas.reset();
|
||||
style.reset();
|
||||
fileSource.reset();
|
||||
workers.reset();
|
||||
|
||||
uv_run(**loop, UV_RUN_DEFAULT);
|
||||
}
|
||||
|
||||
uv::worker &Map::getWorker() {
|
||||
if (!workers) {
|
||||
workers = std::make_unique<uv::worker>(**loop, 4, "Tile Worker");
|
||||
}
|
||||
return *workers;
|
||||
}
|
||||
|
||||
void Map::start() {
|
||||
assert(uv_thread_self() == main_thread);
|
||||
assert(!async);
|
||||
|
||||
// When starting map rendering in another thread, we perform async/continuously
|
||||
// updated rendering. Only in these cases, we attach the async handlers.
|
||||
async = true;
|
||||
|
||||
// Setup async notifications
|
||||
async_terminate = new uv_async_t();
|
||||
uv_async_init(**loop, async_terminate, terminate);
|
||||
async_terminate->data = **loop;
|
||||
// Reset the flag.
|
||||
is_stopped = false;
|
||||
|
||||
async_render = new uv_async_t();
|
||||
uv_async_init(**loop, async_render, render);
|
||||
// Setup async notifications
|
||||
uv_async_init(**loop, async_terminate.get(), terminate);
|
||||
async_terminate->data = this;
|
||||
|
||||
uv_async_init(**loop, async_render.get(), render);
|
||||
async_render->data = this;
|
||||
|
||||
async_cleanup = new uv_async_t();
|
||||
uv_async_init(**loop, async_cleanup, cleanup);
|
||||
uv_async_init(**loop, async_cleanup.get(), cleanup);
|
||||
async_cleanup->data = this;
|
||||
|
||||
uv_thread_create(*thread, [](void *arg) {
|
||||
Map *map = static_cast<Map *>(arg);
|
||||
#ifndef NDEBUG
|
||||
map->map_thread = uv_thread_self();
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
pthread_setname_np("Map");
|
||||
#endif
|
||||
map->run();
|
||||
#ifndef NDEBUG
|
||||
map->map_thread = -1;
|
||||
#endif
|
||||
|
||||
// Make sure that the stop() function knows when to stop invoking the callback function.
|
||||
map->is_stopped = true;
|
||||
map->view.notify();
|
||||
}, this);
|
||||
}
|
||||
|
||||
void Map::stop() {
|
||||
if (async_terminate != nullptr) {
|
||||
uv_async_send(async_terminate);
|
||||
void Map::stop(stop_callback cb, void *data) {
|
||||
assert(uv_thread_self() == main_thread);
|
||||
assert(main_thread != map_thread);
|
||||
assert(async);
|
||||
|
||||
uv_async_send(async_terminate.get());
|
||||
|
||||
if (cb) {
|
||||
// Wait until the render thread stopped. We are using this construct instead of plainly
|
||||
// relying on the thread_join because the system might need to run things in the current
|
||||
// thread that is required for the render thread to terminate correctly. This is for example
|
||||
// the case with Cocoa's NSURLRequest. Otherwise, we will eventually deadlock because this
|
||||
// thread (== main thread) is blocked. The callback function should use an efficient waiting
|
||||
// function to avoid a busy waiting loop.
|
||||
while (!is_stopped) {
|
||||
cb(data);
|
||||
}
|
||||
}
|
||||
|
||||
// If a callback function was provided, this should return immediately because the thread has
|
||||
// already finished executing.
|
||||
uv_thread_join(*thread);
|
||||
|
||||
// Run the event loop once to make sure our async delete handlers are called.
|
||||
uv_run(**loop, UV_RUN_ONCE);
|
||||
|
||||
async = false;
|
||||
}
|
||||
|
||||
@@ -104,22 +150,35 @@ void Map::delete_async(uv_handle_t *handle, int status) {
|
||||
}
|
||||
|
||||
void Map::run() {
|
||||
#ifndef NDEBUG
|
||||
if (!async) {
|
||||
map_thread = main_thread;
|
||||
}
|
||||
#endif
|
||||
assert(uv_thread_self() == map_thread);
|
||||
|
||||
setup();
|
||||
prepare();
|
||||
uv_run(**loop, UV_RUN_DEFAULT);
|
||||
|
||||
// Run the event loop once more to make sure our async delete handlers are called.
|
||||
uv_run(**loop, UV_RUN_ONCE);
|
||||
|
||||
// If the map rendering wasn't started asynchronously, we perform one render
|
||||
// *after* all events have been processed.
|
||||
if (!async) {
|
||||
render();
|
||||
#ifndef NDEBUG
|
||||
map_thread = -1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void Map::rerender() {
|
||||
// We only send render events if we want to continuously update the map
|
||||
// (== async rendering).
|
||||
if (async && async_render != nullptr) {
|
||||
uv_async_send(async_render);
|
||||
if (async) {
|
||||
uv_async_send(async_render.get());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +198,7 @@ void Map::swapped() {
|
||||
|
||||
void Map::cleanup() {
|
||||
if (async_cleanup != nullptr) {
|
||||
uv_async_send(async_cleanup);
|
||||
uv_async_send(async_cleanup.get());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,9 +212,20 @@ void Map::terminate() {
|
||||
painter.terminate();
|
||||
}
|
||||
|
||||
void Map::setReachability(bool reachable) {
|
||||
// Note: This function may be called from *any* thread.
|
||||
if (reachable) {
|
||||
if (fileSource) {
|
||||
fileSource->prepare([&]() {
|
||||
fileSource->retryAllPending();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Map::render(uv_async_t *async, int status) {
|
||||
Map *map = static_cast<Map *>(async->data);
|
||||
|
||||
assert(uv_thread_self() == map->map_thread);
|
||||
|
||||
if (map->state.hasSize()) {
|
||||
if (map->is_rendered.test_and_set() == false) {
|
||||
@@ -175,44 +245,48 @@ void Map::render(uv_async_t *async, int status) {
|
||||
|
||||
void Map::terminate(uv_async_t *async, int status) {
|
||||
// Closes all open handles on the loop. This means that the loop will automatically terminate.
|
||||
uv_loop_t *loop = static_cast<uv_loop_t *>(async->data);
|
||||
uv_walk(loop, [](uv_handle_t *handle, void */*arg*/) {
|
||||
if (!uv_is_closing(handle)) {
|
||||
uv_close(handle, NULL);
|
||||
}
|
||||
}, NULL);
|
||||
Map *map = static_cast<Map *>(async->data);
|
||||
assert(uv_thread_self() == map->map_thread);
|
||||
|
||||
// Remove all of these to make sure they are destructed in the correct thread.
|
||||
map->glyphStore.reset();
|
||||
map->fileSource.reset();
|
||||
map->style.reset();
|
||||
map->workers.reset();
|
||||
map->activeSources.clear();
|
||||
|
||||
uv_close((uv_handle_t *)map->async_cleanup.get(), nullptr);
|
||||
uv_close((uv_handle_t *)map->async_render.get(), nullptr);
|
||||
uv_close((uv_handle_t *)map->async_terminate.get(), nullptr);
|
||||
}
|
||||
|
||||
#pragma mark - Setup
|
||||
|
||||
void Map::setup() {
|
||||
assert(uv_thread_self() == map_thread);
|
||||
view.make_active();
|
||||
painter.setup();
|
||||
view.make_inactive();
|
||||
}
|
||||
|
||||
void Map::setStyleURL(const std::string &url) {
|
||||
fileSource->load(ResourceType::JSON, url, [&](platform::Response *res) {
|
||||
if (res->code == 200) {
|
||||
// Calculate the base
|
||||
const size_t pos = url.rfind('/');
|
||||
std::string base = "";
|
||||
if (pos != std::string::npos) {
|
||||
base = url.substr(0, pos + 1);
|
||||
}
|
||||
|
||||
this->setStyleJSON(res->body, base);
|
||||
} else {
|
||||
Log::Error(Event::Setup, "loading style failed: %d (%s)", res->code, res->error_message.c_str());
|
||||
}
|
||||
}, loop);
|
||||
// TODO: Make threadsafe.
|
||||
styleURL = url;
|
||||
}
|
||||
|
||||
|
||||
void Map::setStyleJSON(std::string newStyleJSON, const std::string &base) {
|
||||
// TODO: Make threadsafe.
|
||||
styleJSON.swap(newStyleJSON);
|
||||
sprite.reset();
|
||||
if (!style) {
|
||||
style = std::make_shared<Style>();
|
||||
}
|
||||
style->loadJSON((const uint8_t *)styleJSON.c_str());
|
||||
if (!fileSource) {
|
||||
fileSource = std::make_shared<FileSource>(**loop, platform::defaultCacheDatabase());
|
||||
glyphStore = std::make_shared<GlyphStore>(fileSource);
|
||||
}
|
||||
fileSource->setBase(base);
|
||||
glyphStore->setURL(util::mapbox::normalizeGlyphsURL(style->glyph_url, getAccessToken()));
|
||||
update();
|
||||
@@ -223,6 +297,7 @@ std::string Map::getStyleJSON() const {
|
||||
}
|
||||
|
||||
void Map::setAccessToken(std::string access_token) {
|
||||
// TODO: Make threadsafe.
|
||||
accessToken.swap(access_token);
|
||||
}
|
||||
|
||||
@@ -230,7 +305,7 @@ std::string Map::getAccessToken() const {
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
std::shared_ptr<Sprite> Map::getSprite() {
|
||||
util::ptr<Sprite> Map::getSprite() {
|
||||
const float pixelRatio = state.getPixelRatio();
|
||||
const std::string &sprite_url = style->getSpriteURL();
|
||||
if (!sprite || sprite->pixelRatio != pixelRatio) {
|
||||
@@ -460,8 +535,10 @@ void Map::setDefaultTransitionDuration(uint64_t duration_milliseconds) {
|
||||
}
|
||||
|
||||
void Map::updateSources() {
|
||||
assert(uv_thread_self() == map_thread);
|
||||
|
||||
// First, disable all existing sources.
|
||||
for (const std::shared_ptr<StyleSource> &source : activeSources) {
|
||||
for (const util::ptr<StyleSource> &source : activeSources) {
|
||||
source->enabled = false;
|
||||
}
|
||||
|
||||
@@ -469,7 +546,7 @@ void Map::updateSources() {
|
||||
updateSources(style->layers);
|
||||
|
||||
// Then, construct or destroy the actual source object, depending on enabled state.
|
||||
for (const std::shared_ptr<StyleSource> &style_source : activeSources) {
|
||||
for (const util::ptr<StyleSource> &style_source : activeSources) {
|
||||
if (style_source->enabled) {
|
||||
if (!style_source->source) {
|
||||
style_source->source = std::make_shared<Source>(style_source->info);
|
||||
@@ -481,20 +558,20 @@ void Map::updateSources() {
|
||||
}
|
||||
|
||||
// Finally, remove all sources that are disabled.
|
||||
util::erase_if(activeSources, [](std::shared_ptr<StyleSource> source){
|
||||
util::erase_if(activeSources, [](util::ptr<StyleSource> source){
|
||||
return !source->enabled;
|
||||
});
|
||||
}
|
||||
|
||||
const std::set<std::shared_ptr<StyleSource>> Map::getActiveSources() const {
|
||||
const std::set<util::ptr<StyleSource>> Map::getActiveSources() const {
|
||||
return activeSources;
|
||||
}
|
||||
|
||||
void Map::updateSources(const std::shared_ptr<StyleLayerGroup> &group) {
|
||||
void Map::updateSources(const util::ptr<StyleLayerGroup> &group) {
|
||||
if (!group) {
|
||||
return;
|
||||
}
|
||||
for (const std::shared_ptr<StyleLayer> &layer : group->layers) {
|
||||
for (const util::ptr<StyleLayer> &layer : group->layers) {
|
||||
if (!layer) continue;
|
||||
if (layer->bucket) {
|
||||
if (layer->bucket->style_source) {
|
||||
@@ -507,7 +584,7 @@ void Map::updateSources(const std::shared_ptr<StyleLayerGroup> &group) {
|
||||
}
|
||||
|
||||
void Map::updateTiles() {
|
||||
for (const std::shared_ptr<StyleSource> &source : getActiveSources()) {
|
||||
for (const util::ptr<StyleSource> &source : getActiveSources()) {
|
||||
source->source->update(*this);
|
||||
}
|
||||
}
|
||||
@@ -515,13 +592,37 @@ void Map::updateTiles() {
|
||||
void Map::updateRenderState() {
|
||||
// Update all clipping IDs.
|
||||
ClipIDGenerator generator;
|
||||
for (const std::shared_ptr<StyleSource> &source : getActiveSources()) {
|
||||
for (const util::ptr<StyleSource> &source : getActiveSources()) {
|
||||
generator.update(source->source->getLoadedTiles());
|
||||
source->source->updateMatrices(painter.projMatrix, state);
|
||||
}
|
||||
}
|
||||
|
||||
void Map::prepare() {
|
||||
if (!fileSource) {
|
||||
fileSource = std::make_shared<FileSource>(**loop, platform::defaultCacheDatabase());
|
||||
glyphStore = std::make_shared<GlyphStore>(fileSource);
|
||||
}
|
||||
|
||||
if (!style) {
|
||||
style = std::make_shared<Style>();
|
||||
|
||||
fileSource->request(ResourceType::JSON, styleURL)->onload([&](const Response &res) {
|
||||
if (res.code == 200) {
|
||||
// Calculate the base
|
||||
const size_t pos = styleURL.rfind('/');
|
||||
std::string base = "";
|
||||
if (pos != std::string::npos) {
|
||||
base = styleURL.substr(0, pos + 1);
|
||||
}
|
||||
|
||||
setStyleJSON(res.data, base);
|
||||
} else {
|
||||
Log::Error(Event::Setup, "loading style failed: %ld (%s)", res.code, res.message.c_str());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Update transform transitions.
|
||||
animationTime = util::now();
|
||||
if (transform.needsTransition()) {
|
||||
@@ -568,7 +669,7 @@ void Map::render() {
|
||||
// This guarantees that we have at least one function per tile called.
|
||||
// When only rendering layers via the stylesheet, it's possible that we don't
|
||||
// ever visit a tile during rendering.
|
||||
for (const std::shared_ptr<StyleSource> &source : getActiveSources()) {
|
||||
for (const util::ptr<StyleSource> &source : getActiveSources()) {
|
||||
source->source->finishRender(painter);
|
||||
}
|
||||
|
||||
@@ -582,7 +683,7 @@ void Map::render() {
|
||||
view.make_inactive();
|
||||
}
|
||||
|
||||
void Map::renderLayers(std::shared_ptr<StyleLayerGroup> group) {
|
||||
void Map::renderLayers(util::ptr<StyleLayerGroup> group) {
|
||||
if (!group) {
|
||||
// Make sure that we actually do have a layer group.
|
||||
return;
|
||||
@@ -625,7 +726,7 @@ void Map::renderLayers(std::shared_ptr<StyleLayerGroup> group) {
|
||||
}
|
||||
}
|
||||
|
||||
void Map::renderLayer(std::shared_ptr<StyleLayer> layer_desc, RenderPass pass, const Tile::ID* id, const mat4* matrix) {
|
||||
void Map::renderLayer(util::ptr<StyleLayer> layer_desc, RenderPass pass, const Tile::ID* id, const mat4* matrix) {
|
||||
if (layer_desc->type == StyleLayerType::Background) {
|
||||
// This layer defines a background color/image.
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
using namespace mbgl;
|
||||
|
||||
|
||||
RasterTileData::RasterTileData(Tile::ID id, Map &map, const SourceInfo &source)
|
||||
RasterTileData::RasterTileData(Tile::ID id, Map &map, const util::ptr<SourceInfo> &source)
|
||||
: TileData(id, map, source),
|
||||
bucket(map.getTexturepool(), properties) {
|
||||
}
|
||||
@@ -25,10 +25,10 @@ void RasterTileData::parse() {
|
||||
}
|
||||
}
|
||||
|
||||
void RasterTileData::render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc, const mat4 &matrix) {
|
||||
void RasterTileData::render(Painter &painter, util::ptr<StyleLayer> layer_desc, const mat4 &matrix) {
|
||||
bucket.render(painter, layer_desc, id, matrix);
|
||||
}
|
||||
|
||||
bool RasterTileData::hasData(std::shared_ptr<StyleLayer> /*layer_desc*/) const {
|
||||
bool RasterTileData::hasData(util::ptr<StyleLayer> /*layer_desc*/) const {
|
||||
return bucket.hasData();
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <mbgl/util/raster.hpp>
|
||||
#include <mbgl/util/string.hpp>
|
||||
#include <mbgl/util/texturepool.hpp>
|
||||
#include <mbgl/util/filesource.hpp>
|
||||
#include <mbgl/storage/file_source.hpp>
|
||||
#include <mbgl/util/vec.hpp>
|
||||
#include <mbgl/util/math.hpp>
|
||||
#include <mbgl/util/std.hpp>
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
Source::Source(SourceInfo& info)
|
||||
Source::Source(const util::ptr<SourceInfo>& info)
|
||||
: info(info)
|
||||
{
|
||||
}
|
||||
@@ -29,32 +29,33 @@ Source::Source(SourceInfo& info)
|
||||
// The reason this isn't part of the constructor is that calling shared_from_this() in
|
||||
// the constructor fails.
|
||||
void Source::load(Map& map) {
|
||||
if (info.url.empty()) {
|
||||
if (info->url.empty()) {
|
||||
loaded = true;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string url = util::mapbox::normalizeSourceURL(info.url, map.getAccessToken());
|
||||
std::shared_ptr<Source> source = shared_from_this();
|
||||
std::string url = util::mapbox::normalizeSourceURL(info->url, map.getAccessToken());
|
||||
util::ptr<Source> source = shared_from_this();
|
||||
|
||||
map.getFileSource()->load(ResourceType::JSON, url, [source, &map](platform::Response *res) {
|
||||
if (res->code != 200) {
|
||||
map.getFileSource()->request(ResourceType::JSON, url)->onload([source, &map](const Response &res) {
|
||||
if (res.code != 200) {
|
||||
Log::Warning(Event::General, "failed to load source TileJSON");
|
||||
return;
|
||||
}
|
||||
|
||||
rapidjson::Document d;
|
||||
d.Parse<0>(res->body.c_str());
|
||||
d.Parse<0>(res.data.c_str());
|
||||
|
||||
if (d.HasParseError()) {
|
||||
Log::Warning(Event::General, "invalid source TileJSON");
|
||||
return;
|
||||
}
|
||||
|
||||
source->info.parseTileJSONProperties(d);
|
||||
source->info->parseTileJSONProperties(d);
|
||||
source->loaded = true;
|
||||
|
||||
map.update();
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@@ -98,7 +99,7 @@ void Source::drawClippingMasks(Painter &painter) {
|
||||
}
|
||||
}
|
||||
|
||||
void Source::render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc) {
|
||||
void Source::render(Painter &painter, util::ptr<StyleLayer> layer_desc) {
|
||||
gl::group group(std::string("layer: ") + layer_desc->id);
|
||||
for (const std::pair<const Tile::ID, std::unique_ptr<Tile>> &pair : tiles) {
|
||||
Tile &tile = *pair.second;
|
||||
@@ -108,7 +109,7 @@ void Source::render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc) {
|
||||
}
|
||||
}
|
||||
|
||||
void Source::render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID &id, const mat4 &matrix) {
|
||||
void Source::render(Painter &painter, util::ptr<StyleLayer> layer_desc, const Tile::ID &id, const mat4 &matrix) {
|
||||
auto it = tiles.find(id);
|
||||
if (it != tiles.end() && it->second->data && it->second->data->state == TileData::State::parsed) {
|
||||
painter.renderTileLayer(*it->second, layer_desc, matrix);
|
||||
@@ -183,9 +184,9 @@ TileData::State Source::addTile(Map &map, const Tile::ID& id) {
|
||||
|
||||
if (!new_tile.data) {
|
||||
// If we don't find working tile data, we're just going to load it.
|
||||
if (info.type == SourceType::Vector) {
|
||||
if (info->type == SourceType::Vector) {
|
||||
new_tile.data = std::make_shared<VectorTileData>(normalized_id, map, info);
|
||||
} else if (info.type == SourceType::Raster) {
|
||||
} else if (info->type == SourceType::Raster) {
|
||||
new_tile.data = std::make_shared<RasterTileData>(normalized_id, map, info);
|
||||
} else {
|
||||
throw std::runtime_error("source type not implemented");
|
||||
@@ -199,7 +200,7 @@ TileData::State Source::addTile(Map &map, const Tile::ID& id) {
|
||||
}
|
||||
|
||||
double Source::getZoom(const TransformState& state) const {
|
||||
double offset = std::log(util::tileSize / info.tile_size) / std::log(2);
|
||||
double offset = std::log(util::tileSize / info->tile_size) / std::log(2);
|
||||
offset += (state.getPixelRatio() > 1.0 ? 1 :0);
|
||||
return state.getZoom() + offset;
|
||||
}
|
||||
@@ -211,8 +212,8 @@ int32_t Source::coveringZoomLevel(const TransformState& state) const {
|
||||
std::forward_list<Tile::ID> Source::coveringTiles(const TransformState& state) const {
|
||||
int32_t z = coveringZoomLevel(state);
|
||||
|
||||
if (z < info.min_zoom) return {{}};
|
||||
if (z > info.max_zoom) z = info.max_zoom;
|
||||
if (z < info->min_zoom) return {{}};
|
||||
if (z > info->max_zoom) z = info->max_zoom;
|
||||
|
||||
// Map four viewport corners to pixel coordinates
|
||||
box points = state.cornersToBox(z);
|
||||
@@ -285,8 +286,8 @@ bool Source::updateTiles(Map &map) {
|
||||
std::forward_list<Tile::ID> required = coveringTiles(map.getState());
|
||||
|
||||
// Determine the overzooming/underzooming amounts.
|
||||
int32_t minCoveringZoom = util::clamp<int32_t>(zoom - 10, info.min_zoom, info.max_zoom);
|
||||
int32_t maxCoveringZoom = util::clamp<int32_t>(zoom + 1, info.min_zoom, info.max_zoom);
|
||||
int32_t minCoveringZoom = util::clamp<int32_t>(zoom - 10, info->min_zoom, info->max_zoom);
|
||||
int32_t maxCoveringZoom = util::clamp<int32_t>(zoom + 1, info->min_zoom, info->max_zoom);
|
||||
|
||||
// Retain is a list of tiles that we shouldn't delete, even if they are not
|
||||
// the most ideal tile for the current viewport. This may include tiles like
|
||||
@@ -333,7 +334,7 @@ bool Source::updateTiles(Map &map) {
|
||||
|
||||
// Remove all the expired pointers from the set.
|
||||
util::erase_if(tile_data, [&retain_data](std::pair<const Tile::ID, std::weak_ptr<TileData>> &pair) {
|
||||
const std::shared_ptr<TileData> tile = pair.second.lock();
|
||||
const util::ptr<TileData> tile = pair.second.lock();
|
||||
if (!tile) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include <string>
|
||||
#include <mbgl/platform/platform.hpp>
|
||||
#include <mbgl/util/filesource.hpp>
|
||||
#include <mbgl/storage/file_source.hpp>
|
||||
#include <mbgl/util/uv_detail.hpp>
|
||||
#include <mbgl/util/std.hpp>
|
||||
|
||||
@@ -22,8 +22,8 @@ SpritePosition::SpritePosition(uint16_t x, uint16_t y, uint16_t width, uint16_t
|
||||
sdf(sdf) {
|
||||
}
|
||||
|
||||
std::shared_ptr<Sprite> Sprite::Create(const std::string& base_url, float pixelRatio, const std::shared_ptr<FileSource> &fileSource) {
|
||||
std::shared_ptr<Sprite> sprite(std::make_shared<Sprite>(Key(), base_url, pixelRatio));
|
||||
util::ptr<Sprite> Sprite::Create(const std::string& base_url, float pixelRatio, const util::ptr<FileSource> &fileSource) {
|
||||
util::ptr<Sprite> sprite(std::make_shared<Sprite>(Key(), base_url, pixelRatio));
|
||||
sprite->load(fileSource);
|
||||
return sprite;
|
||||
}
|
||||
@@ -51,7 +51,7 @@ Sprite::operator bool() const {
|
||||
// Note: This is a separate function that must be called exactly once after creation
|
||||
// The reason this isn't part of the constructor is that calling shared_from_this() in
|
||||
// the constructor fails.
|
||||
void Sprite::load(const std::shared_ptr<FileSource> &fileSource) {
|
||||
void Sprite::load(const util::ptr<FileSource> &fileSource) {
|
||||
if (!valid) {
|
||||
// Treat a non-existent sprite as a successfully loaded empty sprite.
|
||||
loadedImage = true;
|
||||
@@ -60,30 +60,30 @@ void Sprite::load(const std::shared_ptr<FileSource> &fileSource) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::shared_ptr<Sprite> sprite = shared_from_this();
|
||||
util::ptr<Sprite> sprite = shared_from_this();
|
||||
|
||||
fileSource->load(ResourceType::JSON, jsonURL, [sprite](platform::Response *res) {
|
||||
if (res->code == 200) {
|
||||
sprite->body.swap(res->body);
|
||||
fileSource->request(ResourceType::JSON, jsonURL)->onload([sprite](const Response &res) {
|
||||
if (res.code == 200) {
|
||||
sprite->body = res.data;
|
||||
sprite->parseJSON();
|
||||
sprite->complete();
|
||||
} else {
|
||||
Log::Warning(Event::Sprite, "Failed to load sprite info: Error %d: %s", res->code, res->error_message.c_str());
|
||||
Log::Warning(Event::Sprite, "Failed to load sprite info: Error %d: %s", res.code, res.message.c_str());
|
||||
if (!sprite->future.valid()) {
|
||||
sprite->promise.set_exception(std::make_exception_ptr(std::runtime_error(res->error_message)));
|
||||
sprite->promise.set_exception(std::make_exception_ptr(std::runtime_error(res.message)));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
fileSource->load(ResourceType::Image, spriteURL, [sprite](platform::Response *res) {
|
||||
if (res->code == 200) {
|
||||
sprite->image.swap(res->body);
|
||||
fileSource->request(ResourceType::Image, spriteURL)->onload([sprite](const Response &res) {
|
||||
if (res.code == 200) {
|
||||
sprite->image = res.data;
|
||||
sprite->parseImage();
|
||||
sprite->complete();
|
||||
} else {
|
||||
Log::Warning(Event::Sprite, "Failed to load sprite image: Error %d: %s", res->code, res->error_message.c_str());
|
||||
Log::Warning(Event::Sprite, "Failed to load sprite image: Error %d: %s", res.code, res.message.c_str());
|
||||
if (!sprite->future.valid()) {
|
||||
sprite->promise.set_exception(std::make_exception_ptr(std::runtime_error(res->error_message)));
|
||||
sprite->promise.set_exception(std::make_exception_ptr(std::runtime_error(res.message)));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
|
||||
#include <mbgl/util/token.hpp>
|
||||
#include <mbgl/util/string.hpp>
|
||||
#include <mbgl/util/filesource.hpp>
|
||||
#include <mbgl/storage/file_source.hpp>
|
||||
#include <mbgl/util/uv_detail.hpp>
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
TileData::TileData(Tile::ID id, Map &map, const SourceInfo &source)
|
||||
TileData::TileData(Tile::ID id, Map &map, const util::ptr<SourceInfo> &source)
|
||||
: id(id),
|
||||
state(State::initial),
|
||||
map(map),
|
||||
@@ -29,10 +29,10 @@ const std::string TileData::toString() const {
|
||||
}
|
||||
|
||||
void TileData::request() {
|
||||
if (source.tiles.empty())
|
||||
if (source->tiles.empty())
|
||||
return;
|
||||
|
||||
std::string url = source.tiles[(id.x + id.y) % source.tiles.size()];
|
||||
std::string url = source->tiles[(id.x + id.y) % source->tiles.size()];
|
||||
url = util::replaceTokens(url, [&](const std::string &token) -> std::string {
|
||||
if (token == "z") return std::to_string(id.z);
|
||||
if (token == "x") return std::to_string(id.x);
|
||||
@@ -45,21 +45,28 @@ void TileData::request() {
|
||||
|
||||
// Note: Somehow this feels slower than the change to request_http()
|
||||
std::weak_ptr<TileData> weak_tile = shared_from_this();
|
||||
map.getFileSource()->load(ResourceType::Tile, url, [weak_tile, url](platform::Response *res) {
|
||||
std::shared_ptr<TileData> tile = weak_tile.lock();
|
||||
req = map.getFileSource()->request(ResourceType::Tile, url);
|
||||
req->onload([weak_tile, url](const Response &res) {
|
||||
util::ptr<TileData> tile = weak_tile.lock();
|
||||
if (!tile || tile->state == State::obsolete) {
|
||||
// noop. Tile is obsolete and we're now just waiting for the refcount
|
||||
// to drop to zero for destruction.
|
||||
} else if (res->code == 200) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear the request object.
|
||||
tile->req.reset();
|
||||
|
||||
if (res.code == 200) {
|
||||
tile->state = State::loaded;
|
||||
|
||||
tile->data.swap(res->body);
|
||||
tile->data = res.data;
|
||||
|
||||
// Schedule tile parsing in another thread
|
||||
tile->reparse();
|
||||
} else {
|
||||
#if defined(DEBUG)
|
||||
fprintf(stderr, "[%s] tile loading failed: %d, %s\n", url.c_str(), res->code, res->error_message.c_str());
|
||||
fprintf(stderr, "[%s] tile loading failed: %ld, %s\n", url.c_str(), res.code, res.message.c_str());
|
||||
#endif
|
||||
}
|
||||
});
|
||||
@@ -68,7 +75,7 @@ void TileData::request() {
|
||||
void TileData::cancel() {
|
||||
if (state != State::obsolete) {
|
||||
state = State::obsolete;
|
||||
platform::cancel_request_http(req.lock());
|
||||
req.reset();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,12 +86,12 @@ void TileData::reparse() {
|
||||
|
||||
// We're creating a new work request. The work request deletes itself after it executed
|
||||
// the after work handler
|
||||
new uv::work<std::shared_ptr<TileData>>(
|
||||
map.getLoop(),
|
||||
[](std::shared_ptr<TileData> &tile) {
|
||||
new uv::work<util::ptr<TileData>>(
|
||||
map.getWorker(),
|
||||
[](util::ptr<TileData> &tile) {
|
||||
tile->parse();
|
||||
},
|
||||
[](std::shared_ptr<TileData> &tile) {
|
||||
[](util::ptr<TileData> &tile) {
|
||||
tile->afterParse();
|
||||
tile->map.update();
|
||||
},
|
||||
|
||||
@@ -38,19 +38,26 @@ namespace mbgl {
|
||||
TileParser::~TileParser() = default;
|
||||
|
||||
TileParser::TileParser(const std::string &data, VectorTileData &tile,
|
||||
const std::shared_ptr<const Style> &style,
|
||||
const std::shared_ptr<GlyphAtlas> &glyphAtlas,
|
||||
const std::shared_ptr<GlyphStore> &glyphStore,
|
||||
const std::shared_ptr<SpriteAtlas> &spriteAtlas,
|
||||
const std::shared_ptr<Sprite> &sprite)
|
||||
const util::ptr<const Style> &style_,
|
||||
const util::ptr<GlyphAtlas> &glyphAtlas_,
|
||||
const util::ptr<GlyphStore> &glyphStore_,
|
||||
const util::ptr<SpriteAtlas> &spriteAtlas_,
|
||||
const util::ptr<Sprite> &sprite_)
|
||||
: vector_data(pbf((const uint8_t *)data.data(), data.size())),
|
||||
tile(tile),
|
||||
style(style),
|
||||
glyphAtlas(glyphAtlas),
|
||||
glyphStore(glyphStore),
|
||||
spriteAtlas(spriteAtlas),
|
||||
sprite(sprite),
|
||||
collision(std::make_unique<Collision>(tile.id.z, 4096, tile.source.tile_size, tile.depth)) {
|
||||
style(style_),
|
||||
glyphAtlas(glyphAtlas_),
|
||||
glyphStore(glyphStore_),
|
||||
spriteAtlas(spriteAtlas_),
|
||||
sprite(sprite_),
|
||||
collision(std::make_unique<Collision>(tile.id.z, 4096, tile.source->tile_size, tile.depth)) {
|
||||
assert(&tile != nullptr);
|
||||
assert(style);
|
||||
assert(glyphAtlas);
|
||||
assert(glyphStore);
|
||||
assert(spriteAtlas);
|
||||
assert(sprite);
|
||||
assert(collision);
|
||||
}
|
||||
|
||||
void TileParser::parse() {
|
||||
@@ -59,12 +66,12 @@ void TileParser::parse() {
|
||||
|
||||
bool TileParser::obsolete() const { return tile.state == TileData::State::obsolete; }
|
||||
|
||||
void TileParser::parseStyleLayers(std::shared_ptr<StyleLayerGroup> group) {
|
||||
void TileParser::parseStyleLayers(util::ptr<StyleLayerGroup> group) {
|
||||
if (!group) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const std::shared_ptr<StyleLayer> &layer_desc : group->layers) {
|
||||
for (const util::ptr<StyleLayer> &layer_desc : group->layers) {
|
||||
// Cancel early when parsing.
|
||||
if (obsolete()) {
|
||||
return;
|
||||
@@ -96,14 +103,14 @@ void TileParser::parseStyleLayers(std::shared_ptr<StyleLayerGroup> group) {
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<Bucket> TileParser::createBucket(std::shared_ptr<StyleBucket> bucket_desc) {
|
||||
std::unique_ptr<Bucket> TileParser::createBucket(util::ptr<StyleBucket> bucket_desc) {
|
||||
if (!bucket_desc) {
|
||||
fprintf(stderr, "missing bucket desc\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Skip this bucket if we are to not render this
|
||||
if (tile.id.z < std::floor(bucket_desc->min_zoom) && std::floor(bucket_desc->min_zoom) < tile.source.max_zoom) return nullptr;
|
||||
if (tile.id.z < std::floor(bucket_desc->min_zoom) && std::floor(bucket_desc->min_zoom) < tile.source->max_zoom) return nullptr;
|
||||
if (tile.id.z >= std::ceil(bucket_desc->max_zoom)) return nullptr;
|
||||
|
||||
auto layer_it = vector_data.layers.find(bucket_desc->source_layer);
|
||||
@@ -157,7 +164,7 @@ std::unique_ptr<Bucket> TileParser::createFillBucket(const VectorTileLayer& laye
|
||||
return obsolete() ? nullptr : std::move(bucket);
|
||||
}
|
||||
|
||||
std::unique_ptr<Bucket> TileParser::createRasterBucket(const std::shared_ptr<Texturepool> &texturepool, const StyleBucketRaster &raster) {
|
||||
std::unique_ptr<Bucket> TileParser::createRasterBucket(const util::ptr<Texturepool> &texturepool, const StyleBucketRaster &raster) {
|
||||
std::unique_ptr<RasterBucket> bucket = std::make_unique<RasterBucket>(texturepool, raster);
|
||||
return obsolete() ? nullptr : std::move(bucket);
|
||||
}
|
||||
|
||||
@@ -466,7 +466,7 @@ bool Transform::needsTransition() const {
|
||||
void Transform::updateTransitions(const timestamp now) {
|
||||
uv::writelock lock(mtx);
|
||||
|
||||
transitions.remove_if([now](const std::shared_ptr<util::transition> &transition) {
|
||||
transitions.remove_if([now](const util::ptr<util::transition> &transition) {
|
||||
return transition->update(now) == util::transition::complete;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
VectorTileData::VectorTileData(Tile::ID id, Map &map, const SourceInfo &source)
|
||||
VectorTileData::VectorTileData(Tile::ID id, Map &map, const util::ptr<SourceInfo> &source)
|
||||
: TileData(id, map, source),
|
||||
depth(id.z >= source.max_zoom ? map.getMaxZoom() - id.z : 1) {
|
||||
depth(id.z >= source->max_zoom ? map.getMaxZoom() - id.z : 1) {
|
||||
}
|
||||
|
||||
VectorTileData::~VectorTileData() {
|
||||
std::shared_ptr<GlyphAtlas> glyphAtlas = map.getGlyphAtlas();
|
||||
util::ptr<GlyphAtlas> glyphAtlas = map.getGlyphAtlas();
|
||||
if (glyphAtlas) {
|
||||
glyphAtlas->removeGlyphs(id.to_uint64());
|
||||
}
|
||||
@@ -52,7 +52,7 @@ void VectorTileData::afterParse() {
|
||||
parser.reset();
|
||||
}
|
||||
|
||||
void VectorTileData::render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc, const mat4 &matrix) {
|
||||
void VectorTileData::render(Painter &painter, util::ptr<StyleLayer> layer_desc, const mat4 &matrix) {
|
||||
if (state == State::parsed && layer_desc->bucket) {
|
||||
auto databucket_it = buckets.find(layer_desc->bucket->name);
|
||||
if (databucket_it != buckets.end()) {
|
||||
@@ -62,7 +62,7 @@ void VectorTileData::render(Painter &painter, std::shared_ptr<StyleLayer> layer_
|
||||
}
|
||||
}
|
||||
|
||||
bool VectorTileData::hasData(std::shared_ptr<StyleLayer> layer_desc) const {
|
||||
bool VectorTileData::hasData(util::ptr<StyleLayer> layer_desc) const {
|
||||
if (state == State::parsed && layer_desc->bucket) {
|
||||
auto databucket_it = buckets.find(layer_desc->bucket->name);
|
||||
if (databucket_it != buckets.end()) {
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
#include <mbgl/platform/request.hpp>
|
||||
#include <mbgl/platform/platform.hpp>
|
||||
#include <mbgl/util/std.hpp>
|
||||
#include <mbgl/util/uv_detail.hpp>
|
||||
|
||||
using namespace mbgl::platform;
|
||||
|
||||
Request::Request(const std::string &url,
|
||||
std::function<void(Response *)> callback,
|
||||
std::shared_ptr<uv::loop> loop)
|
||||
: url(url),
|
||||
res(std::make_unique<Response>(callback)),
|
||||
cancelled(false),
|
||||
loop(loop) {
|
||||
if (loop) {
|
||||
// Add a check handle without a callback to keep the default loop running.
|
||||
// We don't have a real handler attached to the default loop right from the
|
||||
// beginning, because we're using asynchronous messaging to perform the actual
|
||||
// request in the request thread. Only after the request is complete, we
|
||||
// create an actual work request that is attached to the default loop.
|
||||
async = new uv_async_t();
|
||||
async->data = new std::unique_ptr<Response>();
|
||||
uv_async_init(**loop, async, &complete);
|
||||
}
|
||||
}
|
||||
|
||||
Request::~Request() {
|
||||
}
|
||||
|
||||
void Request::complete() {
|
||||
if (loop) {
|
||||
// We're scheduling the response callback to be invoked in the event loop.
|
||||
// Since the Request object will be deleted before the callback is invoked,
|
||||
// we move over the Response object to be owned by the async handle.
|
||||
((std::unique_ptr<Response> *)async->data)->swap(res);
|
||||
uv_async_send(async);
|
||||
} else {
|
||||
// We're calling the response callback immediately. We're currently on an
|
||||
// arbitrary thread, but that's okay.
|
||||
res->callback(res.get());
|
||||
}
|
||||
}
|
||||
|
||||
void Request::complete(uv_async_t *async, int status) {
|
||||
Response *res = static_cast<std::unique_ptr<Response> *>(async->data)->get();
|
||||
|
||||
res->callback(res);
|
||||
|
||||
// We need to remove our async handle again to allow the main event loop to exit.
|
||||
uv_close((uv_handle_t *)async, [](uv_handle_t *handle) {
|
||||
delete static_cast<std::unique_ptr<Response> *>(handle->data);
|
||||
delete (uv_async_t *)handle;
|
||||
});
|
||||
}
|
||||
@@ -14,7 +14,7 @@ DebugBucket::DebugBucket(DebugFontBuffer& fontBuffer)
|
||||
: fontBuffer(fontBuffer) {
|
||||
}
|
||||
|
||||
void DebugBucket::render(Painter& painter, std::shared_ptr<StyleLayer> /*layer_desc*/, const Tile::ID& /*id*/, const mat4 &matrix) {
|
||||
void DebugBucket::render(Painter& painter, util::ptr<StyleLayer> /*layer_desc*/, const Tile::ID& /*id*/, const mat4 &matrix) {
|
||||
painter.renderDebugText(*this, matrix);
|
||||
}
|
||||
|
||||
|
||||
@@ -204,7 +204,7 @@ void FillBucket::tessellate() {
|
||||
lineGroup.vertex_length += total_vertex_count;
|
||||
}
|
||||
|
||||
void FillBucket::render(Painter& painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix) {
|
||||
void FillBucket::render(Painter& painter, util::ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix) {
|
||||
painter.renderFill(*this, layer_desc, id, matrix);
|
||||
}
|
||||
|
||||
|
||||
@@ -341,7 +341,7 @@ void LineBucket::addGeometry(const std::vector<Coordinate>& vertices) {
|
||||
}
|
||||
}
|
||||
|
||||
void LineBucket::render(Painter& painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix) {
|
||||
void LineBucket::render(Painter& painter, util::ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix) {
|
||||
painter.renderLine(*this, layer_desc, id, matrix);
|
||||
}
|
||||
|
||||
|
||||
@@ -197,7 +197,7 @@ void Painter::prepareTile(const Tile& tile) {
|
||||
glStencilFunc(GL_EQUAL, ref, mask);
|
||||
}
|
||||
|
||||
void Painter::renderTileLayer(const Tile& tile, std::shared_ptr<StyleLayer> layer_desc, const mat4 &matrix) {
|
||||
void Painter::renderTileLayer(const Tile& tile, util::ptr<StyleLayer> layer_desc, const mat4 &matrix) {
|
||||
assert(tile.data);
|
||||
if (tile.data->hasData(layer_desc) || layer_desc->type == StyleLayerType::Raster) {
|
||||
gl::group group(util::sprintf<32>("render %d/%d/%d\n", tile.id.z, tile.id.y, tile.id.z));
|
||||
@@ -206,7 +206,7 @@ void Painter::renderTileLayer(const Tile& tile, std::shared_ptr<StyleLayer> laye
|
||||
}
|
||||
}
|
||||
|
||||
void Painter::renderBackground(std::shared_ptr<StyleLayer> layer_desc) {
|
||||
void Painter::renderBackground(util::ptr<StyleLayer> layer_desc) {
|
||||
const BackgroundProperties& properties = layer_desc->getProperties<BackgroundProperties>();
|
||||
|
||||
Color color = properties.color;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
void Painter::drawClippingMasks(const std::set<std::shared_ptr<StyleSource>> &sources) {
|
||||
void Painter::drawClippingMasks(const std::set<util::ptr<StyleSource>> &sources) {
|
||||
gl::group group("clipping masks");
|
||||
|
||||
useProgram(plainShader->program);
|
||||
@@ -17,7 +17,7 @@ void Painter::drawClippingMasks(const std::set<std::shared_ptr<StyleSource>> &so
|
||||
|
||||
coveringPlainArray.bind(*plainShader, tileStencilBuffer, BUFFER_OFFSET(0));
|
||||
|
||||
for (const std::shared_ptr<StyleSource> &source : sources) {
|
||||
for (const util::ptr<StyleSource> &source : sources) {
|
||||
source->source->drawClippingMasks(*this);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
void Painter::renderFill(FillBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix) {
|
||||
void Painter::renderFill(FillBucket& bucket, util::ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix) {
|
||||
// Abort early.
|
||||
if (!bucket.hasData()) return;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
void Painter::renderLine(LineBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix) {
|
||||
void Painter::renderLine(LineBucket& bucket, util::ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix) {
|
||||
// Abort early.
|
||||
if (pass == RenderPass::Opaque) return;
|
||||
if (!bucket.hasData()) return;
|
||||
@@ -62,7 +62,7 @@ void Painter::renderLine(LineBucket& bucket, std::shared_ptr<StyleLayer> layer_d
|
||||
bucket.drawPoints(*linejoinShader);
|
||||
}
|
||||
|
||||
const std::shared_ptr<Sprite> &sprite = map.getSprite();
|
||||
const util::ptr<Sprite> &sprite = map.getSprite();
|
||||
if (properties.image.size() && sprite) {
|
||||
SpriteAtlasPosition imagePos = map.getSpriteAtlas()->getPosition(properties.image, *sprite);
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
void Painter::renderRaster(RasterBucket& bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix) {
|
||||
void Painter::renderRaster(RasterBucket& bucket, util::ptr<StyleLayer> layer_desc, const Tile::ID& id, const mat4 &matrix) {
|
||||
if (pass != RenderPass::Translucent) return;
|
||||
|
||||
const RasterProperties &properties = layer_desc->getProperties<RasterProperties>();
|
||||
@@ -34,7 +34,7 @@ void Painter::renderRaster(RasterBucket& bucket, std::shared_ptr<StyleLayer> lay
|
||||
// call updateTiles to get parsed data for sublayers
|
||||
map.updateTiles();
|
||||
|
||||
for (const std::shared_ptr<StyleLayer> &layer : layer_desc->layers->layers) {
|
||||
for (const util::ptr<StyleLayer> &layer : layer_desc->layers->layers) {
|
||||
setOpaque();
|
||||
map.renderLayer(layer, RenderPass::Opaque, &id, &preMatrix);
|
||||
setTranslucent();
|
||||
|
||||
@@ -112,7 +112,7 @@ void Painter::renderSDF(SymbolBucket &bucket,
|
||||
}
|
||||
}
|
||||
|
||||
void Painter::renderSymbol(SymbolBucket &bucket, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID &id, const mat4 &matrix) {
|
||||
void Painter::renderSymbol(SymbolBucket &bucket, util::ptr<StyleLayer> layer_desc, const Tile::ID &id, const mat4 &matrix) {
|
||||
// Abort early.
|
||||
if (pass == RenderPass::Opaque) {
|
||||
return;
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
RasterBucket::RasterBucket(const std::shared_ptr<Texturepool> &texturepool, const StyleBucketRaster& properties)
|
||||
RasterBucket::RasterBucket(const util::ptr<Texturepool> &texturepool, const StyleBucketRaster& properties)
|
||||
: properties(properties),
|
||||
texture(properties),
|
||||
raster(texturepool) {
|
||||
}
|
||||
|
||||
void RasterBucket::render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc, const Tile::ID &id, const mat4 &matrix) {
|
||||
void RasterBucket::render(Painter &painter, util::ptr<StyleLayer> layer_desc, const Tile::ID &id, const mat4 &matrix) {
|
||||
painter.renderRaster(*this, layer_desc, id, matrix);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace mbgl {
|
||||
SymbolBucket::SymbolBucket(const StyleBucketSymbol &properties, Collision &collision)
|
||||
: properties(properties), collision(collision) {}
|
||||
|
||||
void SymbolBucket::render(Painter &painter, std::shared_ptr<StyleLayer> layer_desc,
|
||||
void SymbolBucket::render(Painter &painter, util::ptr<StyleLayer> layer_desc,
|
||||
const Tile::ID &id, const mat4 &matrix) {
|
||||
painter.renderSymbol(*this, layer_desc, id, matrix);
|
||||
}
|
||||
|
||||
86
src/storage/base_request.cpp
Normal file
86
src/storage/base_request.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
#include <mbgl/storage/base_request.hpp>
|
||||
#include <mbgl/storage/response.hpp>
|
||||
#include <mbgl/storage/request.hpp>
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
template <typename T, typename ...Args>
|
||||
void invoke(const std::forward_list<std::unique_ptr<Callback>> &list, Args&& ...args) {
|
||||
for (const std::unique_ptr<Callback> &callback : list) {
|
||||
assert(callback);
|
||||
if (callback->is<T>()) {
|
||||
callback->get<T>()(::std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BaseRequest::BaseRequest(const std::string &path_) : thread_id(uv_thread_self()), path(path_) {
|
||||
}
|
||||
|
||||
// A base request can only be "canceled" by destroying the object. In that case, we'll have to
|
||||
// notify all cancel callbacks.
|
||||
BaseRequest::~BaseRequest() {
|
||||
assert(thread_id == uv_thread_self());
|
||||
notify();
|
||||
}
|
||||
|
||||
void BaseRequest::retryImmediately() {
|
||||
// no-op. override in child class.
|
||||
}
|
||||
|
||||
void BaseRequest::notify() {
|
||||
assert(thread_id == uv_thread_self());
|
||||
|
||||
// The parameter exists solely so that any calls to ->remove()
|
||||
// are not going to cause deallocation of this object while this call is in progress.
|
||||
util::ptr<BaseRequest> retain = self;
|
||||
|
||||
// Swap the lists so that it's safe for callbacks to call ->cancel()
|
||||
// on the request object, which would modify the list.
|
||||
const std::forward_list<std::unique_ptr<Callback>> list = std::move(callbacks);
|
||||
callbacks.clear();
|
||||
|
||||
if (response) {
|
||||
invoke<CompletedCallback>(list, *response);
|
||||
} else {
|
||||
invoke<AbortedCallback>(list);
|
||||
}
|
||||
|
||||
self.reset();
|
||||
}
|
||||
|
||||
Callback *BaseRequest::add(Callback &&callback, const util::ptr<BaseRequest> &request) {
|
||||
assert(thread_id == uv_thread_self());
|
||||
assert(this == request.get());
|
||||
|
||||
if (response) {
|
||||
// We already have a response. Notify right away.
|
||||
if (callback.is<CompletedCallback>()) {
|
||||
callback.get<CompletedCallback>()(*response);
|
||||
} else {
|
||||
// We already know that this request was successful. The AbortedCallback will be discarded
|
||||
// here since it would never be called.
|
||||
}
|
||||
return nullptr;
|
||||
} else {
|
||||
self = request;
|
||||
callbacks.push_front(std::unique_ptr<Callback>(new Callback(std::move(callback))));
|
||||
return callbacks.front().get();
|
||||
}
|
||||
}
|
||||
|
||||
void BaseRequest::remove(Callback *callback) {
|
||||
assert(thread_id == uv_thread_self());
|
||||
callbacks.remove_if([=](const std::unique_ptr<Callback> &cb) {
|
||||
return cb.get() == callback;
|
||||
});
|
||||
if (callbacks.empty()) {
|
||||
self.reset();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
37
src/storage/file_request.cpp
Normal file
37
src/storage/file_request.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
#include <mbgl/storage/file_request.hpp>
|
||||
#include <mbgl/storage/file_request_baton.hpp>
|
||||
#include <mbgl/storage/response.hpp>
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
FileRequest::FileRequest(const std::string &path_, uv_loop_t *loop)
|
||||
: BaseRequest(path_), ptr(new FileRequestBaton(this, path, loop)) {
|
||||
}
|
||||
|
||||
void FileRequest::cancel() {
|
||||
assert(thread_id == uv_thread_self());
|
||||
|
||||
if (ptr) {
|
||||
ptr->cancel();
|
||||
|
||||
// When deleting a FileRequest object with a uv_fs_* call is in progress, we are making sure
|
||||
// that the callback doesn't accidentally reference this object again.
|
||||
ptr->request = nullptr;
|
||||
ptr = nullptr;
|
||||
}
|
||||
|
||||
notify();
|
||||
}
|
||||
|
||||
FileRequest::~FileRequest() {
|
||||
assert(thread_id == uv_thread_self());
|
||||
cancel();
|
||||
}
|
||||
|
||||
}
|
||||
142
src/storage/file_request_baton.cpp
Normal file
142
src/storage/file_request_baton.cpp
Normal file
@@ -0,0 +1,142 @@
|
||||
#include <mbgl/storage/file_request_baton.hpp>
|
||||
#include <mbgl/storage/file_request.hpp>
|
||||
#include <mbgl/storage/response.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
FileRequestBaton::FileRequestBaton(FileRequest *request_, const std::string &path, uv_loop_t *loop)
|
||||
: thread_id(uv_thread_self()), request(request_) {
|
||||
req.data = this;
|
||||
uv_fs_open(loop, &req, path.c_str(), O_RDONLY, S_IRUSR, file_opened);
|
||||
}
|
||||
|
||||
FileRequestBaton::~FileRequestBaton() {
|
||||
}
|
||||
|
||||
void FileRequestBaton::cancel() {
|
||||
canceled = true;
|
||||
|
||||
// uv_cancel fails frequently when the request has already been started.
|
||||
// In that case, we have to let it complete and check the canceled bool
|
||||
// instead.
|
||||
uv_cancel((uv_req_t *)&req);
|
||||
}
|
||||
|
||||
void FileRequestBaton::notify_error(uv_fs_t *req) {
|
||||
FileRequestBaton *ptr = (FileRequestBaton *)req->data;
|
||||
assert(ptr->thread_id == uv_thread_self());
|
||||
|
||||
if (ptr->request && req->result < 0 && !ptr->canceled && req->result != UV_ECANCELED) {
|
||||
ptr->request->response = std::unique_ptr<Response>(new Response);
|
||||
ptr->request->response->code = req->result == UV_ENOENT ? 404 : 500;
|
||||
ptr->request->response->message = uv_strerror(int(req->result));
|
||||
ptr->request->notify();
|
||||
}
|
||||
}
|
||||
|
||||
void FileRequestBaton::file_opened(uv_fs_t *req) {
|
||||
FileRequestBaton *ptr = (FileRequestBaton *)req->data;
|
||||
assert(ptr->thread_id == uv_thread_self());
|
||||
|
||||
if (req->result < 0) {
|
||||
// Opening failed or was canceled. There isn't much left we can do.
|
||||
notify_error(req);
|
||||
cleanup(req);
|
||||
} else {
|
||||
const uv_file fd = uv_file(req->result);
|
||||
|
||||
// We're going to reuse this handle, so we need to cleanup first.
|
||||
uv_fs_req_cleanup(req);
|
||||
|
||||
if (ptr->canceled || !ptr->request) {
|
||||
// Either the FileRequest object has been destructed, or the
|
||||
// request was canceled.
|
||||
uv_fs_close(req->loop, req, fd, file_closed);
|
||||
} else {
|
||||
ptr->fd = fd;
|
||||
uv_fs_fstat(req->loop, req, fd, file_stated);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileRequestBaton::file_stated(uv_fs_t *req) {
|
||||
FileRequestBaton *ptr = (FileRequestBaton *)req->data;
|
||||
assert(ptr->thread_id == uv_thread_self());
|
||||
|
||||
if (req->result < 0 || ptr->canceled || !ptr->request) {
|
||||
// Stating failed or was canceled. We already have an open file handle
|
||||
// though, which we'll have to close.
|
||||
notify_error(req);
|
||||
|
||||
uv_fs_req_cleanup(req);
|
||||
uv_fs_close(req->loop, req, ptr->fd, file_closed);
|
||||
} else {
|
||||
if (static_cast<const uv_stat_t *>(req->ptr)->st_size > std::numeric_limits<int>::max()) {
|
||||
// File is too large for us to open this way because uv_buf's only support unsigned
|
||||
// ints as maximum size.
|
||||
if (ptr->request) {
|
||||
ptr->request->response = std::unique_ptr<Response>(new Response);
|
||||
ptr->request->response->code = UV_EFBIG;
|
||||
ptr->request->response->message = uv_strerror(UV_EFBIG);
|
||||
ptr->request->notify();
|
||||
}
|
||||
|
||||
uv_fs_req_cleanup(req);
|
||||
uv_fs_close(req->loop, req, ptr->fd, file_closed);
|
||||
} else {
|
||||
const unsigned int size =
|
||||
(unsigned int)(static_cast<const uv_stat_t *>(req->ptr)->st_size);
|
||||
ptr->body.resize(size);
|
||||
ptr->buffer = uv_buf_init(const_cast<char *>(ptr->body.data()), size);
|
||||
uv_fs_req_cleanup(req);
|
||||
uv_fs_read(req->loop, req, ptr->fd, &ptr->buffer, 1, 0, file_read);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileRequestBaton::file_read(uv_fs_t *req) {
|
||||
FileRequestBaton *ptr = (FileRequestBaton *)req->data;
|
||||
assert(ptr->thread_id == uv_thread_self());
|
||||
|
||||
if (req->result < 0 || ptr->canceled || !ptr->request) {
|
||||
// Stating failed or was canceled. We already have an open file handle
|
||||
// though, which we'll have to close.
|
||||
notify_error(req);
|
||||
} else {
|
||||
// File was successfully read.
|
||||
if (ptr->request) {
|
||||
ptr->request->response = std::unique_ptr<Response>(new Response);
|
||||
ptr->request->response->code = 200;
|
||||
ptr->request->response->data = std::move(ptr->body);
|
||||
ptr->request->notify();
|
||||
}
|
||||
}
|
||||
|
||||
uv_fs_req_cleanup(req);
|
||||
uv_fs_close(req->loop, req, ptr->fd, file_closed);
|
||||
}
|
||||
|
||||
void FileRequestBaton::file_closed(uv_fs_t *req) {
|
||||
FileRequestBaton *ptr = (FileRequestBaton *)req->data;
|
||||
assert(ptr->thread_id == uv_thread_self());
|
||||
|
||||
if (req->result < 0) {
|
||||
// Closing the file failed. But there isn't anything we can do.
|
||||
}
|
||||
|
||||
cleanup(req);
|
||||
}
|
||||
|
||||
void FileRequestBaton::cleanup(uv_fs_t *req) {
|
||||
FileRequestBaton *ptr = (FileRequestBaton *)req->data;
|
||||
assert(ptr->thread_id == uv_thread_self());
|
||||
|
||||
if (ptr->request) {
|
||||
ptr->request->ptr = nullptr;
|
||||
}
|
||||
|
||||
uv_fs_req_cleanup(req);
|
||||
delete ptr;
|
||||
}
|
||||
|
||||
}
|
||||
105
src/storage/file_source.cpp
Normal file
105
src/storage/file_source.cpp
Normal file
@@ -0,0 +1,105 @@
|
||||
#include <mbgl/storage/file_source.hpp>
|
||||
#include <mbgl/storage/file_request.hpp>
|
||||
#include <mbgl/storage/http_request.hpp>
|
||||
#include <mbgl/storage/sqlite_store.hpp>
|
||||
#include <mbgl/util/uv-messenger.h>
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
FileSource::FileSource(uv_loop_t *loop_, const std::string &path)
|
||||
: thread_id(uv_thread_self()),
|
||||
store(!path.empty() ? util::ptr<SQLiteStore>(new SQLiteStore(loop_, path)) : nullptr),
|
||||
loop(loop_),
|
||||
queue(new uv_messenger_t) {
|
||||
|
||||
uv_messenger_init(loop, queue, [](void *ptr) {
|
||||
std::unique_ptr<std::function<void()>> fn { reinterpret_cast<std::function<void()> *>(ptr) };
|
||||
(*fn)();
|
||||
});
|
||||
uv_unref((uv_handle_t *)&queue->async);
|
||||
}
|
||||
|
||||
FileSource::~FileSource() {
|
||||
assert(thread_id == uv_thread_self());
|
||||
uv_messenger_stop(queue);
|
||||
// NOTE: We don't need to delete the messenger since it will be deleted by the
|
||||
// uv_messenger_stop() function.
|
||||
|
||||
util::ptr<BaseRequest> request;
|
||||
|
||||
// Send a cancel() message to all requests that we are still holding.
|
||||
for (const std::pair<std::string, std::weak_ptr<BaseRequest>> &pair : pending) {
|
||||
if ((request = pair.second.lock())) {
|
||||
request->cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileSource::setBase(const std::string &value) {
|
||||
assert(thread_id == uv_thread_self());
|
||||
base = value;
|
||||
}
|
||||
|
||||
const std::string &FileSource::getBase() const {
|
||||
assert(thread_id == uv_thread_self());
|
||||
return base;
|
||||
}
|
||||
|
||||
std::unique_ptr<Request> FileSource::request(ResourceType type, const std::string &url) {
|
||||
assert(thread_id == uv_thread_self());
|
||||
|
||||
// Make URL absolute.
|
||||
const std::string absoluteURL = [&]() -> std::string {
|
||||
const size_t separator = url.find("://");
|
||||
if (separator == std::string::npos) {
|
||||
// Relative URL.
|
||||
return base + url;
|
||||
} else {
|
||||
return url;
|
||||
}
|
||||
}();
|
||||
|
||||
util::ptr<BaseRequest> request;
|
||||
|
||||
// First, try to find an existing Request object.
|
||||
auto it = pending.find(absoluteURL);
|
||||
if (it != pending.end()) {
|
||||
request = it->second.lock();
|
||||
}
|
||||
|
||||
if (!request) {
|
||||
if (absoluteURL.substr(0, 7) == "file://") {
|
||||
request = std::make_shared<FileRequest>(absoluteURL.substr(7), loop);
|
||||
} else {
|
||||
request = std::make_shared<HTTPRequest>(type, absoluteURL, loop, store);
|
||||
}
|
||||
|
||||
pending.emplace(absoluteURL, request);
|
||||
}
|
||||
|
||||
return std::unique_ptr<Request>(new Request(request));
|
||||
}
|
||||
|
||||
void FileSource::prepare(std::function<void()> fn) {
|
||||
if (thread_id == uv_thread_self()) {
|
||||
fn();
|
||||
} else {
|
||||
uv_messenger_send(queue, new std::function<void()>(std::move(fn)));
|
||||
}
|
||||
}
|
||||
|
||||
void FileSource::retryAllPending() {
|
||||
assert(thread_id == uv_thread_self());
|
||||
|
||||
util::ptr<BaseRequest> request;
|
||||
for (const std::pair<std::string, std::weak_ptr<BaseRequest>> &pair : pending) {
|
||||
if ((request = pair.second.lock())) {
|
||||
request->retryImmediately();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
270
src/storage/http_request.cpp
Normal file
270
src/storage/http_request.cpp
Normal file
@@ -0,0 +1,270 @@
|
||||
#include <mbgl/storage/http_request.hpp>
|
||||
#include <mbgl/storage/sqlite_store.hpp>
|
||||
#include <mbgl/storage/http_request_baton.hpp>
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
|
||||
#pragma clang diagnostic ignored "-Wexit-time-destructors"
|
||||
#pragma clang diagnostic ignored "-Wglobal-constructors"
|
||||
|
||||
struct CacheRequestBaton {
|
||||
HTTPRequest *request = nullptr;
|
||||
std::string path;
|
||||
util::ptr<SQLiteStore> store;
|
||||
};
|
||||
|
||||
HTTPRequest::HTTPRequest(ResourceType type_, const std::string &path, uv_loop_t *loop_, util::ptr<SQLiteStore> store_)
|
||||
: BaseRequest(path), thread_id(uv_thread_self()), loop(loop_), store(store_), type(type_) {
|
||||
if (store) {
|
||||
startCacheRequest();
|
||||
} else {
|
||||
startHTTPRequest(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPRequest::startCacheRequest() {
|
||||
assert(uv_thread_self() == thread_id);
|
||||
|
||||
cache_baton = new CacheRequestBaton;
|
||||
cache_baton->request = this;
|
||||
cache_baton->path = path;
|
||||
cache_baton->store = store;
|
||||
store->get(path, [](std::unique_ptr<Response> &&response, void *ptr) {
|
||||
// Wrap in a unique_ptr, so it'll always get auto-destructed.
|
||||
std::unique_ptr<CacheRequestBaton> baton((CacheRequestBaton *)ptr);
|
||||
if (baton->request) {
|
||||
baton->request->cache_baton = nullptr;
|
||||
baton->request->handleCacheResponse(std::move(response));
|
||||
}
|
||||
}, cache_baton);
|
||||
}
|
||||
|
||||
void HTTPRequest::handleCacheResponse(std::unique_ptr<Response> &&res) {
|
||||
assert(uv_thread_self() == thread_id);
|
||||
|
||||
if (res) {
|
||||
// This entry was stored in the cache. Now determine if we need to revalidate.
|
||||
const int64_t now = std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
if (res->expires > now) {
|
||||
response = std::move(res);
|
||||
notify();
|
||||
// Note: after calling notify(), the request object may cease to exist.
|
||||
// This HTTPRequest is completed.
|
||||
return;
|
||||
} else {
|
||||
// TODO: notify with preliminary results.
|
||||
}
|
||||
}
|
||||
|
||||
startHTTPRequest(std::move(res));
|
||||
}
|
||||
|
||||
void HTTPRequest::startHTTPRequest(std::unique_ptr<Response> &&res) {
|
||||
assert(uv_thread_self() == thread_id);
|
||||
assert(!http_baton);
|
||||
|
||||
http_baton = std::make_shared<HTTPRequestBaton>(path);
|
||||
http_baton->request = this;
|
||||
http_baton->async = new uv_async_t;
|
||||
http_baton->response = std::move(res);
|
||||
http_baton->async->data = new util::ptr<HTTPRequestBaton>(http_baton);
|
||||
|
||||
uv_async_init(loop, http_baton->async, [](uv_async_t *async) {
|
||||
util::ptr<HTTPRequestBaton> &http_baton = *(util::ptr<HTTPRequestBaton> *)async->data;
|
||||
|
||||
if (http_baton->request) {
|
||||
HTTPRequest *request = http_baton->request;
|
||||
request->http_baton.reset();
|
||||
http_baton->request = nullptr;
|
||||
request->handleHTTPResponse(http_baton->type, std::move(http_baton->response));
|
||||
}
|
||||
|
||||
delete (util::ptr<HTTPRequestBaton> *)async->data;
|
||||
uv_close((uv_handle_t *)async, [](uv_handle_t *handle) {
|
||||
uv_async_t *async = (uv_async_t *)handle;
|
||||
delete async;
|
||||
});
|
||||
});
|
||||
attempts++;
|
||||
HTTPRequestBaton::start(http_baton);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void HTTPRequest::handleHTTPResponse(HTTPResponseType responseType, std::unique_ptr<Response> &&res) {
|
||||
assert(uv_thread_self() == thread_id);
|
||||
assert(!http_baton);
|
||||
assert(!response);
|
||||
|
||||
switch (responseType) {
|
||||
// This error was caused by a temporary error and it is likely that it will be resolved
|
||||
// immediately. We are going to try again right away. This is like the TemporaryError,
|
||||
// except that we will not perform exponential back-off.
|
||||
case HTTPResponseType::SingularError:
|
||||
if (attempts >= 4) {
|
||||
// Report as error after 4 attempts.
|
||||
response = std::move(res);
|
||||
notify();
|
||||
} else if (attempts >= 2) {
|
||||
// Switch to the back-off algorithm after the second failure.
|
||||
retryHTTPRequest(std::move(res), (1 << attempts) * 1000);
|
||||
return;
|
||||
} else {
|
||||
startHTTPRequest(std::move(res));
|
||||
}
|
||||
break;
|
||||
|
||||
// This error might be resolved by waiting some time (e.g. server issues).
|
||||
// We are going to do an exponential back-off and will try again in a few seconds.
|
||||
case HTTPResponseType::TemporaryError:
|
||||
if (attempts >= 4) {
|
||||
// Report error back after it failed completely.
|
||||
response = std::move(res);
|
||||
notify();
|
||||
} else {
|
||||
retryHTTPRequest(std::move(res), (1 << attempts) * 1000);
|
||||
}
|
||||
break;
|
||||
|
||||
// This error might be resolved once the network reachability status changes.
|
||||
// We are going to watch the network status for changes and will retry as soon as the
|
||||
// operating system notifies us of a network status change.
|
||||
case HTTPResponseType::ConnectionError:
|
||||
|
||||
if (attempts >= 4) {
|
||||
// Report error back after it failed completely.
|
||||
response = std::move(res);
|
||||
notify();
|
||||
} else {
|
||||
// By default, we will retry every 60 seconds.
|
||||
retryHTTPRequest(std::move(res), 60000);
|
||||
}
|
||||
break;
|
||||
|
||||
// The request was canceled programatically.
|
||||
case HTTPResponseType::Canceled:
|
||||
response.reset();
|
||||
notify();
|
||||
break;
|
||||
|
||||
// This error probably won't be resolved by retrying anytime soon. We are giving up.
|
||||
case HTTPResponseType::PermanentError:
|
||||
response = std::move(res);
|
||||
notify();
|
||||
break;
|
||||
|
||||
// The request returned data successfully. We retrieved and decoded the data successfully.
|
||||
case HTTPResponseType::Successful:
|
||||
if (store) {
|
||||
store->put(path, type, *res);
|
||||
}
|
||||
response = std::move(res);
|
||||
notify();
|
||||
break;
|
||||
|
||||
// The request confirmed that the data wasn't changed. We already have the data.
|
||||
case HTTPResponseType::NotModified:
|
||||
if (store) {
|
||||
store->updateExpiration(path, res->expires);
|
||||
}
|
||||
response = std::move(res);
|
||||
notify();
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(!"Response wasn't set");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
using RetryBaton = std::pair<HTTPRequest *, std::unique_ptr<Response>>;
|
||||
|
||||
void HTTPRequest::retryHTTPRequest(std::unique_ptr<Response> &&res, uint64_t timeout) {
|
||||
assert(uv_thread_self() == thread_id);
|
||||
assert(!backoff_timer);
|
||||
backoff_timer = new uv_timer_t();
|
||||
uv_timer_init(loop, backoff_timer);
|
||||
backoff_timer->data = new RetryBaton(this, std::move(res));
|
||||
uv_timer_start(backoff_timer, [](uv_timer_t *timer) {
|
||||
std::unique_ptr<RetryBaton> pair { static_cast<RetryBaton *>(timer->data) };
|
||||
pair->first->startHTTPRequest(std::move(pair->second));
|
||||
pair->first->backoff_timer = nullptr;
|
||||
uv_timer_stop(timer);
|
||||
uv_close((uv_handle_t *)timer, [](uv_handle_t *handle) { delete (uv_timer_t *)handle; });
|
||||
}, timeout, 0);
|
||||
}
|
||||
|
||||
void HTTPRequest::removeHTTPBaton() {
|
||||
assert(uv_thread_self() == thread_id);
|
||||
if (http_baton) {
|
||||
http_baton->request = nullptr;
|
||||
HTTPRequestBaton::stop(http_baton);
|
||||
http_baton.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPRequest::removeCacheBaton() {
|
||||
assert(uv_thread_self() == thread_id);
|
||||
if (cache_baton) {
|
||||
// Make sre that this object doesn't accidentally get accessed when it is destructed before
|
||||
// the callback returned. They are being run in the same thread, so just setting it to
|
||||
// null is sufficient.
|
||||
// Note: We don't manually delete the CacheRequestBaton since it'll be deleted by the
|
||||
// callback.
|
||||
cache_baton->request = nullptr;
|
||||
cache_baton = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPRequest::removeBackoffTimer() {
|
||||
assert(uv_thread_self() == thread_id);
|
||||
if (backoff_timer) {
|
||||
delete static_cast<RetryBaton *>(backoff_timer->data);
|
||||
uv_timer_stop(backoff_timer);
|
||||
uv_close((uv_handle_t *)backoff_timer, [](uv_handle_t *handle) { delete (uv_timer_t *)handle; });
|
||||
backoff_timer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPRequest::retryImmediately() {
|
||||
assert(uv_thread_self() == thread_id);
|
||||
if (!cache_baton && !http_baton) {
|
||||
if (backoff_timer) {
|
||||
// Retry immediately.
|
||||
uv_timer_stop(backoff_timer);
|
||||
std::unique_ptr<RetryBaton> pair { static_cast<RetryBaton *>(backoff_timer->data) };
|
||||
assert(pair->first == this);
|
||||
startHTTPRequest(std::move(pair->second));
|
||||
uv_close((uv_handle_t *)backoff_timer, [](uv_handle_t *handle) { delete (uv_timer_t *)handle; });
|
||||
backoff_timer = nullptr;
|
||||
} else {
|
||||
assert(!"We should always have a backoff_timer when there are no batons");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPRequest::cancel() {
|
||||
assert(uv_thread_self() == thread_id);
|
||||
removeCacheBaton();
|
||||
removeHTTPBaton();
|
||||
removeBackoffTimer();
|
||||
notify();
|
||||
}
|
||||
|
||||
|
||||
HTTPRequest::~HTTPRequest() {
|
||||
assert(uv_thread_self() == thread_id);
|
||||
cancel();
|
||||
}
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
}
|
||||
12
src/storage/http_request_baton.cpp
Normal file
12
src/storage/http_request_baton.cpp
Normal file
@@ -0,0 +1,12 @@
|
||||
#include <mbgl/storage/http_request_baton.hpp>
|
||||
#include <uv.h>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
HTTPRequestBaton::HTTPRequestBaton(const std::string &path_) : thread_id(uv_thread_self()), path(path_) {
|
||||
}
|
||||
|
||||
HTTPRequestBaton::~HTTPRequestBaton() {
|
||||
}
|
||||
|
||||
}
|
||||
49
src/storage/request.cpp
Normal file
49
src/storage/request.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
#include <mbgl/storage/request.hpp>
|
||||
#include <mbgl/storage/base_request.hpp>
|
||||
|
||||
#include <uv.h>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
Request::Request(const util::ptr<BaseRequest> &base_)
|
||||
: thread_id(uv_thread_self()), base(base_) {
|
||||
}
|
||||
|
||||
Request::~Request() {
|
||||
assert(thread_id == uv_thread_self());
|
||||
}
|
||||
|
||||
void Request::onload(CompletedCallback cb) {
|
||||
assert(thread_id == uv_thread_self());
|
||||
if (base) {
|
||||
Callback *callback = base->add(std::move(cb), base);
|
||||
if (callback) {
|
||||
callbacks.push_front(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Request::oncancel(AbortedCallback cb) {
|
||||
assert(thread_id == uv_thread_self());
|
||||
if (base) {
|
||||
Callback *callback = base->add(std::move(cb), base);
|
||||
if (callback) {
|
||||
callbacks.push_front(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Request::cancel() {
|
||||
assert(thread_id == uv_thread_self());
|
||||
if (base) {
|
||||
for (Callback *callback : callbacks) {
|
||||
base->remove(callback);
|
||||
}
|
||||
base.reset();
|
||||
}
|
||||
callbacks.clear();
|
||||
}
|
||||
|
||||
}
|
||||
22
src/storage/response.cpp
Normal file
22
src/storage/response.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include <mbgl/storage/response.hpp>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
int64_t Response::parseCacheControl(const char *value) {
|
||||
if (value) {
|
||||
uint64_t seconds = 0;
|
||||
// TODO: cache-control may contain other information as well:
|
||||
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9
|
||||
if (std::sscanf(value, "max-age=%llu", &seconds) == 1) {
|
||||
return std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch()).count() +
|
||||
seconds;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user