summaryrefslogtreecommitdiff
path: root/include/mbgl
diff options
context:
space:
mode:
Diffstat (limited to 'include/mbgl')
-rw-r--r--include/mbgl/ios/MGLMapView.h34
-rw-r--r--include/mbgl/map/camera.hpp4
-rw-r--r--include/mbgl/map/map.hpp17
-rw-r--r--include/mbgl/map/mode.hpp34
-rw-r--r--include/mbgl/map/still_image.hpp21
-rw-r--r--include/mbgl/map/view.hpp6
-rw-r--r--include/mbgl/platform/darwin/settings_nsuserdefaults.hpp2
-rw-r--r--include/mbgl/platform/default/glfw_view.hpp1
-rw-r--r--include/mbgl/platform/default/headless_view.hpp2
-rw-r--r--include/mbgl/platform/default/image_reader.hpp42
-rw-r--r--include/mbgl/platform/default/jpeg_reader.hpp74
-rw-r--r--include/mbgl/platform/default/png_reader.hpp67
-rw-r--r--include/mbgl/platform/default/settings_json.hpp5
-rw-r--r--include/mbgl/storage/default_file_source.hpp10
-rw-r--r--include/mbgl/storage/file_source.hpp28
-rw-r--r--include/mbgl/storage/request.hpp52
-rw-r--r--include/mbgl/storage/response.hpp6
-rw-r--r--include/mbgl/util/chrono.hpp31
-rw-r--r--include/mbgl/util/geo.hpp13
-rw-r--r--include/mbgl/util/image.hpp35
-rw-r--r--include/mbgl/util/run_loop.hpp159
-rw-r--r--include/mbgl/util/time.hpp5
-rw-r--r--include/mbgl/util/uv_detail.hpp220
-rw-r--r--include/mbgl/util/work_request.hpp24
-rw-r--r--include/mbgl/util/work_task.hpp21
25 files changed, 599 insertions, 314 deletions
diff --git a/include/mbgl/ios/MGLMapView.h b/include/mbgl/ios/MGLMapView.h
index 779faa4e9b..609d062a98 100644
--- a/include/mbgl/ios/MGLMapView.h
+++ b/include/mbgl/ios/MGLMapView.h
@@ -20,7 +20,7 @@ NS_ASSUME_NONNULL_BEGIN
/** An MGLMapView object provides an embeddable map interface, similar to the one provided by Apple's MapKit. You use this class to display map information and to manipulate the map contents from your application. You can center the map on a given coordinate, specify the size of the area you want to display, and style the features of the map to fit your application's use case.
*
-* Use of MGLMapView requires a Mapbox API access token. Obtain an access token on the [Mapbox account page](https://www.mapbox.com/account/apps/). If you instantiate an MGLMapView from Interface Builder, rendering of the map won't begin until the accessToken property has been set.
+* Use of MGLMapView requires a Mapbox API access token. Obtain an access token on the [Mapbox account page](https://www.mapbox.com/studio/account/tokens/). If you instantiate an MGLMapView from Interface Builder, rendering of the map won't begin until the accessToken property has been set.
*
* @warning Please note that you are responsible for getting permission to use the map data, and for ensuring your use adheres to the relevant terms of use. */
IB_DESIGNABLE
@@ -134,6 +134,14 @@ IB_DESIGNABLE
* @param animated Specify `YES` if you want the map view to animate scrolling, zooming, and rotating to the new location or `NO` if you want the map to display the new location immediately. */
- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(double)zoomLevel direction:(CLLocationDirection)direction animated:(BOOL)animated;
+/** Changes the center coordinate, zoom level, and direction of the map, calling a completion handler at the end of an optional animation.
+* @param centerCoordinate The new center coordinate for the map.
+* @param zoomLevel The new zoom level for the map.
+* @param direction The new direction for the map, measured in degrees relative to true north.
+* @param animated Specify `YES` if you want the map view to animate scrolling, zooming, and rotating to the new location or `NO` if you want the map to display the new location immediately.
+* @param completion The block executed after the animation finishes. */
+- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(double)zoomLevel direction:(CLLocationDirection)direction animated:(BOOL)animated completionHandler:(nullable void (^)(void))completion;
+
/** The coordinate bounds visible in the receiver’s viewport.
*
* Changing the value of this property updates the receiver immediately. If you want to animate the change, call `setVisibleCoordinateBounds:animated:` instead. */
@@ -157,6 +165,16 @@ IB_DESIGNABLE
* @param animated Specify `YES` to animate the change by smoothly scrolling and zooming or `NO` to immediately display the given bounds. */
- (void)setVisibleCoordinates:(CLLocationCoordinate2D *)coordinates count:(NSUInteger)count edgePadding:(UIEdgeInsets)insets animated:(BOOL)animated;
+/** Changes the receiver’s viewport to fit all of the given coordinates and optionally some additional padding on each side.
+* @param coordinates The coordinates that the viewport will show.
+* @param count The number of coordinates. This number must not be greater than the number of elements in `coordinates`.
+* @param insets The minimum padding (in screen points) that will be visible around the given coordinate bounds.
+* @param direction The direction to rotate the map to, measured in degrees relative to true north.
+* @param duration The duration to animate the change in seconds.
+* @param function The timing function to animate the change.
+* @param completion The block executed after the animation finishes. */
+- (void)setVisibleCoordinates:(CLLocationCoordinate2D *)coordinates count:(NSUInteger)count edgePadding:(UIEdgeInsets)insets direction:(CLLocationDirection)direction duration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function completionHandler:(nullable void (^)(void))completion;
+
/** Sets the visible region so that the map displays the specified annotations.
*
* Calling this method updates the value in the visibleCoordinateBounds property and potentially other properties to reflect the new map region.
@@ -193,6 +211,13 @@ IB_DESIGNABLE
* @param function A timing function used for the animation. Set this parameter to `nil` for a transition that matches most system animations. If the duration is `0`, this parameter is ignored. */
- (void)setCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function;
+/** Moves the viewpoint to a different location with respect to the map with an optional transition duration and timing function.
+* @param camera The new viewpoint.
+* @param duration The amount of time, measured in seconds, that the transition animation should take. Specify `0` to jump to the new viewpoint instantaneously.
+* @param function A timing function used for the animation. Set this parameter to `nil` for a transition that matches most system animations. If the duration is `0`, this parameter is ignored.
+* @param completion The block to execute after the animation finishes. */
+- (void)setCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function completionHandler:(nullable void (^)(void))completion;
+
#pragma mark - Converting Map Coordinates
/** @name Converting Map Coordinates */
@@ -234,6 +259,9 @@ IB_DESIGNABLE
* To display the default style, set this property to `nil`. */
@property (nonatomic, null_resettable) NSURL *styleURL;
+/* Discourage programmatic usage of this IB-only property. Interface Builder skips over this declaration because it is unable to parse attributes. See the real declaration in MGLMapView+IBAdditions.h. */
+@property (nonatomic, nullable) IBInspectable NSString *styleURL__ __attribute__((unavailable("styleURL__ is for use within Interface Builder only. Use styleURL in code.")));
+
/** Currently active style classes, represented as an array of string identifiers. */
@property (nonatomic) NS_ARRAY_OF(NSString *) *styleClasses;
@@ -377,8 +405,8 @@ IB_DESIGNABLE
* The default value of this property is `NO`. */
@property (nonatomic, getter=isDebugActive) BOOL debugActive;
-/** Toggle the current value of debugActive. */
-- (void)toggleDebug;
+/** Cycle map debug options. */
+- (void)cycleDebugOptions;
/** Empties the in-memory tile cache. */
- (void)emptyMemoryCache;
diff --git a/include/mbgl/map/camera.hpp b/include/mbgl/map/camera.hpp
index a16c1d4dc2..d787a39e11 100644
--- a/include/mbgl/map/camera.hpp
+++ b/include/mbgl/map/camera.hpp
@@ -7,6 +7,8 @@
#include <mbgl/util/chrono.hpp>
#include <mbgl/util/unitbezier.hpp>
+#include <functional>
+
namespace mbgl {
struct CameraOptions {
@@ -16,6 +18,8 @@ struct CameraOptions {
mapbox::util::optional<double> pitch;
mapbox::util::optional<Duration> duration;
mapbox::util::optional<mbgl::util::UnitBezier> easing;
+ std::function<void(double)> transitionFrameFn;
+ std::function<void()> transitionFinishFn;
};
}
diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp
index f2e605141b..8401976e15 100644
--- a/include/mbgl/map/map.hpp
+++ b/include/mbgl/map/map.hpp
@@ -2,6 +2,7 @@
#define MBGL_MAP_MAP
#include <mbgl/util/chrono.hpp>
+#include <mbgl/util/image.hpp>
#include <mbgl/map/update.hpp>
#include <mbgl/map/mode.hpp>
#include <mbgl/util/geo.hpp>
@@ -21,7 +22,6 @@ class FileSource;
class View;
class MapData;
class MapContext;
-class StillImage;
class SpriteImage;
class Transform;
class PointAnnotation;
@@ -45,7 +45,8 @@ class Map : private util::noncopyable {
public:
explicit Map(View&, FileSource&,
MapMode mapMode = MapMode::Continuous,
- GLContextMode contextMode = GLContextMode::Unique);
+ GLContextMode contextMode = GLContextMode::Unique,
+ ConstrainMode constrainMode = ConstrainMode::HeightOnly);
~Map();
// Pauses the render thread. The render thread will stop running but will not be terminated and will not lose state until resumed.
@@ -57,7 +58,7 @@ public:
// Register a callback that will get called (on the render thread) when all resources have
// been loaded and a complete render occurs.
- using StillImageCallback = std::function<void(std::exception_ptr, std::unique_ptr<const StillImage>)>;
+ using StillImageCallback = std::function<void (std::exception_ptr, PremultipliedImage&&)>;
void renderStill(StillImageCallback callback);
// Triggers a synchronous render.
@@ -167,12 +168,10 @@ public:
void onLowMemory();
// Debug
- void setDebug(bool value);
- void toggleDebug();
- bool getDebug() const;
- void setCollisionDebug(bool value);
- void toggleCollisionDebug();
- bool getCollisionDebug() const;
+ void setDebug(MapDebugOptions);
+ void cycleDebugOptions();
+ MapDebugOptions getDebug() const;
+
bool isFullyLoaded() const;
void dumpDebugLogs() const;
diff --git a/include/mbgl/map/mode.hpp b/include/mbgl/map/mode.hpp
index 6ad9af5c74..c197b28589 100644
--- a/include/mbgl/map/mode.hpp
+++ b/include/mbgl/map/mode.hpp
@@ -5,7 +5,9 @@
namespace mbgl {
-enum class MapMode : uint8_t {
+using EnumType = uint32_t;
+
+enum class MapMode : EnumType {
Continuous, // continually updating map
Still, // a once-off still image
};
@@ -14,11 +16,39 @@ enum class MapMode : uint8_t {
// being shared. In a shared GL context case, we need to make sure that the
// correct GL configurations are in use - they might have changed between render
// calls.
-enum class GLContextMode : uint8_t {
+enum class GLContextMode : EnumType {
Unique,
Shared,
};
+// We can choose to constrain the map both horizontally or vertically, or only
+// vertically e.g. while panning.
+enum class ConstrainMode : EnumType {
+ HeightOnly,
+ WidthAndHeight,
+};
+
+enum class MapDebugOptions : EnumType {
+ NoDebug = 0,
+ TileBorders = 1 << 1,
+ ParseStatus = 1 << 2,
+ Timestamps = 1 << 3,
+ Collision = 1 << 4,
+};
+
+inline MapDebugOptions operator| (const MapDebugOptions& lhs, const MapDebugOptions& rhs) {
+ return MapDebugOptions(static_cast<EnumType>(lhs) | static_cast<EnumType>(rhs));
+}
+
+inline MapDebugOptions& operator|=(MapDebugOptions& lhs, const MapDebugOptions& rhs) {
+ lhs = lhs | rhs;
+ return lhs;
+}
+
+inline bool operator& (const MapDebugOptions& lhs, const MapDebugOptions& rhs) {
+ return static_cast<EnumType>(lhs) & static_cast<EnumType>(rhs);
+}
+
} // namespace mbgl
#endif // MBGL_MAP_MODE
diff --git a/include/mbgl/map/still_image.hpp b/include/mbgl/map/still_image.hpp
deleted file mode 100644
index b9ce0620fa..0000000000
--- a/include/mbgl/map/still_image.hpp
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef MBGL_MAP_STILL_IMAGE
-#define MBGL_MAP_STILL_IMAGE
-
-#include <mbgl/util/noncopyable.hpp>
-
-#include <string>
-#include <cstdint>
-
-namespace mbgl {
-
-class StillImage : util::noncopyable {
-public:
- uint16_t width = 0;
- uint16_t height = 0;
- using Pixel = uint32_t;
- std::unique_ptr<Pixel[]> pixels;
-};
-
-}
-
-#endif
diff --git a/include/mbgl/map/view.hpp b/include/mbgl/map/view.hpp
index fadd035e49..ecdd93377f 100644
--- a/include/mbgl/map/view.hpp
+++ b/include/mbgl/map/view.hpp
@@ -2,14 +2,14 @@
#define MBGL_MAP_VIEW
#include <mbgl/util/chrono.hpp>
-#include <functional>
+#include <mbgl/util/image.hpp>
+#include <functional>
#include <memory>
namespace mbgl {
class Map;
-class StillImage;
enum MapChange : uint8_t {
MapChangeRegionWillChange = 0,
@@ -70,7 +70,7 @@ public:
// Reads the pixel data from the current framebuffer. If your View implementation
// doesn't support reading from the framebuffer, return a null pointer.
- virtual std::unique_ptr<StillImage> readStillImage();
+ virtual PremultipliedImage readStillImage();
// Notifies a watcher of map x/y/scale/rotation changes.
// Must only be called from the same thread that caused the change.
diff --git a/include/mbgl/platform/darwin/settings_nsuserdefaults.hpp b/include/mbgl/platform/darwin/settings_nsuserdefaults.hpp
index 615320ee55..6364f249dd 100644
--- a/include/mbgl/platform/darwin/settings_nsuserdefaults.hpp
+++ b/include/mbgl/platform/darwin/settings_nsuserdefaults.hpp
@@ -22,7 +22,7 @@ public:
MGLUserTrackingMode userTrackingMode = MGLUserTrackingModeNone;
bool showsUserLocation = false;
- bool debug = false;
+ uint32_t debug = 0;
};
}
diff --git a/include/mbgl/platform/default/glfw_view.hpp b/include/mbgl/platform/default/glfw_view.hpp
index 17050d64db..a434b71bb1 100644
--- a/include/mbgl/platform/default/glfw_view.hpp
+++ b/include/mbgl/platform/default/glfw_view.hpp
@@ -65,6 +65,7 @@ private:
const bool benchmark = false;
bool tracking = false;
bool rotating = false;
+ bool pitching = false;
// Frame timer
int frames = 0;
diff --git a/include/mbgl/platform/default/headless_view.hpp b/include/mbgl/platform/default/headless_view.hpp
index 50edc48428..4b25b81bb9 100644
--- a/include/mbgl/platform/default/headless_view.hpp
+++ b/include/mbgl/platform/default/headless_view.hpp
@@ -39,7 +39,7 @@ public:
void invalidate() override;
void beforeRender() override;
void afterRender() override;
- std::unique_ptr<StillImage> readStillImage() override;
+ PremultipliedImage readStillImage() override;
void resizeFramebuffer();
void resize(uint16_t width, uint16_t height);
diff --git a/include/mbgl/platform/default/image_reader.hpp b/include/mbgl/platform/default/image_reader.hpp
deleted file mode 100644
index 52a67a2830..0000000000
--- a/include/mbgl/platform/default/image_reader.hpp
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef MBGL_UTIL_IMAGE_READER_HPP
-#define MBGL_UTIL_IMAGE_READER_HPP
-
-#include <mbgl/util/noncopyable.hpp>
-// stl
-#include <stdexcept>
-#include <string>
-#include <memory>
-
-namespace mbgl { namespace util {
-
-class ImageReaderException : public std::exception
-{
-private:
- std::string message_;
-public:
- ImageReaderException(std::string const& message)
- : message_(message) {}
-
- ~ImageReaderException() throw() {}
-
- virtual const char* what() const throw()
- {
- return message_.c_str();
- }
-};
-
-struct ImageReader : private noncopyable
-{
- virtual unsigned width() const=0;
- virtual unsigned height() const=0;
- virtual bool hasAlpha() const=0;
- virtual bool premultipliedAlpha() const=0;
- virtual void read(unsigned x,unsigned y, unsigned width, unsigned height, char* image)=0;
- virtual ~ImageReader() {}
-};
-
-std::unique_ptr<ImageReader> getImageReader(char const* data, size_t size);
-
-}}
-
-#endif
diff --git a/include/mbgl/platform/default/jpeg_reader.hpp b/include/mbgl/platform/default/jpeg_reader.hpp
deleted file mode 100644
index 3e64ce291b..0000000000
--- a/include/mbgl/platform/default/jpeg_reader.hpp
+++ /dev/null
@@ -1,74 +0,0 @@
-#ifndef MBGL_UTIL_JPEG_READER_HPP
-#define MBGL_UTIL_JPEG_READER_HPP
-
-#include <mbgl/platform/default/image_reader.hpp>
-
-// jpeg
-extern "C"
-{
-#include <jpeglib.h>
-}
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunknown-pragmas"
-#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
-#pragma GCC diagnostic ignored "-Wshadow"
-#include <boost/iostreams/stream.hpp>
-#pragma GCC diagnostic pop
-
-namespace mbgl { namespace util {
-
-template <typename T>
-class JpegReader : public ImageReader
-{
-public:
- using source_type = T;
- using input_stream = boost::iostreams::stream<source_type>;
- const static unsigned BUF_SIZE = 4096;
-private:
- struct jpeg_stream_wrapper
- {
- jpeg_source_mgr manager;
- input_stream * stream;
- JOCTET buffer[BUF_SIZE];
- };
-
- struct jpeg_info_guard
- {
- jpeg_info_guard(jpeg_decompress_struct * cinfo)
- : i_(cinfo) {}
-
- ~jpeg_info_guard()
- {
- jpeg_destroy_decompress(i_);
- }
- jpeg_decompress_struct * i_;
- };
-
-private:
- source_type source_;
- input_stream stream_;
- unsigned width_;
- unsigned height_;
-public:
- JpegReader(char const* data, size_t size);
- ~JpegReader();
- unsigned width() const;
- unsigned height() const;
- inline bool hasAlpha() const { return false; }
- inline bool premultipliedAlpha() const { return true; }
- void read(unsigned x,unsigned y, unsigned w, unsigned h, char *image);
-private:
- void init();
- static void on_error(j_common_ptr cinfo);
- static void on_error_message(j_common_ptr cinfo);
- static void init_source(j_decompress_ptr cinfo);
- static boolean fill_input_buffer(j_decompress_ptr cinfo);
- static void skip(j_decompress_ptr cinfo, long count);
- static void term(j_decompress_ptr cinfo);
- static void attach_stream(j_decompress_ptr cinfo, input_stream* in);
-};
-
-}}
-
-#endif // MBGL_UTIL_JPEG_READER_HPP
diff --git a/include/mbgl/platform/default/png_reader.hpp b/include/mbgl/platform/default/png_reader.hpp
deleted file mode 100644
index 5cbbc51e77..0000000000
--- a/include/mbgl/platform/default/png_reader.hpp
+++ /dev/null
@@ -1,67 +0,0 @@
-#ifndef MBGL_UTIL_PNG_READER_HPP
-#define MBGL_UTIL_PNG_READER_HPP
-
-#include <mbgl/platform/default/image_reader.hpp>
-
-extern "C"
-{
-#include <png.h>
-}
-
-#include <cstring>
-#include <memory>
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunknown-pragmas"
-#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
-#pragma GCC diagnostic ignored "-Wshadow"
-#include <boost/iostreams/stream.hpp>
-#pragma GCC diagnostic pop
-
-namespace mbgl { namespace util {
-
-template <typename T>
-class PngReader : public ImageReader
-{
- using source_type = T;
- using input_stream = boost::iostreams::stream<source_type>;
-
- struct png_struct_guard
- {
- png_struct_guard(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)
- : p_(png_ptr_ptr),
- i_(info_ptr_ptr) {}
-
- ~png_struct_guard()
- {
- png_destroy_read_struct(p_,i_,0);
- }
- png_structpp p_;
- png_infopp i_;
- };
-
-private:
- source_type source_;
- input_stream stream_;
- unsigned width_;
- unsigned height_;
- int bit_depth_;
- int color_type_;
- bool has_alpha_;
-public:
- PngReader(char const* data, std::size_t size);
- ~PngReader();
- unsigned width() const;
- unsigned height() const;
- inline bool hasAlpha() const { return has_alpha_; }
- bool premultipliedAlpha() const { return true; } // png_set_alpha_mode(png, PNG_ALPHA_PREMULTIPLIED, 2.2)
- void read(unsigned x,unsigned y, unsigned width, unsigned height, char * image);
-private:
- void init();
- static void png_read_data(png_structp png_ptr, png_bytep data, png_size_t length);
-};
-
-
-}}
-
-#endif // MBGL_UTIL_PNG_READER_HPP
diff --git a/include/mbgl/platform/default/settings_json.hpp b/include/mbgl/platform/default/settings_json.hpp
index 25c2179ba0..ceec1e7fde 100644
--- a/include/mbgl/platform/default/settings_json.hpp
+++ b/include/mbgl/platform/default/settings_json.hpp
@@ -1,6 +1,8 @@
#ifndef MBGL_JSON_SETTINGS
#define MBGL_JSON_SETTINGS
+#include <mbgl/map/mode.hpp>
+
namespace mbgl {
class Settings_JSON {
@@ -15,8 +17,9 @@ public:
double latitude = 0;
double zoom = 0;
double bearing = 0;
+ double pitch = 0;
- bool debug = false;
+ EnumType debug = 0;
};
}
diff --git a/include/mbgl/storage/default_file_source.hpp b/include/mbgl/storage/default_file_source.hpp
index 8cfae03a96..8d2832b33b 100644
--- a/include/mbgl/storage/default_file_source.hpp
+++ b/include/mbgl/storage/default_file_source.hpp
@@ -18,13 +18,13 @@ public:
void setAccessToken(const std::string& t) { accessToken = t; }
std::string getAccessToken() const { return accessToken; }
- // FileSource API
- Request* request(const Resource&, uv_loop_t*, Callback) override;
- void cancel(Request*) override;
+ std::unique_ptr<FileRequest> request(const Resource&, Callback) override;
-public:
- class Impl;
private:
+ friend class DefaultFileRequest;
+ void cancel(const Resource&, FileRequest*);
+
+ class Impl;
const std::unique_ptr<util::Thread<Impl>> thread;
std::string accessToken;
};
diff --git a/include/mbgl/storage/file_source.hpp b/include/mbgl/storage/file_source.hpp
index 3b19e00788..0167eccc08 100644
--- a/include/mbgl/storage/file_source.hpp
+++ b/include/mbgl/storage/file_source.hpp
@@ -1,33 +1,33 @@
#ifndef MBGL_STORAGE_FILE_SOURCE
#define MBGL_STORAGE_FILE_SOURCE
-#include "response.hpp"
-#include "resource.hpp"
+#include <mbgl/storage/response.hpp>
+#include <mbgl/storage/resource.hpp>
#include <mbgl/util/noncopyable.hpp>
-#include <mbgl/util/util.hpp>
#include <functional>
-
-typedef struct uv_loop_s uv_loop_t;
+#include <memory>
namespace mbgl {
-class Request;
+class FileRequest : private util::noncopyable {
+public:
+ virtual ~FileRequest() = default;
+};
class FileSource : private util::noncopyable {
-protected:
- MBGL_STORE_THREAD(tid)
-
public:
virtual ~FileSource() = default;
- using Callback = std::function<void(const Response &)>;
+ using Callback = std::function<void (Response)>;
- // These can be called from any thread. The callback will be invoked in the loop.
- // You can only cancel a request from the same thread it was created in.
- virtual Request* request(const Resource&, uv_loop_t*, Callback) = 0;
- virtual void cancel(Request*) = 0;
+ // Request a resource. The callback will be called asynchronously, in the same
+ // thread as the request was made. This thread must have an active RunLoop. The
+ // request may be cancelled before completion by releasing the returned FileRequest.
+ // If the request is cancelled before the callback is executed, the callback will
+ // not be executed.
+ virtual std::unique_ptr<FileRequest> request(const Resource&, Callback) = 0;
};
}
diff --git a/include/mbgl/storage/request.hpp b/include/mbgl/storage/request.hpp
deleted file mode 100644
index 1fb15c5a92..0000000000
--- a/include/mbgl/storage/request.hpp
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef MBGL_STORAGE_DEFAULT_REQUEST
-#define MBGL_STORAGE_DEFAULT_REQUEST
-
-#include <mbgl/storage/resource.hpp>
-
-#include <mbgl/util/util.hpp>
-#include <mbgl/util/noncopyable.hpp>
-
-#include <mutex>
-#include <thread>
-#include <functional>
-#include <memory>
-
-typedef struct uv_loop_s uv_loop_t;
-namespace uv { class async; }
-
-namespace mbgl {
-
-class Response;
-
-class Request : private util::noncopyable {
-public:
- using Callback = std::function<void(const Response &)>;
- Request(const Resource &resource, uv_loop_t *loop, Callback callback);
-
-public:
- // May be called from any thread.
- void notify(const std::shared_ptr<const Response> &response);
- void destruct();
-
- // May be called only from the thread the Request was created in.
- void cancel();
-
-private:
- ~Request();
- void notifyCallback();
-
-private:
- std::mutex mtx;
- bool canceled = false;
- bool confirmed = false;
- const std::unique_ptr<uv::async> async;
- Callback callback;
- std::shared_ptr<const Response> response;
-
-public:
- const Resource resource;
-};
-
-}
-
-#endif
diff --git a/include/mbgl/storage/response.hpp b/include/mbgl/storage/response.hpp
index 8ab6170ba2..852110cb2a 100644
--- a/include/mbgl/storage/response.hpp
+++ b/include/mbgl/storage/response.hpp
@@ -1,6 +1,8 @@
#ifndef MBGL_STORAGE_RESPONSE
#define MBGL_STORAGE_RESPONSE
+#include <mbgl/util/chrono.hpp>
+
#include <string>
#include <memory>
@@ -25,8 +27,8 @@ public:
// The actual data of the response. This is guaranteed to never be empty.
std::shared_ptr<const std::string> data;
- int64_t modified = 0;
- int64_t expires = 0;
+ Seconds modified = Seconds::zero();
+ Seconds expires = Seconds::zero();
std::string etag;
};
diff --git a/include/mbgl/util/chrono.hpp b/include/mbgl/util/chrono.hpp
index df8c5e6234..9c99c7bcdf 100644
--- a/include/mbgl/util/chrono.hpp
+++ b/include/mbgl/util/chrono.hpp
@@ -8,9 +8,40 @@ namespace mbgl {
using Clock = std::chrono::steady_clock;
using SystemClock = std::chrono::system_clock;
+using Seconds = std::chrono::seconds;
+using Milliseconds = std::chrono::milliseconds;
+
using TimePoint = Clock::time_point;
using Duration = Clock::duration;
+using SystemTimePoint = SystemClock::time_point;
+using SystemDuration = SystemClock::duration;
+
+template <class _Clock, class _Duration>
+_Duration toDuration(std::chrono::time_point<_Clock, _Duration> time_point) {
+ return time_point.time_since_epoch();
+}
+
+template <class _Duration>
+Seconds asSeconds(_Duration duration) {
+ return std::chrono::duration_cast<Seconds>(duration);
+}
+
+template <class _Clock, class _Duration>
+Seconds toSeconds(std::chrono::time_point<_Clock, _Duration> time_point) {
+ return asSeconds(toDuration<_Clock, _Duration>(time_point));
+}
+
+template <class _Duration>
+Milliseconds asMilliseconds(_Duration duration) {
+ return std::chrono::duration_cast<Milliseconds>(duration);
+}
+
+template <class _Clock, class _Duration>
+Milliseconds toMilliseconds(std::chrono::time_point<_Clock, _Duration> time_point) {
+ return asMilliseconds(toDuration<_Clock, _Duration>(time_point));
+}
+
}
#endif
diff --git a/include/mbgl/util/geo.hpp b/include/mbgl/util/geo.hpp
index 98b5daa6f5..4112b183b2 100644
--- a/include/mbgl/util/geo.hpp
+++ b/include/mbgl/util/geo.hpp
@@ -41,12 +41,19 @@ struct ProjectedMeters {
};
struct LatLngBounds {
- LatLng sw = {90, 180};
- LatLng ne = {-90, -180};
+ LatLng sw = {-90, -180};
+ LatLng ne = {90, 180};
- inline LatLngBounds(const LatLng& sw_ = {90, 180}, const LatLng& ne_ = {-90, -180})
+ inline LatLngBounds() {}
+
+ inline LatLngBounds(const LatLng& sw_, const LatLng& ne_)
: sw(sw_), ne(ne_) {}
+ static inline LatLngBounds getExtendable() {
+ LatLngBounds bounds;
+ return { bounds.ne, bounds.sw };
+ }
+
inline operator bool() const {
return sw && ne;
}
diff --git a/include/mbgl/util/image.hpp b/include/mbgl/util/image.hpp
index f58c2c0989..b8e018f696 100644
--- a/include/mbgl/util/image.hpp
+++ b/include/mbgl/util/image.hpp
@@ -5,30 +5,37 @@
#include <memory>
namespace mbgl {
-namespace util {
-
-std::string compress_png(int width, int height, const void *rgba);
+enum ImageAlphaMode {
+ Unassociated,
+ Premultiplied
+};
+template <ImageAlphaMode Mode>
class Image {
public:
- explicit Image(const std::string &img);
+ Image() {}
- inline const char *getData() const { return img.get(); }
- inline uint32_t getWidth() const { return width; }
- inline uint32_t getHeight() const { return height; }
- inline operator bool() const { return img && width && height; }
+ Image(size_t w, size_t h)
+ : width(w),
+ height(h),
+ data(std::make_unique<uint8_t[]>(size())) {}
-private:
- // loaded image dimensions
- uint32_t width = 0, height = 0;
+ size_t stride() const { return width * 4; }
+ size_t size() const { return width * height * 4; }
- // the raw image data
- std::unique_ptr<char[]> img;
+ size_t width = 0;
+ size_t height = 0;
+ std::unique_ptr<uint8_t[]> data;
};
+using UnassociatedImage = Image<ImageAlphaMode::Unassociated>;
+using PremultipliedImage = Image<ImageAlphaMode::Premultiplied>;
+
+// TODO: don't use std::string for binary data.
+PremultipliedImage decodeImage(const std::string&);
+std::string encodePNG(const PremultipliedImage&);
-}
}
#endif
diff --git a/include/mbgl/util/run_loop.hpp b/include/mbgl/util/run_loop.hpp
new file mode 100644
index 0000000000..6113ac2215
--- /dev/null
+++ b/include/mbgl/util/run_loop.hpp
@@ -0,0 +1,159 @@
+#ifndef MBGL_UTIL_RUN_LOOP
+#define MBGL_UTIL_RUN_LOOP
+
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/work_task.hpp>
+#include <mbgl/util/work_request.hpp>
+#include <mbgl/util/uv_detail.hpp>
+
+#include <functional>
+#include <utility>
+#include <queue>
+#include <mutex>
+#include <atomic>
+
+namespace mbgl {
+namespace util {
+
+class RunLoop : private util::noncopyable {
+public:
+ RunLoop(uv_loop_t*);
+ ~RunLoop();
+
+ static RunLoop* Get() {
+ return current.get();
+ }
+
+ static uv_loop_t* getLoop() {
+ return current.get()->get();
+ }
+
+ void stop();
+
+ // Invoke fn(args...) on this RunLoop.
+ template <class Fn, class... Args>
+ void invoke(Fn&& fn, Args&&... args) {
+ auto tuple = std::make_tuple(std::move(args)...);
+ auto task = std::make_shared<Invoker<Fn, decltype(tuple)>>(
+ std::move(fn),
+ std::move(tuple));
+
+ withMutex([&] { queue.push(task); });
+ async.send();
+ }
+
+ // Post the cancellable work fn(args...) to this RunLoop.
+ template <class Fn, class... Args>
+ std::unique_ptr<WorkRequest>
+ invokeCancellable(Fn&& fn, Args&&... args) {
+ auto flag = std::make_shared<std::atomic<bool>>();
+ *flag = false;
+
+ auto tuple = std::make_tuple(std::move(args)...);
+ auto task = std::make_shared<Invoker<Fn, decltype(tuple)>>(
+ std::move(fn),
+ std::move(tuple),
+ flag);
+
+ withMutex([&] { queue.push(task); });
+ async.send();
+
+ return std::make_unique<WorkRequest>(task);
+ }
+
+ // Invoke fn(args...) on this RunLoop, then invoke callback(results...) on the current RunLoop.
+ template <class Fn, class Cb, class... Args>
+ std::unique_ptr<WorkRequest>
+ invokeWithCallback(Fn&& fn, Cb&& callback, Args&&... args) {
+ auto flag = std::make_shared<std::atomic<bool>>();
+ *flag = false;
+
+ // Create a lambda L1 that invokes another lambda L2 on the current RunLoop R, that calls
+ // the callback C. Both lambdas check the flag before proceeding. L1 needs to check the flag
+ // because if the request was cancelled, then R might have been destroyed. L2 needs to check
+ // the flag because the request may have been cancelled after L2 was invoked but before it
+ // began executing.
+ auto after = [flag, current = RunLoop::current.get(), callback1 = std::move(callback)] (auto&&... results1) {
+ if (!*flag) {
+ current->invoke([flag, callback2 = std::move(callback1)] (auto&&... results2) {
+ if (!*flag) {
+ callback2(std::move(results2)...);
+ }
+ }, std::move(results1)...);
+ }
+ };
+
+ auto tuple = std::make_tuple(std::move(args)..., after);
+ auto task = std::make_shared<Invoker<Fn, decltype(tuple)>>(
+ std::move(fn),
+ std::move(tuple),
+ flag);
+
+ withMutex([&] { queue.push(task); });
+ async.send();
+
+ return std::make_unique<WorkRequest>(task);
+ }
+
+ uv_loop_t* get() { return async.get()->loop; }
+
+private:
+ template <class F, class P>
+ class Invoker : public WorkTask {
+ public:
+ Invoker(F&& f, P&& p, std::shared_ptr<std::atomic<bool>> canceled_ = nullptr)
+ : canceled(canceled_),
+ func(std::move(f)),
+ params(std::move(p)) {
+ }
+
+ void operator()() override {
+ // Lock the mutex while processing so that cancel() will block.
+ std::lock_guard<std::recursive_mutex> lock(mutex);
+ if (!canceled || !*canceled) {
+ invoke(std::make_index_sequence<std::tuple_size<P>::value>{});
+ }
+ }
+
+ // If the task has not yet begun, this will cancel it.
+ // If the task is in progress, this will block until it completed. (Currently
+ // necessary because of shared state, but should be removed.) It will also
+ // cancel the after callback.
+ // If the task has completed, but the after callback has not executed, this
+ // will cancel the after callback.
+ // If the task has completed and the after callback has executed, this will
+ // do nothing.
+ void cancel() override {
+ std::lock_guard<std::recursive_mutex> lock(mutex);
+ *canceled = true;
+ }
+
+ private:
+ template <std::size_t... I>
+ void invoke(std::index_sequence<I...>) {
+ func(std::get<I>(std::forward<P>(params))...);
+ }
+
+ std::recursive_mutex mutex;
+ std::shared_ptr<std::atomic<bool>> canceled;
+
+ F func;
+ P params;
+ };
+
+ using Queue = std::queue<std::shared_ptr<WorkTask>>;
+
+ void withMutex(std::function<void()>&&);
+ void process();
+
+ Queue queue;
+ std::mutex mutex;
+ uv::async async;
+
+ static uv::tls<RunLoop> current;
+};
+
+}
+}
+
+#endif
diff --git a/include/mbgl/util/time.hpp b/include/mbgl/util/time.hpp
index c2e931b10b..ec8dafa45e 100644
--- a/include/mbgl/util/time.hpp
+++ b/include/mbgl/util/time.hpp
@@ -1,6 +1,8 @@
#ifndef MBGL_UTIL_TIME
#define MBGL_UTIL_TIME
+#include <mbgl/util/chrono.hpp>
+
#include <string>
#include <cstdint>
#include <ctime>
@@ -12,6 +14,9 @@ namespace util {
// Returns the RFC1123 formatted date. E.g. "Tue, 04 Nov 2014 02:13:24 GMT"
std::string rfc1123(std::time_t time);
+// YYYY-mm-dd HH:MM:SS e.g. "2015-11-26 16:11:23"
+std::string iso8601(std::time_t time);
+
}
}
diff --git a/include/mbgl/util/uv_detail.hpp b/include/mbgl/util/uv_detail.hpp
new file mode 100644
index 0000000000..86a64d33f2
--- /dev/null
+++ b/include/mbgl/util/uv_detail.hpp
@@ -0,0 +1,220 @@
+#ifndef MBGL_UTIL_UV_DETAIL
+#define MBGL_UTIL_UV_DETAIL
+
+#include <mbgl/util/uv.hpp>
+#include <mbgl/util/noncopyable.hpp>
+
+#include <uv.h>
+
+// XXX: uv.h will include <bits/termios.h> that will
+// polute the namespace by defining "B0" which
+// will conflict with boost macros.
+#ifdef B0
+#undef B0
+#endif
+
+#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
+#define UV_ASYNC_PARAMS(handle) uv_async_t *handle, int
+#define UV_TIMER_PARAMS(timer) uv_timer_t *timer, int
+#else
+#define UV_ASYNC_PARAMS(handle) uv_async_t *handle
+#define UV_TIMER_PARAMS(timer) uv_timer_t *timer
+#endif
+
+#include <functional>
+#include <cassert>
+#include <memory>
+#include <string>
+
+#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
+
+// Add thread local storage to libuv API:
+// https://github.com/joyent/libuv/commit/5d2434bf71e47802841bad218d521fa254d1ca2d
+
+typedef pthread_key_t uv_key_t;
+
+UV_EXTERN int uv_key_create(uv_key_t* key);
+UV_EXTERN void uv_key_delete(uv_key_t* key);
+UV_EXTERN void* uv_key_get(uv_key_t* key);
+UV_EXTERN void uv_key_set(uv_key_t* key, void* value);
+
+#endif
+
+
+namespace uv {
+
+class loop : public mbgl::util::noncopyable {
+public:
+ inline loop() {
+#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
+ l = uv_loop_new();
+ if (l == nullptr) {
+#else
+ l = new uv_loop_t;
+ if (uv_loop_init(l) != 0) {
+#endif
+ throw std::runtime_error("failed to initialize loop");
+ }
+ }
+
+ inline ~loop() {
+#if UV_VERSION_MAJOR == 0 && UV_VERSION_MINOR <= 10
+ uv_loop_delete(l);
+#else
+ uv_loop_close(l);
+ delete l;
+#endif
+ }
+
+ inline void run() {
+ uv_run(l, UV_RUN_DEFAULT);
+ }
+
+ inline uv_loop_t* operator*() {
+ return l;
+ }
+
+ inline uv_loop_t* get() {
+ return l;
+ }
+
+private:
+ uv_loop_t *l = nullptr;
+};
+
+template <class T>
+class handle : public mbgl::util::noncopyable {
+public:
+ inline handle() : t(reinterpret_cast<uv_handle_t*>(new T)) {
+ t->data = this;
+ }
+
+ inline ~handle() {
+ uv_close(t.release(), [](uv_handle_t* h) {
+ delete reinterpret_cast<T*>(h);
+ });
+ }
+
+ inline void ref() {
+ uv_ref(t.get());
+ }
+
+ inline void unref() {
+ uv_unref(t.get());
+ }
+
+ inline T* get() {
+ return reinterpret_cast<T*>(t.get());
+ }
+
+private:
+ std::unique_ptr<uv_handle_t> t;
+};
+
+class async : public handle<uv_async_t> {
+public:
+ inline async(uv_loop_t* loop, std::function<void ()> fn_)
+ : fn(fn_) {
+ if (uv_async_init(loop, get(), async_cb) != 0) {
+ throw std::runtime_error("failed to initialize async");
+ }
+ }
+
+ inline void send() {
+ if (uv_async_send(get()) != 0) {
+ throw std::runtime_error("failed to async send");
+ }
+ }
+
+private:
+ static void async_cb(UV_ASYNC_PARAMS(handle)) {
+ reinterpret_cast<async*>(handle->data)->fn();
+ }
+
+ std::function<void ()> fn;
+};
+
+class timer : public handle<uv_timer_t> {
+public:
+ inline timer(uv_loop_t* loop) {
+ if (uv_timer_init(loop, get()) != 0) {
+ throw std::runtime_error("failed to initialize timer");
+ }
+ }
+
+ inline void start(uint64_t timeout, uint64_t repeat, std::function<void ()> fn_) {
+ fn = fn_;
+ if (uv_timer_start(get(), timer_cb, timeout, repeat) != 0) {
+ throw std::runtime_error("failed to start timer");
+ }
+ }
+
+ inline void stop() {
+ fn = nullptr;
+ if (uv_timer_stop(get()) != 0) {
+ throw std::runtime_error("failed to stop timer");
+ }
+ }
+
+private:
+ static void timer_cb(UV_TIMER_PARAMS(t)) {
+ reinterpret_cast<timer*>(t->data)->fn();
+ }
+
+ std::function<void ()> fn;
+};
+
+class mutex : public mbgl::util::noncopyable {
+public:
+ inline mutex() {
+ if (uv_mutex_init(&mtx) != 0) {
+ throw std::runtime_error("failed to initialize mutex lock");
+ }
+ }
+ inline ~mutex() { uv_mutex_destroy(&mtx); }
+ inline void lock() { uv_mutex_lock(&mtx); }
+ inline void unlock() { uv_mutex_unlock(&mtx); }
+private:
+ uv_mutex_t mtx;
+};
+
+class rwlock : public mbgl::util::noncopyable {
+public:
+ inline rwlock() {
+ if (uv_rwlock_init(&mtx) != 0) {
+ throw std::runtime_error("failed to initialize read-write lock");
+ }
+ }
+ inline ~rwlock() { uv_rwlock_destroy(&mtx); }
+ inline void rdlock() { uv_rwlock_rdlock(&mtx); }
+ inline void wrlock() { uv_rwlock_wrlock(&mtx); }
+ inline void rdunlock() { uv_rwlock_rdunlock(&mtx); }
+ inline void wrunlock() { uv_rwlock_wrunlock(&mtx); }
+
+private:
+ uv_rwlock_t mtx;
+};
+
+template <class T>
+class tls : public mbgl::util::noncopyable {
+public:
+ inline tls(T* val) {
+ tls();
+ set(val);
+ }
+ inline tls() {
+ if (uv_key_create(&key) != 0) {
+ throw std::runtime_error("failed to initialize thread local storage key");
+ }
+ }
+ inline ~tls() { uv_key_delete(&key); }
+ inline T* get() { return reinterpret_cast<T*>(uv_key_get(&key)); }
+ inline void set(T* val) { uv_key_set(&key, val); }
+
+private:
+ uv_key_t key;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/util/work_request.hpp b/include/mbgl/util/work_request.hpp
new file mode 100644
index 0000000000..f2aa2bbacc
--- /dev/null
+++ b/include/mbgl/util/work_request.hpp
@@ -0,0 +1,24 @@
+#ifndef MBGL_UTIL_WORK_REQUEST
+#define MBGL_UTIL_WORK_REQUEST
+
+#include <mbgl/util/noncopyable.hpp>
+
+#include <memory>
+
+namespace mbgl {
+
+class WorkTask;
+
+class WorkRequest : public util::noncopyable {
+public:
+ using Task = std::shared_ptr<WorkTask>;
+ WorkRequest(Task);
+ ~WorkRequest();
+
+private:
+ std::shared_ptr<WorkTask> task;
+};
+
+}
+
+#endif
diff --git a/include/mbgl/util/work_task.hpp b/include/mbgl/util/work_task.hpp
new file mode 100644
index 0000000000..2224b211c4
--- /dev/null
+++ b/include/mbgl/util/work_task.hpp
@@ -0,0 +1,21 @@
+#ifndef MBGL_UTIL_WORK_TASK
+#define MBGL_UTIL_WORK_TASK
+
+#include <mbgl/util/noncopyable.hpp>
+
+namespace mbgl {
+
+// A movable type-erasing function wrapper. This allows to store arbitrary invokable
+// things (like std::function<>, or the result of a movable-only std::bind()) in the queue.
+// Source: http://stackoverflow.com/a/29642072/331379
+class WorkTask : private util::noncopyable {
+public:
+ virtual ~WorkTask() = default;
+
+ virtual void operator()() = 0;
+ virtual void cancel() = 0;
+};
+
+}
+
+#endif