diff options
author | Konstantin Käfer <mail@kkaefer.com> | 2018-12-13 18:45:29 +0100 |
---|---|---|
committer | Konstantin Käfer <mail@kkaefer.com> | 2018-12-14 11:03:03 +0100 |
commit | 1d8235f5b899a2cd8414522b2d72b96fab91577b (patch) | |
tree | 2ab56dce064de872525db7f24ba150a9065c4757 /platform/default/include/mbgl | |
parent | c2a4a8822ce9577c972975da61034a30fb0fe3e9 (diff) | |
download | qtlocation-mapboxgl-1d8235f5b899a2cd8414522b2d72b96fab91577b.tar.gz |
[build] rework platform/default directory and add -files.txt for vendored libs
Diffstat (limited to 'platform/default/include/mbgl')
17 files changed, 939 insertions, 0 deletions
diff --git a/platform/default/include/mbgl/gl/headless_backend.hpp b/platform/default/include/mbgl/gl/headless_backend.hpp new file mode 100644 index 0000000000..7757037533 --- /dev/null +++ b/platform/default/include/mbgl/gl/headless_backend.hpp @@ -0,0 +1,50 @@ +#pragma once + +#include <mbgl/renderer/renderer_backend.hpp> + +#include <memory> +#include <functional> + +namespace mbgl { + +class HeadlessBackend : public RendererBackend { +public: + HeadlessBackend(Size = { 256, 256 }); + ~HeadlessBackend() override; + + void bind() override; + Size getFramebufferSize() const override; + void updateAssumedState() override; + + void setSize(Size); + PremultipliedImage readStillImage(); + + class Impl { + public: + virtual ~Impl() = default; + virtual gl::ProcAddress getExtensionFunctionPointer(const char*) = 0; + virtual void activateContext() = 0; + virtual void deactivateContext() {} + }; + +private: + // Implementation specific functions + gl::ProcAddress getExtensionFunctionPointer(const char*) override; + + void activate() override; + void deactivate() override; + + void createImpl(); + +private: + std::unique_ptr<Impl> impl; + + Size size; + float pixelRatio; + bool active = false; + + class View; + std::unique_ptr<View> view; +}; + +} // namespace mbgl diff --git a/platform/default/include/mbgl/gl/headless_frontend.hpp b/platform/default/include/mbgl/gl/headless_frontend.hpp new file mode 100644 index 0000000000..18f0cfa537 --- /dev/null +++ b/platform/default/include/mbgl/gl/headless_frontend.hpp @@ -0,0 +1,61 @@ +#pragma once + +#include <mbgl/map/camera.hpp> +#include <mbgl/renderer/mode.hpp> +#include <mbgl/renderer/renderer_frontend.hpp> +#include <mbgl/gl/headless_backend.hpp> +#include <mbgl/util/async_task.hpp> +#include <mbgl/util/optional.hpp> + +#include <memory> + +namespace mbgl { + +class FileSource; +class Scheduler; +class Renderer; +class RendererBackend; +class Map; +class TransformState; + +class HeadlessFrontend : public RendererFrontend { +public: + HeadlessFrontend(float pixelRatio_, FileSource&, Scheduler&, const optional<std::string> programCacheDir = {}, GLContextMode mode = GLContextMode::Unique, const optional<std::string> localFontFamily = {}); + HeadlessFrontend(Size, float pixelRatio_, FileSource&, Scheduler&, const optional<std::string> programCacheDir = {}, GLContextMode mode = GLContextMode::Unique, const optional<std::string> localFontFamily = {}); + ~HeadlessFrontend() override; + + void reset() override; + void update(std::shared_ptr<UpdateParameters>) override; + void setObserver(RendererObserver&) override; + + Size getSize() const; + void setSize(Size); + + Renderer* getRenderer(); + RendererBackend* getBackend(); + CameraOptions getCameraOptions(); + + bool hasImage(const std::string&); + bool hasLayer(const std::string&); + bool hasSource(const std::string&); + + ScreenCoordinate pixelForLatLng(const LatLng&); + LatLng latLngForPixel(const ScreenCoordinate&); + + PremultipliedImage readStillImage(); + PremultipliedImage render(Map&); + + optional<TransformState> getTransformState() const; + +private: + Size size; + float pixelRatio; + + HeadlessBackend backend; + util::AsyncTask asyncInvalidate; + + std::unique_ptr<Renderer> renderer; + std::shared_ptr<UpdateParameters> updateParameters; +}; + +} // namespace mbgl diff --git a/platform/default/include/mbgl/map/map_snapshotter.hpp b/platform/default/include/mbgl/map/map_snapshotter.hpp new file mode 100644 index 0000000000..2deb2b3cda --- /dev/null +++ b/platform/default/include/mbgl/map/map_snapshotter.hpp @@ -0,0 +1,66 @@ +#pragma once + +#include <mbgl/util/image.hpp> +#include <mbgl/util/thread.hpp> +#include <mbgl/util/optional.hpp> +#include <mbgl/util/geo.hpp> + +#include <exception> +#include <memory> +#include <string> +#include <vector> +#include <functional> + +namespace mbgl { + +template<class> class ActorRef; +struct CameraOptions; +class FileSource; +class Size; +class LatLngBounds; + +namespace style { +class Style; +} // namespace style + +class MapSnapshotter { +public: + MapSnapshotter(FileSource* fileSource, + std::shared_ptr<Scheduler> scheduler, + const std::pair<bool, std::string> style, + const Size&, + const float pixelRatio, + const optional<CameraOptions> cameraOptions, + const optional<LatLngBounds> region, + const optional<std::string> cacheDir = {}, + const optional<std::string> localFontFamily = {}); + + ~MapSnapshotter(); + + void setStyleURL(const std::string& styleURL); + std::string getStyleURL() const; + + void setStyleJSON(const std::string& styleJSON); + std::string getStyleJSON() const; + + void setSize(const Size&); + Size getSize() const; + + void setCameraOptions(const CameraOptions&); + CameraOptions getCameraOptions() const; + + void setRegion(const LatLngBounds&); + LatLngBounds getRegion() const; + + using PointForFn = std::function<ScreenCoordinate (const LatLng&)>; + using LatLngForFn = std::function<LatLng (const ScreenCoordinate&)>; + using Attributions = std::vector<std::string>; + using Callback = std::function<void (std::exception_ptr, PremultipliedImage, Attributions, PointForFn, LatLngForFn)>; + void snapshot(ActorRef<Callback>); + +private: + class Impl; + std::unique_ptr<util::Thread<Impl>> impl; +}; + +} // namespace mbgl diff --git a/platform/default/include/mbgl/storage/file_source_request.hpp b/platform/default/include/mbgl/storage/file_source_request.hpp new file mode 100644 index 0000000000..6bd0d44df6 --- /dev/null +++ b/platform/default/include/mbgl/storage/file_source_request.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include <mbgl/actor/actor_ref.hpp> +#include <mbgl/storage/file_source.hpp> +#include <mbgl/util/async_request.hpp> + +#include <memory> +#include <functional> + +namespace mbgl { + +class Mailbox; + +class FileSourceRequest : public AsyncRequest { +public: + FileSourceRequest(FileSource::Callback&& callback); + ~FileSourceRequest() final; + + void onCancel(std::function<void()>&& callback); + void setResponse(const Response& res); + + ActorRef<FileSourceRequest> actor(); + +private: + FileSource::Callback responseCallback = nullptr; + std::function<void()> cancelCallback = nullptr; + + std::shared_ptr<Mailbox> mailbox; +}; + +} // namespace mbgl diff --git a/platform/default/include/mbgl/storage/merge_sideloaded.hpp b/platform/default/include/mbgl/storage/merge_sideloaded.hpp new file mode 100644 index 0000000000..494018c966 --- /dev/null +++ b/platform/default/include/mbgl/storage/merge_sideloaded.hpp @@ -0,0 +1,53 @@ +#pragma once + +// THIS IS A GENERATED FILE; EDIT merge_sideloaded.sql INSTEAD +// To regenerate, run `node platform/default/mbgl/storage/merge_sideloaded.js` + +namespace mbgl { + +static constexpr const char* mergeSideloadedDatabaseSQL = +"INSERT INTO regions\n" +" SELECT DISTINCT NULL, sr.definition, sr.description\n" +" FROM side.regions sr \n" +" LEFT JOIN regions r ON sr.definition = r.definition AND sr.description IS r.description\n" +" WHERE r.definition IS NULL;\n" +"CREATE TEMPORARY TABLE region_mapping AS\n" +" SELECT sr.id AS side_region_id,\n" +" r.id AS main_region_id\n" +" FROM side.regions sr\n" +" JOIN regions r ON sr.definition = r.definition AND sr.description IS r.description;\n" +"REPLACE INTO tiles\n" +" SELECT t.id,\n" +" st.url_template, st.pixel_ratio, st.z, st.x, st.y,\n" +" st.expires, st.modified, st.etag, st.data, st.compressed, st.accessed, st.must_revalidate\n" +" FROM (SELECT DISTINCT sti.* FROM side.region_tiles srt JOIN side.tiles sti ON srt.tile_id = sti.id)\n" +" AS st\n" +" LEFT JOIN tiles t ON st.url_template = t.url_template AND st.pixel_ratio = t.pixel_ratio AND st.z = t.z AND st.x = t.x AND st.y = t.y\n" +" WHERE t.id IS NULL\n" +" OR st.modified > t.modified;\n" +"INSERT OR IGNORE INTO region_tiles\n" +" SELECT rm.main_region_id, sti.id\n" +" FROM side.region_tiles srt\n" +" JOIN region_mapping rm ON srt.region_id = rm.side_region_id\n" +" JOIN (SELECT t.id, st.id AS side_tile_id FROM side.tiles st\n" +" JOIN tiles t ON st.url_template = t.url_template AND st.pixel_ratio = t.pixel_ratio AND st.z = t.z AND st.x = t.x AND st.y = t.y\n" +" ) AS sti ON srt.tile_id = sti.side_tile_id;\n" +"REPLACE INTO resources\n" +" SELECT r.id, \n" +" sr.url, sr.kind, sr.expires, sr.modified, sr.etag,\n" +" sr.data, sr.compressed, sr.accessed, sr.must_revalidate\n" +" FROM side.region_resources srr JOIN side.resources sr ON srr.resource_id = sr.id\n" +" LEFT JOIN resources r ON sr.url = r.url\n" +" WHERE r.id IS NULL\n" +" OR sr.modified > r.modified;\n" +"INSERT OR IGNORE INTO region_resources\n" +" SELECT rm.main_region_id, sri.id\n" +" FROM side.region_resources srr\n" +" JOIN region_mapping rm ON srr.region_id = rm.side_region_id\n" +" JOIN (SELECT r.id, sr.id AS side_resource_id FROM side.resources sr\n" +" JOIN resources r ON sr.url = r.url) AS sri ON srr.resource_id = sri.side_resource_id;\n" +" \n" +"DROP TABLE region_mapping;\n" +; + +} // namespace mbgl diff --git a/platform/default/include/mbgl/storage/merge_sideloaded.js b/platform/default/include/mbgl/storage/merge_sideloaded.js new file mode 100644 index 0000000000..98d52eb8b3 --- /dev/null +++ b/platform/default/include/mbgl/storage/merge_sideloaded.js @@ -0,0 +1,21 @@ +var fs = require('fs'); +fs.writeFileSync('platform/default/mbgl/storage/merge_sideloaded.hpp', `#pragma once + +// THIS IS A GENERATED FILE; EDIT merge_sideloaded.sql INSTEAD +// To regenerate, run \`node platform/default/mbgl/storage/merge_sideloaded.js\` + +namespace mbgl { + +static constexpr const char* mergeSideloadedDatabaseSQL = +${fs.readFileSync('platform/default/mbgl/storage/merge_sideloaded.sql', 'utf8') + .replace(/ *--.*/g, '') + .split('\n') + .filter(a => a) + .map(line => '"' + line + '\\n"') + .join('\n') +} +; + +} // namespace mbgl +`); + diff --git a/platform/default/include/mbgl/storage/merge_sideloaded.sql b/platform/default/include/mbgl/storage/merge_sideloaded.sql new file mode 100644 index 0000000000..55345a6f15 --- /dev/null +++ b/platform/default/include/mbgl/storage/merge_sideloaded.sql @@ -0,0 +1,51 @@ +INSERT INTO regions + SELECT DISTINCT NULL, sr.definition, sr.description -- Merge duplicate regions + FROM side.regions sr + LEFT JOIN regions r ON sr.definition = r.definition AND sr.description IS r.description + WHERE r.definition IS NULL; + +CREATE TEMPORARY TABLE region_mapping AS + SELECT sr.id AS side_region_id, + r.id AS main_region_id + FROM side.regions sr + JOIN regions r ON sr.definition = r.definition AND sr.description IS r.description; + +--Insert /Update tiles +REPLACE INTO tiles + SELECT t.id, -- use the old ID in case we run a REPLACE. If it doesn't exist yet, it'll be NULL which will auto-assign a new ID. + st.url_template, st.pixel_ratio, st.z, st.x, st.y, + st.expires, st.modified, st.etag, st.data, st.compressed, st.accessed, st.must_revalidate + FROM (SELECT DISTINCT sti.* FROM side.region_tiles srt JOIN side.tiles sti ON srt.tile_id = sti.id) -- ensure that we're only considering region tiles, and not ambient tiles. + AS st + LEFT JOIN tiles t ON st.url_template = t.url_template AND st.pixel_ratio = t.pixel_ratio AND st.z = t.z AND st.x = t.x AND st.y = t.y + WHERE t.id IS NULL -- only consider tiles that don't exist yet in the original database. + OR st.modified > t.modified; -- ...or tiles that are newer in the side loaded DB. + +-- Update region_tiles usage +INSERT OR IGNORE INTO region_tiles + SELECT rm.main_region_id, sti.id + FROM side.region_tiles srt + JOIN region_mapping rm ON srt.region_id = rm.side_region_id + JOIN (SELECT t.id, st.id AS side_tile_id FROM side.tiles st + JOIN tiles t ON st.url_template = t.url_template AND st.pixel_ratio = t.pixel_ratio AND st.z = t.z AND st.x = t.x AND st.y = t.y + ) AS sti ON srt.tile_id = sti.side_tile_id; + +-- copy over resources +REPLACE INTO resources + SELECT r.id, + sr.url, sr.kind, sr.expires, sr.modified, sr.etag, + sr.data, sr.compressed, sr.accessed, sr.must_revalidate + FROM side.region_resources srr JOIN side.resources sr ON srr.resource_id = sr.id --only consider region resources, and not ambient resources. + LEFT JOIN resources r ON sr.url = r.url + WHERE r.id IS NULL -- only consider resources that don't exist yet in the main database + OR sr.modified > r.modified; -- ...or resources that are newer in the side loaded DB. + +-- Update region_resources usage +INSERT OR IGNORE INTO region_resources + SELECT rm.main_region_id, sri.id + FROM side.region_resources srr + JOIN region_mapping rm ON srr.region_id = rm.side_region_id + JOIN (SELECT r.id, sr.id AS side_resource_id FROM side.resources sr + JOIN resources r ON sr.url = r.url) AS sri ON srr.resource_id = sri.side_resource_id; + +DROP TABLE region_mapping;
\ No newline at end of file diff --git a/platform/default/include/mbgl/storage/offline_database.hpp b/platform/default/include/mbgl/storage/offline_database.hpp new file mode 100644 index 0000000000..993f36a606 --- /dev/null +++ b/platform/default/include/mbgl/storage/offline_database.hpp @@ -0,0 +1,130 @@ +#pragma once + +#include <mbgl/storage/resource.hpp> +#include <mbgl/storage/offline.hpp> +#include <mbgl/util/exception.hpp> +#include <mbgl/util/noncopyable.hpp> +#include <mbgl/util/optional.hpp> +#include <mbgl/util/constants.hpp> +#include <mbgl/util/mapbox.hpp> +#include <mbgl/util/expected.hpp> + +#include <unordered_map> +#include <memory> +#include <string> +#include <list> + +namespace mapbox { +namespace sqlite { +class Database; +class Statement; +class Query; +class Exception; +} // namespace sqlite +} // namespace mapbox + +namespace mbgl { + +class Response; +class TileID; + +namespace util { +struct IOException; +} // namespace util + +struct MapboxTileLimitExceededException : util::Exception { + MapboxTileLimitExceededException() : util::Exception("Mapbox tile limit exceeded") {} +}; + +class OfflineDatabase : private util::noncopyable { +public: + // Limits affect ambient caching (put) only; resources required by offline + // regions are exempt. + OfflineDatabase(std::string path, uint64_t maximumCacheSize = util::DEFAULT_MAX_CACHE_SIZE); + ~OfflineDatabase(); + + optional<Response> get(const Resource&); + + // Return value is (inserted, stored size) + std::pair<bool, uint64_t> put(const Resource&, const Response&); + + expected<OfflineRegions, std::exception_ptr> listRegions(); + + expected<OfflineRegion, std::exception_ptr> createRegion(const OfflineRegionDefinition&, + const OfflineRegionMetadata&); + + expected<OfflineRegions, std::exception_ptr> + mergeDatabase(const std::string& sideDatabasePath); + + expected<OfflineRegionMetadata, std::exception_ptr> + updateMetadata(const int64_t regionID, const OfflineRegionMetadata&); + + std::exception_ptr deleteRegion(OfflineRegion&&); + + // Return value is (response, stored size) + optional<std::pair<Response, uint64_t>> getRegionResource(int64_t regionID, const Resource&); + optional<int64_t> hasRegionResource(int64_t regionID, const Resource&); + uint64_t putRegionResource(int64_t regionID, const Resource&, const Response&); + void putRegionResources(int64_t regionID, const std::list<std::tuple<Resource, Response>>&, OfflineRegionStatus&); + + expected<OfflineRegionDefinition, std::exception_ptr> getRegionDefinition(int64_t regionID); + expected<OfflineRegionStatus, std::exception_ptr> getRegionCompletedStatus(int64_t regionID); + + void setOfflineMapboxTileCountLimit(uint64_t); + uint64_t getOfflineMapboxTileCountLimit(); + bool offlineMapboxTileCountLimitExceeded(); + uint64_t getOfflineMapboxTileCount(); + bool exceedsOfflineMapboxTileCountLimit(const Resource&); + +private: + void initialize(); + void handleError(const mapbox::sqlite::Exception&, const char* action); + void handleError(const util::IOException&, const char* action); + + void removeExisting(); + void removeOldCacheTable(); + void createSchema(); + void migrateToVersion5(); + void migrateToVersion3(); + void migrateToVersion6(); + + mapbox::sqlite::Statement& getStatement(const char *); + + optional<std::pair<Response, uint64_t>> getTile(const Resource::TileData&); + optional<int64_t> hasTile(const Resource::TileData&); + bool putTile(const Resource::TileData&, const Response&, + const std::string&, bool compressed); + + optional<std::pair<Response, uint64_t>> getResource(const Resource&); + optional<int64_t> hasResource(const Resource&); + bool putResource(const Resource&, const Response&, + const std::string&, bool compressed); + + uint64_t putRegionResourceInternal(int64_t regionID, const Resource&, const Response&); + + optional<std::pair<Response, uint64_t>> getInternal(const Resource&); + optional<int64_t> hasInternal(const Resource&); + std::pair<bool, uint64_t> putInternal(const Resource&, const Response&, bool evict); + + // Return value is true iff the resource was previously unused by any other regions. + bool markUsed(int64_t regionID, const Resource&); + + std::pair<int64_t, int64_t> getCompletedResourceCountAndSize(int64_t regionID); + std::pair<int64_t, int64_t> getCompletedTileCountAndSize(int64_t regionID); + + const std::string path; + std::unique_ptr<mapbox::sqlite::Database> db; + std::unordered_map<const char *, const std::unique_ptr<mapbox::sqlite::Statement>> statements; + + template <class T> + T getPragma(const char *); + + uint64_t maximumCacheSize; + + uint64_t offlineMapboxTileCountLimit = util::mapbox::DEFAULT_OFFLINE_TILE_COUNT_LIMIT; + optional<uint64_t> offlineMapboxTileCount; + + bool evict(uint64_t neededFreeSize); +}; + +} // namespace mbgl diff --git a/platform/default/include/mbgl/storage/offline_download.hpp b/platform/default/include/mbgl/storage/offline_download.hpp new file mode 100644 index 0000000000..1e77ff1d35 --- /dev/null +++ b/platform/default/include/mbgl/storage/offline_download.hpp @@ -0,0 +1,69 @@ +#pragma once + +#include <mbgl/storage/offline.hpp> +#include <mbgl/storage/resource.hpp> +#include <mbgl/storage/online_file_source.hpp> + +#include <list> +#include <unordered_set> +#include <memory> +#include <deque> + +namespace mbgl { + +class OfflineDatabase; +class FileSource; +class AsyncRequest; +class Response; +class Tileset; + +namespace style { +class Parser; +} // namespace style + +/** + * Coordinates the request and storage of all resources for an offline region. + + * @private + */ +class OfflineDownload { +public: + OfflineDownload(int64_t id, OfflineRegionDefinition&&, OfflineDatabase& offline, OnlineFileSource& online); + ~OfflineDownload(); + + void setObserver(std::unique_ptr<OfflineRegionObserver>); + void setState(OfflineRegionDownloadState); + + OfflineRegionStatus getStatus() const; + +private: + void activateDownload(); + void continueDownload(); + void deactivateDownload(); + + /* + * Ensure that the resource is stored in the database, requesting it if necessary. + * While the request is in progress, it is recorded in `requests`. If the download + * is deactivated, all in progress requests are cancelled. + */ + void ensureResource(const Resource&, std::function<void (Response)> = {}); + + void onMapboxTileCountLimitExceeded(); + + int64_t id; + OfflineRegionDefinition definition; + OfflineDatabase& offlineDatabase; + OnlineFileSource& onlineFileSource; + OfflineRegionStatus status; + std::unique_ptr<OfflineRegionObserver> observer; + + std::list<std::unique_ptr<AsyncRequest>> requests; + std::unordered_set<std::string> requiredSourceURLs; + std::deque<Resource> resourcesRemaining; + std::list<std::tuple<Resource, Response>> buffer; + + void queueResource(Resource); + void queueTiles(style::SourceType, uint16_t tileSize, const Tileset&); +}; + +} // namespace mbgl diff --git a/platform/default/include/mbgl/storage/offline_schema.hpp b/platform/default/include/mbgl/storage/offline_schema.hpp new file mode 100644 index 0000000000..e177d0dbd3 --- /dev/null +++ b/platform/default/include/mbgl/storage/offline_schema.hpp @@ -0,0 +1,63 @@ +#pragma once + +// THIS IS A GENERATED FILE; EDIT offline_schema.sql INSTEAD +// To regenerate, run `node platform/default/mbgl/storage/offline_schema.js` + +namespace mbgl { + +static constexpr const char* offlineDatabaseSchema = +"CREATE TABLE resources (\n" +" id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,\n" +" url TEXT NOT NULL,\n" +" kind INTEGER NOT NULL,\n" +" expires INTEGER,\n" +" modified INTEGER,\n" +" etag TEXT,\n" +" data BLOB,\n" +" compressed INTEGER NOT NULL DEFAULT 0,\n" +" accessed INTEGER NOT NULL,\n" +" must_revalidate INTEGER NOT NULL DEFAULT 0,\n" +" UNIQUE (url)\n" +");\n" +"CREATE TABLE tiles (\n" +" id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,\n" +" url_template TEXT NOT NULL,\n" +" pixel_ratio INTEGER NOT NULL,\n" +" z INTEGER NOT NULL,\n" +" x INTEGER NOT NULL,\n" +" y INTEGER NOT NULL,\n" +" expires INTEGER,\n" +" modified INTEGER,\n" +" etag TEXT,\n" +" data BLOB,\n" +" compressed INTEGER NOT NULL DEFAULT 0,\n" +" accessed INTEGER NOT NULL,\n" +" must_revalidate INTEGER NOT NULL DEFAULT 0,\n" +" UNIQUE (url_template, pixel_ratio, z, x, y)\n" +");\n" +"CREATE TABLE regions (\n" +" id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,\n" +" definition TEXT NOT NULL,\n" +" description BLOB\n" +");\n" +"CREATE TABLE region_resources (\n" +" region_id INTEGER NOT NULL REFERENCES regions(id) ON DELETE CASCADE,\n" +" resource_id INTEGER NOT NULL REFERENCES resources(id),\n" +" UNIQUE (region_id, resource_id)\n" +");\n" +"CREATE TABLE region_tiles (\n" +" region_id INTEGER NOT NULL REFERENCES regions(id) ON DELETE CASCADE,\n" +" tile_id INTEGER NOT NULL REFERENCES tiles(id),\n" +" UNIQUE (region_id, tile_id)\n" +");\n" +"CREATE INDEX resources_accessed\n" +"ON resources (accessed);\n" +"CREATE INDEX tiles_accessed\n" +"ON tiles (accessed);\n" +"CREATE INDEX region_resources_resource_id\n" +"ON region_resources (resource_id);\n" +"CREATE INDEX region_tiles_tile_id\n" +"ON region_tiles (tile_id);\n" +; + +} // namespace mbgl diff --git a/platform/default/include/mbgl/storage/offline_schema.js b/platform/default/include/mbgl/storage/offline_schema.js new file mode 100644 index 0000000000..fdb7dc6405 --- /dev/null +++ b/platform/default/include/mbgl/storage/offline_schema.js @@ -0,0 +1,21 @@ +var fs = require('fs'); +fs.writeFileSync('platform/default/mbgl/storage/offline_schema.hpp', `#pragma once + +// THIS IS A GENERATED FILE; EDIT offline_schema.sql INSTEAD +// To regenerate, run \`node platform/default/mbgl/storage/offline_schema.js\` + +namespace mbgl { + +static constexpr const char* offlineDatabaseSchema = +${fs.readFileSync('platform/default/mbgl/storage/offline_schema.sql', 'utf8') + .replace(/ *--.*/g, '') + .split('\n') + .filter(a => a) + .map(line => '"' + line + '\\n"') + .join('\n') +} +; + +} // namespace mbgl +`); + diff --git a/platform/default/include/mbgl/storage/offline_schema.sql b/platform/default/include/mbgl/storage/offline_schema.sql new file mode 100644 index 0000000000..722b0e0451 --- /dev/null +++ b/platform/default/include/mbgl/storage/offline_schema.sql @@ -0,0 +1,64 @@ +CREATE TABLE resources ( -- Generic table for style, source, sprite, and glyph resources. + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + url TEXT NOT NULL, + kind INTEGER NOT NULL, + expires INTEGER, + modified INTEGER, + etag TEXT, + data BLOB, + compressed INTEGER NOT NULL DEFAULT 0, + accessed INTEGER NOT NULL, + must_revalidate INTEGER NOT NULL DEFAULT 0, + UNIQUE (url) +); + +CREATE TABLE tiles ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + url_template TEXT NOT NULL, + pixel_ratio INTEGER NOT NULL, + z INTEGER NOT NULL, + x INTEGER NOT NULL, + y INTEGER NOT NULL, + expires INTEGER, + modified INTEGER, + etag TEXT, + data BLOB, + compressed INTEGER NOT NULL DEFAULT 0, + accessed INTEGER NOT NULL, + must_revalidate INTEGER NOT NULL DEFAULT 0, + UNIQUE (url_template, pixel_ratio, z, x, y) +); + +CREATE TABLE regions ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + definition TEXT NOT NULL, -- JSON formatted definition of region. Regions may be of variant types: + -- e.g. bbox and zoom range, route path, flyTo parameters, etc. Note that + -- the set of tiles required for a region may span multiple sources. + description BLOB -- User provided data in user-defined format +); + +CREATE TABLE region_resources ( + region_id INTEGER NOT NULL REFERENCES regions(id) ON DELETE CASCADE, + resource_id INTEGER NOT NULL REFERENCES resources(id), + UNIQUE (region_id, resource_id) +); + +CREATE TABLE region_tiles ( + region_id INTEGER NOT NULL REFERENCES regions(id) ON DELETE CASCADE, + tile_id INTEGER NOT NULL REFERENCES tiles(id), + UNIQUE (region_id, tile_id) +); + +-- Indexes for efficient eviction queries + +CREATE INDEX resources_accessed +ON resources (accessed); + +CREATE INDEX tiles_accessed +ON tiles (accessed); + +CREATE INDEX region_resources_resource_id +ON region_resources (resource_id); + +CREATE INDEX region_tiles_tile_id +ON region_tiles (tile_id); diff --git a/platform/default/include/mbgl/storage/sqlite3.hpp b/platform/default/include/mbgl/storage/sqlite3.hpp new file mode 100644 index 0000000000..44dc746075 --- /dev/null +++ b/platform/default/include/mbgl/storage/sqlite3.hpp @@ -0,0 +1,180 @@ +#pragma once + +#include <string> +#include <vector> +#include <stdexcept> +#include <chrono> +#include <memory> +#include <mapbox/variant.hpp> + +namespace mapbox { +namespace sqlite { + +enum OpenFlag : int { + ReadOnly = 0b001, + ReadWriteCreate = 0b110, +}; + +enum class ResultCode : uint8_t { + OK = 0, + Error = 1, + Internal = 2, + Perm = 3, + Abort = 4, + Busy = 5, + Locked = 6, + NoMem = 7, + ReadOnly = 8, + Interrupt = 9, + IOErr = 10, + Corrupt = 11, + NotFound = 12, + Full = 13, + CantOpen = 14, + Protocol = 15, + Schema = 17, + TooBig = 18, + Constraint = 19, + Mismatch = 20, + Misuse = 21, + NoLFS = 22, + Auth = 23, + Range = 25, + NotADB = 26, +}; + +enum class ExtendedResultCode : uint8_t { + Unknown = 0, + ReadOnlyDBMoved = 4, +}; + +class Exception : public std::runtime_error { +public: + Exception(ResultCode err, const char* msg) : Exception(static_cast<int>(err), msg) {} + Exception(int err, const char* msg) : Exception(err, std::string{ msg }) {} + Exception(int err, const std::string& msg) + : std::runtime_error(msg), + code(static_cast<ResultCode>(err)), + extendedCode(static_cast<ExtendedResultCode>(err >> 8)) { + } + const ResultCode code = ResultCode::OK; + const ExtendedResultCode extendedCode = ExtendedResultCode::Unknown; +}; + +class DatabaseImpl; +class Statement; +class StatementImpl; +class Query; +class Transaction; + +void setTempPath(const std::string&); + +class Database { +private: + Database(std::unique_ptr<DatabaseImpl>); + +public: + Database(const Database &) = delete; + Database &operator=(const Database &) = delete; + static mapbox::util::variant<Database, Exception> tryOpen(const std::string &filename, int flags = 0); + static Database open(const std::string &filename, int flags = 0); + + Database(Database &&); + ~Database(); + Database &operator=(Database &&); + + void setBusyTimeout(std::chrono::milliseconds); + void exec(const std::string &sql); + +private: + std::unique_ptr<DatabaseImpl> impl; + + friend class Statement; + friend class Transaction; +}; + +// A Statement object represents a prepared statement that can be run repeatedly run with a Query object. +class Statement { +public: + Statement(Database& db, const char* sql); + Statement(const Statement&) = delete; + Statement(Statement&&) = delete; + Statement& operator=(const Statement&) = delete; + Statement& operator=(Statement&&) = delete; + ~Statement(); + + friend class Query; + +private: + std::unique_ptr<StatementImpl> impl; + +#ifndef NDEBUG + // This flag stores whether there exists a Query object that uses this prepared statement. + // There may only be one Query object at a time. Statement objects must outlive Query objects. + // While a Query object exists, a Statement object may not be moved or deleted. + bool used = false; +#endif +}; + +// A Query object is used to run a database query with a prepared statement (stored in a Statement +// object). There may only exist one Query object per Statement object. Query objects are designed +// to be constructed and destroyed frequently. +class Query { +public: + Query(Statement&); + Query(const Query&) = delete; + Query(Query&&) = delete; + Query& operator=(const Query&) = delete; + Query& operator=(Query&&) = delete; + ~Query(); + + template <typename T> + void bind(int offset, T value); + + // Text + void bind(int offset, const char*, std::size_t length, bool retain = true); + void bind(int offset, const std::string&, bool retain = true); + + // Blob + void bindBlob(int offset, const void*, std::size_t length, bool retain = true); + void bindBlob(int offset, const std::vector<uint8_t>&, bool retain = true); + + template <typename T> + T get(int offset); + + bool run(); + void reset(); + void clearBindings(); + + int64_t lastInsertRowId() const; + uint64_t changes() const; + +private: + Statement& stmt; +}; + +class Transaction { +public: + Transaction(const Transaction&) = delete; + Transaction(Transaction&&) = delete; + Transaction& operator=(const Transaction&) = delete; + + enum Mode { + Deferred, + Immediate, + Exclusive + }; + + Transaction(Database&, Mode = Deferred); + ~Transaction(); + + void commit(); + void rollback(); + +private: + DatabaseImpl& dbImpl; + bool needRollback = true; +}; + +} // namespace sqlite +} // namespace mapbox diff --git a/platform/default/include/mbgl/text/unaccent.hpp b/platform/default/include/mbgl/text/unaccent.hpp new file mode 100644 index 0000000000..85ac37a7de --- /dev/null +++ b/platform/default/include/mbgl/text/unaccent.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include <string> + +namespace mbgl { +namespace platform { + +// Non-locale-aware diacritic folding based on nunicode +// Used as a fallback when locale-aware comparisons aren't available +std::string unaccent(const std::string &string); + +} // namespace platform +} // namespace mbgl diff --git a/platform/default/include/mbgl/util/default_styles.hpp b/platform/default/include/mbgl/util/default_styles.hpp new file mode 100644 index 0000000000..13f08252a7 --- /dev/null +++ b/platform/default/include/mbgl/util/default_styles.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include <vector> +#include <string> + +namespace mbgl { +namespace util { +namespace default_styles { + +struct DefaultStyle { + const char* url; + const char* name; + const unsigned currentVersion; +}; + +constexpr const DefaultStyle streets = { "mapbox://styles/mapbox/streets-v10", "Streets", 10 }; +constexpr const DefaultStyle outdoors = { "mapbox://styles/mapbox/outdoors-v10", "Outdoors", 10 }; +constexpr const DefaultStyle light = { "mapbox://styles/mapbox/light-v9", "Light", 9 }; +constexpr const DefaultStyle dark = { "mapbox://styles/mapbox/dark-v9", "Dark", 9 }; +constexpr const DefaultStyle satellite = { "mapbox://styles/mapbox/satellite-v9", "Satellite", 9 }; +constexpr const DefaultStyle satelliteStreets = { "mapbox://styles/mapbox/satellite-streets-v10", "Satellite Streets", 10 }; + +const DefaultStyle orderedStyles[] = { + streets, outdoors, light, dark, satellite, satelliteStreets, +}; +const size_t numOrderedStyles = sizeof(orderedStyles) / sizeof(DefaultStyle); + +} // end namespace default_styles +} // end namespace util +} // end namespace mbgl diff --git a/platform/default/include/mbgl/util/default_thread_pool.hpp b/platform/default/include/mbgl/util/default_thread_pool.hpp new file mode 100644 index 0000000000..a14d16d771 --- /dev/null +++ b/platform/default/include/mbgl/util/default_thread_pool.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include <mbgl/actor/scheduler.hpp> + +#include <condition_variable> +#include <mutex> +#include <queue> +#include <thread> + +namespace mbgl { + +class ThreadPool : public Scheduler { +public: + ThreadPool(std::size_t count); + ~ThreadPool() override; + + void schedule(std::weak_ptr<Mailbox>) override; + +private: + std::vector<std::thread> threads; + std::queue<std::weak_ptr<Mailbox>> queue; + std::mutex mutex; + std::condition_variable cv; + bool terminate { false }; +}; + +} // namespace mbgl diff --git a/platform/default/include/mbgl/util/shared_thread_pool.hpp b/platform/default/include/mbgl/util/shared_thread_pool.hpp new file mode 100644 index 0000000000..04a3cb58d5 --- /dev/null +++ b/platform/default/include/mbgl/util/shared_thread_pool.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include <mbgl/util/default_thread_pool.hpp> + +namespace mbgl { + +std::shared_ptr<ThreadPool> sharedThreadPool(); + +} // namespace mbgl |