summaryrefslogtreecommitdiff
path: root/platform/default
diff options
context:
space:
mode:
Diffstat (limited to 'platform/default')
-rw-r--r--platform/default/include/mbgl/gfx/headless_backend.hpp10
-rw-r--r--platform/default/include/mbgl/gfx/headless_frontend.hpp16
-rw-r--r--platform/default/include/mbgl/gl/headless_backend.hpp7
-rw-r--r--platform/default/include/mbgl/storage/offline_database.hpp1
-rw-r--r--platform/default/include/mbgl/storage/offline_schema.hpp2
-rwxr-xr-x[-rw-r--r--]platform/default/include/mbgl/storage/offline_schema.js8
-rw-r--r--platform/default/include/mbgl/storage/offline_schema.sql164
-rw-r--r--platform/default/src/mbgl/gfx/headless_frontend.cpp71
-rw-r--r--platform/default/src/mbgl/gl/headless_backend.cpp32
-rw-r--r--platform/default/src/mbgl/i18n/collator.cpp (renamed from platform/default/src/mbgl/text/collator.cpp)64
-rw-r--r--platform/default/src/mbgl/i18n/format_number.cpp (renamed from platform/default/src/mbgl/util/format_number.cpp)2
-rw-r--r--platform/default/src/mbgl/i18n/number_format.cpp41
-rw-r--r--platform/default/src/mbgl/map/map_snapshotter.cpp4
-rw-r--r--platform/default/src/mbgl/render-test/main.cpp5
-rw-r--r--platform/default/src/mbgl/storage/offline_database.cpp20
-rw-r--r--platform/default/src/mbgl/text/unaccent.cpp43
-rw-r--r--platform/default/src/mbgl/util/monotonic_timer.cpp24
17 files changed, 362 insertions, 152 deletions
diff --git a/platform/default/include/mbgl/gfx/headless_backend.hpp b/platform/default/include/mbgl/gfx/headless_backend.hpp
index 325422323a..5167e6a465 100644
--- a/platform/default/include/mbgl/gfx/headless_backend.hpp
+++ b/platform/default/include/mbgl/gfx/headless_backend.hpp
@@ -15,11 +15,13 @@ namespace gfx {
// of readStillImage.
class HeadlessBackend : public gfx::Renderable {
public:
+ enum class SwapBehaviour { NoFlush, Flush };
+
// Factory.
- static std::unique_ptr<HeadlessBackend>
- Create(const Size size = { 256, 256 },
- const gfx::ContextMode contextMode = gfx::ContextMode::Unique) {
- return Backend::Create<HeadlessBackend, Size, gfx::ContextMode>(size, contextMode);
+ static std::unique_ptr<HeadlessBackend> Create(const Size size = {256, 256},
+ SwapBehaviour swapBehavior = SwapBehaviour::NoFlush,
+ const gfx::ContextMode contextMode = gfx::ContextMode::Unique) {
+ return Backend::Create<HeadlessBackend, Size, SwapBehaviour, gfx::ContextMode>(size, swapBehavior, contextMode);
}
virtual PremultipliedImage readStillImage() = 0;
diff --git a/platform/default/include/mbgl/gfx/headless_frontend.hpp b/platform/default/include/mbgl/gfx/headless_frontend.hpp
index 8f7a7bf202..8a98b4112d 100644
--- a/platform/default/include/mbgl/gfx/headless_frontend.hpp
+++ b/platform/default/include/mbgl/gfx/headless_frontend.hpp
@@ -1,11 +1,13 @@
#pragma once
+#include <mbgl/gfx/headless_backend.hpp>
+#include <mbgl/gfx/rendering_stats.hpp>
#include <mbgl/map/camera.hpp>
#include <mbgl/renderer/renderer_frontend.hpp>
-#include <mbgl/gfx/headless_backend.hpp>
#include <mbgl/util/async_task.hpp>
#include <mbgl/util/optional.hpp>
+#include <atomic>
#include <memory>
namespace mbgl {
@@ -16,11 +18,18 @@ class TransformState;
class HeadlessFrontend : public RendererFrontend {
public:
+ struct RenderResult {
+ PremultipliedImage image;
+ gfx::RenderingStats stats;
+ };
+
HeadlessFrontend(float pixelRatio_,
+ gfx::HeadlessBackend::SwapBehaviour swapBehviour = gfx::HeadlessBackend::SwapBehaviour::NoFlush,
gfx::ContextMode mode = gfx::ContextMode::Unique,
const optional<std::string> localFontFamily = {});
HeadlessFrontend(Size,
float pixelRatio_,
+ gfx::HeadlessBackend::SwapBehaviour swapBehviour = gfx::HeadlessBackend::SwapBehaviour::NoFlush,
gfx::ContextMode mode = gfx::ContextMode::Unique,
const optional<std::string> localFontFamily = {});
~HeadlessFrontend() override;
@@ -29,6 +38,7 @@ public:
void update(std::shared_ptr<UpdateParameters>) override;
void setObserver(RendererObserver&) override;
+ double getFrameTime() const;
Size getSize() const;
void setSize(Size);
@@ -44,7 +54,8 @@ public:
LatLng latLngForPixel(const ScreenCoordinate&);
PremultipliedImage readStillImage();
- PremultipliedImage render(Map&);
+ RenderResult render(Map&);
+ void renderOnce(Map&);
optional<TransformState> getTransformState() const;
@@ -52,6 +63,7 @@ private:
Size size;
float pixelRatio;
+ std::atomic<double> frameTime;
std::unique_ptr<gfx::HeadlessBackend> backend;
util::AsyncTask asyncInvalidate;
diff --git a/platform/default/include/mbgl/gl/headless_backend.hpp b/platform/default/include/mbgl/gl/headless_backend.hpp
index 8aefb5ff6c..b77f1b756f 100644
--- a/platform/default/include/mbgl/gl/headless_backend.hpp
+++ b/platform/default/include/mbgl/gl/headless_backend.hpp
@@ -10,13 +10,17 @@ namespace gl {
class HeadlessBackend final : public gl::RendererBackend, public gfx::HeadlessBackend {
public:
- HeadlessBackend(Size = { 256, 256 }, gfx::ContextMode = gfx::ContextMode::Unique);
+ HeadlessBackend(Size = {256, 256},
+ SwapBehaviour = SwapBehaviour::NoFlush,
+ gfx::ContextMode = gfx::ContextMode::Unique);
~HeadlessBackend() override;
void updateAssumedState() override;
gfx::Renderable& getDefaultRenderable() override;
PremultipliedImage readStillImage() override;
RendererBackend* getRendererBackend() override;
+ void swap();
+
class Impl {
public:
virtual ~Impl() = default;
@@ -37,6 +41,7 @@ private:
private:
std::unique_ptr<Impl> impl;
bool active = false;
+ SwapBehaviour swapBehaviour = SwapBehaviour::NoFlush;
};
} // namespace gl
diff --git a/platform/default/include/mbgl/storage/offline_database.hpp b/platform/default/include/mbgl/storage/offline_database.hpp
index 96b867eaa6..e599094a6d 100644
--- a/platform/default/include/mbgl/storage/offline_database.hpp
+++ b/platform/default/include/mbgl/storage/offline_database.hpp
@@ -108,6 +108,7 @@ private:
void migrateToVersion6();
void cleanup();
bool disabled();
+ void vacuum();
mapbox::sqlite::Statement& getStatement(const char *);
diff --git a/platform/default/include/mbgl/storage/offline_schema.hpp b/platform/default/include/mbgl/storage/offline_schema.hpp
index e177d0dbd3..77c66b7d15 100644
--- a/platform/default/include/mbgl/storage/offline_schema.hpp
+++ b/platform/default/include/mbgl/storage/offline_schema.hpp
@@ -1,7 +1,7 @@
#pragma once
// THIS IS A GENERATED FILE; EDIT offline_schema.sql INSTEAD
-// To regenerate, run `node platform/default/mbgl/storage/offline_schema.js`
+// To regenerate, run `node platform/default/include/mbgl/storage/offline_schema.js`
namespace mbgl {
diff --git a/platform/default/include/mbgl/storage/offline_schema.js b/platform/default/include/mbgl/storage/offline_schema.js
index fdb7dc6405..a58e216d4a 100644..100755
--- a/platform/default/include/mbgl/storage/offline_schema.js
+++ b/platform/default/include/mbgl/storage/offline_schema.js
@@ -1,13 +1,15 @@
+#!/usr/bin/env node
+
var fs = require('fs');
-fs.writeFileSync('platform/default/mbgl/storage/offline_schema.hpp', `#pragma once
+fs.writeFileSync('platform/default/include/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\`
+// To regenerate, run \`node platform/default/include/mbgl/storage/offline_schema.js\`
namespace mbgl {
static constexpr const char* offlineDatabaseSchema =
-${fs.readFileSync('platform/default/mbgl/storage/offline_schema.sql', 'utf8')
+${fs.readFileSync('platform/default/include/mbgl/storage/offline_schema.sql', 'utf8')
.replace(/ *--.*/g, '')
.split('\n')
.filter(a => a)
diff --git a/platform/default/include/mbgl/storage/offline_schema.sql b/platform/default/include/mbgl/storage/offline_schema.sql
index 722b0e0451..93f6f2a5ce 100644
--- a/platform/default/include/mbgl/storage/offline_schema.sql
+++ b/platform/default/include/mbgl/storage/offline_schema.sql
@@ -1,55 +1,159 @@
-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,
+--
+-- Table containing the style, source, sprite, and glyph
+-- resources. Essentially everything that is not a tile.
+--
+CREATE TABLE resources (
+ id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, -- Primary key.
+
+ url TEXT NOT NULL, -- The URL of the resource without the access token. If a Mapbox
+ -- resource, will be stored using the mapbox:// schema. Must be
+ -- unique and that is enforced by the database schema.
+
+ kind INTEGER NOT NULL, -- Type of the resource, taken from Resource::Kind enumeration:
+ -- style = 1
+ -- source = 2
+ -- tile = 3
+ -- glyphs = 4
+ -- sprite image = 5
+ -- sprite JSON = 6
+ -- image = 7
+
+ expires INTEGER, -- Expiration time. The resource will be refreshed after this
+ -- expiration is reached.
+
+ modified INTEGER, -- Last time the resource was modified.
+
+ etag TEXT, -- Checksum used for cache optimization. If, when refreshing the
+ -- resource, it matches the etag on the server, the resource will
+ -- not get re-downloaded. See:
+ -- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag
+
+ data BLOB, -- Contents of the resource.
+
+ compressed INTEGER NOT NULL DEFAULT 0, -- If the resource is compressed with Deflate or not. Compression is
+ -- optional and should be used when the compression ratio is
+ -- significant. Using compression will make decoding time slower
+ -- because it will add an extra decompression step.
+
+ accessed INTEGER NOT NULL, -- Last time the resource was used by GL Native. Useful for when
+ -- evicting the least used resources from the cache.
+
+ must_revalidate INTEGER NOT NULL DEFAULT 0, -- When set to true, the resource will not be used unless it gets
+ -- first revalidated by the server.
UNIQUE (url)
);
+--
+-- Table containing all tiles, both vector and raster.
+--
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,
+ id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, -- Primary key.
+
+ url_template TEXT NOT NULL, -- The URL of the resource without the access token and without
+ -- the tiles id substituted. Mapbox tiles will be stored using
+ -- the mapbox:// schema. Example:
+ -- mapbox://tiles/user.dataset/{z}/{x}/{y}.vector.pbf
+
+ pixel_ratio INTEGER NOT NULL, -- The tile pixel ratio, typically 1 for vector tiles.
+
+ z INTEGER NOT NULL, -- The zoom level of the tile.
+
+ x INTEGER NOT NULL, -- The x position of the tile on the tile grid.
+
+ y INTEGER NOT NULL, -- The y position of the tile on the tile grid.
+
+ expires INTEGER, -- Expiration time. The tile will be refreshed after this
+ -- expiration is reached. Expired tiles can still be rendered,
+ -- unless must_revalidate is set to true. If an expired tile
+ -- gets rendered, it will be replaced by a newer version as soon
+ -- as the network request with a new tile arrives.
+
+ modified INTEGER, -- Last time the tile was modified.
+
+ etag TEXT, -- Checksum used for cache optimization. If, when refreshing the
+ -- tile, it matches the etag on the server, the tile will not
+ -- get re-downloaded. See:
+ -- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag
+
+ data BLOB, -- Contents of the tile.
+
+ compressed INTEGER NOT NULL DEFAULT 0, -- If the tile is compressed with Deflate or not. Compression is
+ -- optional and should be used when the compression ratio is
+ -- significant. Using compression will make decoding time slower
+ -- because it will add an extra decompression step.
+
+ accessed INTEGER NOT NULL, -- Last time the tile was used by GL Native. Useful for when
+ -- evicting the least used tiles from the cache.
+
+ must_revalidate INTEGER NOT NULL DEFAULT 0, -- When set to true, the tile will not be used unless it gets
+ -- first revalidated by the server.
UNIQUE (url_template, pixel_ratio, z, x, y)
);
+--
+-- Regions define the offline regions, which could be a GeoJSON geometry,
+-- or a bounding box like this example:
+--
+-- {
+-- "bounds": [
+-- 37.2,
+-- -122.8,
+-- 38.1,
+-- -121.7
+-- ],
+-- "include_ideographs": false,
+-- "max_zoom": 15.0,
+-- "min_zoom": 0.0,
+-- "pixel_ratio": 1.0,
+-- "style_url": "mapbox://styles/mapbox/streets-v11"
+-- }
+--
+-- The semantic definition of the region is up to the user and
+-- it could be a city, a country or an arbitrary bounding box.
+--
+-- Regions can overlap, which will cause them to share resources
+-- when it is the case.
+--
+-- "include_ideographs" is set to true when CJK characters are
+-- include on the offline package. By default, CJK is rendered
+-- by GL Native client side using local fonts. Downloading CJK
+-- will increase the size of the database considerably.
+--
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
+ id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, -- Primary key.
+
+ definition TEXT NOT NULL, -- JSON formatted definition of a region, a bounding box
+ -- or a GeoJSON geometry. See https://geojson.org.
+
+ description BLOB -- User provided data in user-defined format.
);
+--
+-- Table mapping resources to regions. A resource
+-- might be part of many regions. Resources without
+-- regions are part of the ambient cache.
+--
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)
);
+--
+-- Table mapping tiles to regions. A tile might
+-- be part of many regions, meaning that regions might
+-- overlap efficiently. Tiles without regions are part
+-- of the ambient cache.
+--
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
+--
+-- Indexes for efficient eviction queries.
+--
CREATE INDEX resources_accessed
ON resources (accessed);
diff --git a/platform/default/src/mbgl/gfx/headless_frontend.cpp b/platform/default/src/mbgl/gfx/headless_frontend.cpp
index 287567adbd..5235b2f408 100644
--- a/platform/default/src/mbgl/gfx/headless_frontend.cpp
+++ b/platform/default/src/mbgl/gfx/headless_frontend.cpp
@@ -1,43 +1,51 @@
-#include <mbgl/gfx/headless_frontend.hpp>
#include <mbgl/gfx/backend_scope.hpp>
+#include <mbgl/gfx/context.hpp>
+#include <mbgl/gfx/headless_frontend.hpp>
+#include <mbgl/map/map.hpp>
+#include <mbgl/map/transform_state.hpp>
#include <mbgl/renderer/renderer.hpp>
#include <mbgl/renderer/renderer_state.hpp>
#include <mbgl/renderer/update_parameters.hpp>
-#include <mbgl/map/map.hpp>
-#include <mbgl/map/transform_state.hpp>
+#include <mbgl/util/monotonic_timer.hpp>
#include <mbgl/util/run_loop.hpp>
namespace mbgl {
HeadlessFrontend::HeadlessFrontend(float pixelRatio_,
+ gfx::HeadlessBackend::SwapBehaviour swapBehavior,
const gfx::ContextMode contextMode,
const optional<std::string> localFontFamily)
- : HeadlessFrontend(
- { 256, 256 }, pixelRatio_, contextMode, localFontFamily) {
-}
+ : HeadlessFrontend({256, 256}, pixelRatio_, swapBehavior, contextMode, localFontFamily) {}
HeadlessFrontend::HeadlessFrontend(Size size_,
float pixelRatio_,
+ gfx::HeadlessBackend::SwapBehaviour swapBehavior,
const gfx::ContextMode contextMode,
const optional<std::string> localFontFamily)
: size(size_),
pixelRatio(pixelRatio_),
- backend(gfx::HeadlessBackend::Create({ static_cast<uint32_t>(size.width * pixelRatio),
- static_cast<uint32_t>(size.height * pixelRatio) }, contextMode)),
- asyncInvalidate([this] {
- if (renderer && updateParameters) {
- gfx::BackendScope guard { *getBackend() };
-
- // onStyleImageMissing might be called during a render. The user implemented method
- // could trigger a call to MGLRenderFrontend#update which overwrites `updateParameters`.
- // Copy the shared pointer here so that the parameters aren't destroyed while `render(...)` is
- // still using them.
- auto updateParameters_ = updateParameters;
- renderer->render(*updateParameters_);
- }
- }),
- renderer(std::make_unique<Renderer>(*getBackend(), pixelRatio, localFontFamily)) {
-}
+ frameTime(0),
+ backend(gfx::HeadlessBackend::Create(
+ {static_cast<uint32_t>(size.width * pixelRatio), static_cast<uint32_t>(size.height * pixelRatio)},
+ swapBehavior,
+ contextMode)),
+ asyncInvalidate([this] {
+ if (renderer && updateParameters) {
+ auto startTime = mbgl::util::MonotonicTimer::now();
+ gfx::BackendScope guard{*getBackend()};
+
+ // onStyleImageMissing might be called during a render. The user implemented method
+ // could trigger a call to MGLRenderFrontend#update which overwrites `updateParameters`.
+ // Copy the shared pointer here so that the parameters aren't destroyed while `render(...)` is
+ // still using them.
+ auto updateParameters_ = updateParameters;
+ renderer->render(*updateParameters_);
+
+ auto endTime = mbgl::util::MonotonicTimer::now();
+ frameTime = (endTime - startTime).count();
+ }
+ }),
+ renderer(std::make_unique<Renderer>(*getBackend(), pixelRatio, localFontFamily)) {}
HeadlessFrontend::~HeadlessFrontend() = default;
@@ -56,6 +64,10 @@ void HeadlessFrontend::setObserver(RendererObserver& observer_) {
renderer->setObserver(&observer_);
}
+double HeadlessFrontend::getFrameTime() const {
+ return frameTime;
+}
+
Size HeadlessFrontend::getSize() const {
return size;
}
@@ -128,29 +140,34 @@ PremultipliedImage HeadlessFrontend::readStillImage() {
return backend->readStillImage();
}
-PremultipliedImage HeadlessFrontend::render(Map& map) {
- PremultipliedImage result;
+HeadlessFrontend::RenderResult HeadlessFrontend::render(Map& map) {
+ HeadlessFrontend::RenderResult result;
std::exception_ptr error;
map.renderStill([&](std::exception_ptr e) {
if (e) {
error = e;
} else {
- result = backend->readStillImage();
+ result.image = backend->readStillImage();
+ result.stats = getBackend()->getContext().renderingStats();
}
});
- while (!result.valid() && !error) {
+ while (!result.image.valid() && !error) {
util::RunLoop::Get()->runOnce();
}
if (error) {
std::rethrow_exception(error);
}
-
+
return result;
}
+void HeadlessFrontend::renderOnce(Map&) {
+ util::RunLoop::Get()->runOnce();
+}
+
optional<TransformState> HeadlessFrontend::getTransformState() const {
if (updateParameters) {
return updateParameters->transformState;
diff --git a/platform/default/src/mbgl/gl/headless_backend.cpp b/platform/default/src/mbgl/gl/headless_backend.cpp
index 732e4babae..697c560f76 100644
--- a/platform/default/src/mbgl/gl/headless_backend.cpp
+++ b/platform/default/src/mbgl/gl/headless_backend.cpp
@@ -12,12 +12,12 @@ namespace gl {
class HeadlessRenderableResource final : public gl::RenderableResource {
public:
- HeadlessRenderableResource(gl::Context& context_, Size size_)
- : context(context_),
+ HeadlessRenderableResource(HeadlessBackend& backend_, gl::Context& context_, Size size_)
+ : backend(backend_),
+ context(context_),
color(context.createRenderbuffer<gfx::RenderbufferPixelType::RGBA>(size_)),
depthStencil(context.createRenderbuffer<gfx::RenderbufferPixelType::DepthStencil>(size_)),
- framebuffer(context.createFramebuffer(color, depthStencil)) {
- }
+ framebuffer(context.createFramebuffer(color, depthStencil)) {}
void bind() override {
context.bindFramebuffer = framebuffer.framebuffer;
@@ -25,18 +25,22 @@ public:
context.viewport = { 0, 0, framebuffer.size };
}
+ void swap() override { backend.swap(); }
+
+ HeadlessBackend& backend;
gl::Context& context;
gfx::Renderbuffer<gfx::RenderbufferPixelType::RGBA> color;
gfx::Renderbuffer<gfx::RenderbufferPixelType::DepthStencil> depthStencil;
gl::Framebuffer framebuffer;
};
-HeadlessBackend::HeadlessBackend(const Size size_, const gfx::ContextMode contextMode_)
- : mbgl::gl::RendererBackend(contextMode_), mbgl::gfx::HeadlessBackend(size_) {
-}
+HeadlessBackend::HeadlessBackend(const Size size_,
+ gfx::HeadlessBackend::SwapBehaviour swapBehaviour_,
+ const gfx::ContextMode contextMode_)
+ : mbgl::gl::RendererBackend(contextMode_), mbgl::gfx::HeadlessBackend(size_), swapBehaviour(swapBehaviour_) {}
HeadlessBackend::~HeadlessBackend() {
- gfx::BackendScope guard { *this };
+ gfx::BackendScope guard{*this};
resource.reset();
// Explicitly reset the context so that it is destructed and cleaned up before we destruct
// the impl object.
@@ -67,11 +71,15 @@ void HeadlessBackend::deactivate() {
gfx::Renderable& HeadlessBackend::getDefaultRenderable() {
if (!resource) {
- resource = std::make_unique<HeadlessRenderableResource>(static_cast<gl::Context&>(getContext()), size);
+ resource = std::make_unique<HeadlessRenderableResource>(*this, static_cast<gl::Context&>(getContext()), size);
}
return *this;
}
+void HeadlessBackend::swap() {
+ if (swapBehaviour == SwapBehaviour::Flush) static_cast<gl::Context&>(getContext()).finish();
+}
+
void HeadlessBackend::updateAssumedState() {
// no-op
}
@@ -89,9 +97,9 @@ RendererBackend* HeadlessBackend::getRendererBackend() {
namespace gfx {
template <>
-std::unique_ptr<gfx::HeadlessBackend>
-Backend::Create<gfx::Backend::Type::OpenGL>(const Size size, const gfx::ContextMode contextMode) {
- return std::make_unique<gl::HeadlessBackend>(size, contextMode);
+std::unique_ptr<gfx::HeadlessBackend> Backend::Create<gfx::Backend::Type::OpenGL>(
+ const Size size, gfx::HeadlessBackend::SwapBehaviour swapBehavior, const gfx::ContextMode contextMode) {
+ return std::make_unique<gl::HeadlessBackend>(size, swapBehavior, contextMode);
}
} // namespace gfx
diff --git a/platform/default/src/mbgl/text/collator.cpp b/platform/default/src/mbgl/i18n/collator.cpp
index 400fa4d94d..f46accff8a 100644
--- a/platform/default/src/mbgl/text/collator.cpp
+++ b/platform/default/src/mbgl/i18n/collator.cpp
@@ -1,7 +1,9 @@
-#include <mbgl/style/expression/collator.hpp>
-#include <mbgl/util/platform.hpp>
#include <libnu/strcoll.h>
-#include <mbgl/text/unaccent.hpp>
+#include <libnu/unaccent.h>
+#include <mbgl/i18n/collator.hpp>
+
+#include <cstring>
+#include <sstream>
/*
The default implementation of Collator ignores locale.
@@ -16,9 +18,35 @@
but would require bundling locale data.
*/
+namespace {
+std::string unaccent(const std::string& str) {
+ std::stringstream output;
+ char const *itr = str.c_str(), *nitr;
+ char const* end = itr + str.length();
+ char lo[5] = {0};
+
+ for (; itr < end; itr = nitr) {
+ uint32_t code_point = 0;
+ char const* buf = nullptr;
+
+ nitr = _nu_tounaccent(itr, end, nu_utf8_read, &code_point, &buf, nullptr);
+ if (buf != nullptr) {
+ do {
+ buf = NU_CASEMAP_DECODING_FUNCTION(buf, &code_point);
+ if (code_point == 0) break;
+ output.write(lo, nu_utf8_write(code_point, lo) - lo);
+ } while (code_point != 0);
+ } else {
+ output.write(itr, nitr - itr);
+ }
+ }
+
+ return output.str();
+}
+} // namespace
+
namespace mbgl {
-namespace style {
-namespace expression {
+namespace platform {
class Collator::Impl {
public:
@@ -28,8 +56,7 @@ public:
{}
bool operator==(const Impl& other) const {
- return caseSensitive == other.caseSensitive &&
- diacriticSensitive == other.diacriticSensitive;
+ return caseSensitive == other.caseSensitive && diacriticSensitive == other.diacriticSensitive;
}
int compare(const std::string& lhs, const std::string& rhs) const {
@@ -40,40 +67,35 @@ public:
return nu_strcasecoll(lhs.c_str(), rhs.c_str(),
nu_utf8_read, nu_utf8_read);
} else if (caseSensitive && !diacriticSensitive) {
- return nu_strcoll(platform::unaccent(lhs).c_str(), platform::unaccent(rhs).c_str(),
- nu_utf8_read, nu_utf8_read);
+ return nu_strcoll(unaccent(lhs).c_str(), unaccent(rhs).c_str(), nu_utf8_read, nu_utf8_read);
} else {
- return nu_strcasecoll(platform::unaccent(lhs).c_str(), platform::unaccent(rhs).c_str(),
- nu_utf8_read, nu_utf8_read);
+ return nu_strcasecoll(unaccent(lhs).c_str(), unaccent(rhs).c_str(), nu_utf8_read, nu_utf8_read);
}
}
std::string resolvedLocale() const {
return "";
}
+
private:
bool caseSensitive;
bool diacriticSensitive;
};
-
-Collator::Collator(bool caseSensitive, bool diacriticSensitive, optional<std::string> locale_)
- : impl(std::make_shared<Impl>(caseSensitive, diacriticSensitive, std::move(locale_)))
-{}
+int Collator::compare(const std::string& lhs, const std::string& rhs) const {
+ return impl->compare(lhs, rhs);
+}
bool Collator::operator==(const Collator& other) const {
return *impl == *(other.impl);
}
-int Collator::compare(const std::string& lhs, const std::string& rhs) const {
- return impl->compare(lhs, rhs);
-}
-
std::string Collator::resolvedLocale() const {
return impl->resolvedLocale();
}
+Collator::Collator(bool caseSensitive, bool diacriticSensitive, optional<std::string> locale)
+ : impl(std::make_shared<Impl>(caseSensitive, diacriticSensitive, std::move(locale))) {}
-} // namespace expression
-} // namespace style
+} // namespace platform
} // namespace mbgl
diff --git a/platform/default/src/mbgl/util/format_number.cpp b/platform/default/src/mbgl/i18n/format_number.cpp
index d1b51e11a1..7b6f24221d 100644
--- a/platform/default/src/mbgl/util/format_number.cpp
+++ b/platform/default/src/mbgl/i18n/format_number.cpp
@@ -1,4 +1,4 @@
-#include <mbgl/util/platform.hpp>
+#include <mbgl/i18n/number_format.hpp>
#include <unicode/numberformatter.h>
diff --git a/platform/default/src/mbgl/i18n/number_format.cpp b/platform/default/src/mbgl/i18n/number_format.cpp
new file mode 100644
index 0000000000..7f2bc5a5ef
--- /dev/null
+++ b/platform/default/src/mbgl/i18n/number_format.cpp
@@ -0,0 +1,41 @@
+#include <mbgl/i18n/number_format.hpp>
+
+#include <unicode/numberformatter.h>
+
+namespace mbgl {
+namespace platform {
+
+std::string formatNumber(double number,
+ const std::string& localeId,
+ const std::string& currency,
+ uint8_t minFractionDigits,
+ uint8_t maxFractionDigits) {
+ UErrorCode status = U_ZERO_ERROR;
+ icu::UnicodeString ustr;
+ std::string formatted;
+
+ icu::Locale locale = icu::Locale(localeId.c_str());
+ // Print the value as currency
+ if (!currency.empty()) {
+ icu::UnicodeString ucurrency = icu::UnicodeString::fromUTF8(currency);
+ ustr = icu::number::NumberFormatter::with()
+ .unit(icu::CurrencyUnit(ucurrency.getBuffer(), status))
+ .locale(locale)
+ .formatDouble(number, status)
+ .toString();
+ } else {
+ ustr = icu::number::NumberFormatter::with()
+#if U_ICU_VERSION_MAJOR_NUM >= 62
+ .precision(icu::number::Precision::minMaxFraction(minFractionDigits, maxFractionDigits))
+#else
+ .rounding(icu::number::Rounder::minMaxFraction(minFractionDigits, maxFractionDigits))
+#endif
+ .locale(locale)
+ .formatDouble(number, status)
+ .toString();
+ }
+ return ustr.toUTF8String(formatted);
+}
+
+} // namespace platform
+} // namespace mbgl
diff --git a/platform/default/src/mbgl/map/map_snapshotter.cpp b/platform/default/src/mbgl/map/map_snapshotter.cpp
index 5f4060e3f0..705a791af9 100644
--- a/platform/default/src/mbgl/map/map_snapshotter.cpp
+++ b/platform/default/src/mbgl/map/map_snapshotter.cpp
@@ -51,8 +51,8 @@ MapSnapshotter::Impl::Impl(const std::pair<bool, std::string> style,
const optional<LatLngBounds> region,
const optional<std::string> localFontFamily,
const ResourceOptions& resourceOptions)
- : frontend(
- size, pixelRatio, gfx::ContextMode::Unique, localFontFamily),
+ : frontend(
+ size, pixelRatio, gfx::HeadlessBackend::SwapBehaviour::NoFlush, gfx::ContextMode::Unique, localFontFamily),
map(frontend,
MapObserver::nullObserver(),
MapOptions().withMapMode(MapMode::Static).withSize(size).withPixelRatio(pixelRatio),
diff --git a/platform/default/src/mbgl/render-test/main.cpp b/platform/default/src/mbgl/render-test/main.cpp
new file mode 100644
index 0000000000..9b22b20e00
--- /dev/null
+++ b/platform/default/src/mbgl/render-test/main.cpp
@@ -0,0 +1,5 @@
+#include <mbgl/render_test.hpp>
+
+int main(int argc, char *argv[]) {
+ return mbgl::runRenderTests(argc, argv);
+}
diff --git a/platform/default/src/mbgl/storage/offline_database.cpp b/platform/default/src/mbgl/storage/offline_database.cpp
index 133e1f7992..5aa5738f41 100644
--- a/platform/default/src/mbgl/storage/offline_database.cpp
+++ b/platform/default/src/mbgl/storage/offline_database.cpp
@@ -140,11 +140,12 @@ void OfflineDatabase::removeExisting() {
void OfflineDatabase::removeOldCacheTable() {
assert(db);
db->exec("DROP TABLE IF EXISTS http_cache");
- db->exec("VACUUM");
+ vacuum();
}
void OfflineDatabase::createSchema() {
assert(db);
+ vacuum();
db->exec("PRAGMA journal_mode = DELETE");
db->exec("PRAGMA synchronous = FULL");
mapbox::sqlite::Transaction transaction(*db);
@@ -155,7 +156,7 @@ void OfflineDatabase::createSchema() {
void OfflineDatabase::migrateToVersion3() {
assert(db);
- db->exec("VACUUM");
+ vacuum();
db->exec("PRAGMA user_version = 3");
}
@@ -181,6 +182,15 @@ void OfflineDatabase::migrateToVersion6() {
transaction.commit();
}
+void OfflineDatabase::vacuum() {
+ if (getPragma<int64_t>("PRAGMA auto_vacuum") != 2 /*INCREMENTAL*/) {
+ db->exec("PRAGMA auto_vacuum = INCREMENTAL");
+ db->exec("VACUUM");
+ } else {
+ db->exec("PRAGMA incremental_vacuum");
+ }
+}
+
mapbox::sqlite::Statement& OfflineDatabase::getStatement(const char* sql) {
if (!db) {
initialize();
@@ -683,7 +693,7 @@ std::exception_ptr OfflineDatabase::clearAmbientCache() try {
resourceQuery.run();
- db->exec("VACUUM");
+ vacuum();
return nullptr;
} catch (const mapbox::sqlite::Exception& ex) {
@@ -871,7 +881,7 @@ std::exception_ptr OfflineDatabase::deleteRegion(OfflineRegion&& region) try {
evict(0);
assert(db);
- db->exec("VACUUM");
+ vacuum();
// Ensure that the cached offlineTileCount value is recalculated.
offlineMapboxTileCount = {};
@@ -1218,7 +1228,7 @@ std::exception_ptr OfflineDatabase::setMaximumAmbientCacheSize(uint64_t size) {
if (databaseSize > maximumAmbientCacheSize) {
evict(0);
- db->exec("VACUUM");
+ vacuum();
}
return nullptr;
diff --git a/platform/default/src/mbgl/text/unaccent.cpp b/platform/default/src/mbgl/text/unaccent.cpp
deleted file mode 100644
index 37b9a0d9ca..0000000000
--- a/platform/default/src/mbgl/text/unaccent.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-#include <mbgl/util/platform.hpp>
-#include <libnu/unaccent.h>
-#include <mbgl/text/unaccent.hpp>
-
-#include <cstring>
-#include <sstream>
-
-namespace mbgl { namespace platform {
-
-std::string unaccent(const std::string& str)
-{
- std::stringstream output;
- char const *itr = str.c_str(), *nitr;
- char const *end = itr + str.length();
- char lo[5] = { 0 };
-
- for (; itr < end; itr = nitr)
- {
- uint32_t code_point = 0;
- char const* buf = nullptr;
-
- nitr = _nu_tounaccent(itr, end, nu_utf8_read, &code_point, &buf, nullptr);
- if (buf != nullptr)
- {
- do
- {
- buf = NU_CASEMAP_DECODING_FUNCTION(buf, &code_point);
- if (code_point == 0) break;
- output.write(lo, nu_utf8_write(code_point, lo) - lo);
- }
- while (code_point != 0);
- }
- else
- {
- output.write(itr, nitr - itr);
- }
- }
-
- return output.str();
-}
-
-} // namespace platform
-} // namespace mbgl
diff --git a/platform/default/src/mbgl/util/monotonic_timer.cpp b/platform/default/src/mbgl/util/monotonic_timer.cpp
new file mode 100644
index 0000000000..43c2ce6717
--- /dev/null
+++ b/platform/default/src/mbgl/util/monotonic_timer.cpp
@@ -0,0 +1,24 @@
+#include <assert.h>
+#include <chrono>
+#include <mbgl/util/monotonic_timer.hpp>
+
+namespace mbgl {
+namespace util {
+
+// Prefer high resolution timer if it is monotonic
+template <typename T, std::enable_if_t<std::chrono::high_resolution_clock::is_steady, T>* = nullptr>
+static T sample() {
+ return std::chrono::duration_cast<T>(std::chrono::high_resolution_clock::now().time_since_epoch());
+}
+
+template <typename T, std::enable_if_t<!std::chrono::high_resolution_clock::is_steady, T>* = nullptr>
+static T sample() {
+ return std::chrono::duration_cast<T>(std::chrono::steady_clock::now().time_since_epoch());
+}
+
+std::chrono::duration<double> MonotonicTimer::now() {
+ return sample<std::chrono::duration<double>>();
+}
+
+} // namespace util
+} // namespace mbgl \ No newline at end of file