[general] moving ios and android project under ./platform folder

This commit is contained in:
Petr Pokorny
2020-12-20 12:38:56 +01:00
parent 8e759a51e4
commit 41f0be34e7
9877 changed files with 141 additions and 2889 deletions

View File

@@ -0,0 +1,74 @@
#pragma once
#include <mbgl/actor/aspiring_actor.hpp>
#include <mbgl/actor/established_actor.hpp>
#include <mbgl/actor/mailbox.hpp>
#include <mbgl/actor/message.hpp>
#include <mbgl/actor/actor_ref.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <memory>
#include <future>
#include <type_traits>
#include <cassert>
namespace mbgl {
/*
An `Actor<O>` is an owning reference to an asynchronous object of type `O`: an "actor".
Communication with an actor happens via message passing: you send a message to the object
(using `invoke`), passing a pointer to the member function to call and arguments which
are then forwarded to the actor.
The actor receives messages sent to it asynchronously, in a manner defined its `Scheduler`.
To store incoming messages before their receipt, each actor has a `Mailbox`, which acts as
a FIFO queue. Messages sent from actor S to actor R are guaranteed to be processed in the
order sent. However, relative order of messages sent by two *different* actors S1 and S2
to R is *not* guaranteed (and can't be: S1 and S2 may be acting asynchronously with respect
to each other).
An `Actor<O>` can be converted to an `ActorRef<O>`, a non-owning value object representing
a (weak) reference to the actor. Messages can be sent via the `Ref` as well.
It's safe -- and encouraged -- to pass `Ref`s between actors via messages. This is how two-way
communication and other forms of collaboration between multiple actors is accomplished.
It's safe for a `Ref` to outlive its `Actor` -- the reference is "weak", and does not extend
the lifetime of the owning Actor, and sending a message to a `Ref` whose `Actor` has died is
a no-op. (In the future, a dead-letters queue or log may be implemented.)
Construction and destruction of an Actor is synchronous: the corresponding `O`
object is constructed synchronously by the `Actor` constructor, and destructed synchronously
by the `~Actor` destructor, after ensuring that the `O` is not currently receiving an
asynchronous message. The constructor of `O` is passed an `ActorRef<O>` referring to itself
(which it can use to self-send messages), followed by the forwarded arguments passed to
`Actor<O>`. Asynchronous object construction can be accomplished by directly using the
lower-level types, `AspiringActor<O>` and `EstablishedActor<O>`.
Please don't send messages that contain shared pointers or references. That subverts the
purpose of the actor model: prohibiting direct concurrent access to shared state.
*/
template <class Object>
class Actor {
public:
template <class... Args>
Actor(Scheduler& scheduler, Args&&... args)
: target(scheduler, parent, std::forward<Args>(args)...) {}
template <class... Args>
Actor(std::shared_ptr<Scheduler> scheduler, Args&&... args)
: retainer(std::move(scheduler)), target(*retainer, parent, std::forward<Args>(args)...) {}
Actor(const Actor&) = delete;
ActorRef<std::decay_t<Object>> self() {
return parent.self();
}
private:
std::shared_ptr<Scheduler> retainer;
AspiringActor<Object> parent;
EstablishedActor<Object> target;
};
} // namespace mbgl

View File

@@ -0,0 +1,64 @@
#pragma once
#include <mbgl/actor/mailbox.hpp>
#include <mbgl/actor/message.hpp>
#include <memory>
namespace mbgl {
/*
An `ActorRef<O>` is a *non*-owning, weak reference to an actor of type `O`. You can send it
messages just like an `Actor<O>`. It's a value object: safe to copy and pass between actors
via messages.
An `ActorRef<O>` does not extend the lifetime of the corresponding `Actor<O>`. That's determined
entirely by whichever object owns the `Actor<O>` -- the actor's "supervisor".
It's safe for a `Ref` to outlive its `Actor` -- the reference is "weak", and does not extend
the lifetime of the owning Actor, and sending a message to a `Ref` whose `Actor` has died is
a no-op. (In the future, a dead-letters queue or log may be implemented.)
*/
template <class Object>
class ActorRef {
public:
ActorRef(Object& object_, std::weak_ptr<Mailbox> weakMailbox_)
: object(&object_),
weakMailbox(std::move(weakMailbox_)) {
}
template <typename Fn, class... Args>
void invoke(Fn fn, Args&&... args) const {
if (auto mailbox = weakMailbox.lock()) {
mailbox->push(actor::makeMessage(*object, fn, std::forward<Args>(args)...));
}
}
template <typename Fn, class... Args>
auto ask(Fn fn, Args&&... args) const {
// Result type is deduced from the function's return type
using ResultType = typename std::result_of<decltype(fn)(Object, Args...)>::type;
std::promise<ResultType> promise;
auto future = promise.get_future();
if (auto mailbox = weakMailbox.lock()) {
mailbox->push(
actor::makeMessage(
std::move(promise), *object, fn, std::forward<Args>(args)...
)
);
} else {
promise.set_exception(std::make_exception_ptr(std::runtime_error("Actor has gone away")));
}
return future;
}
private:
Object* object;
std::weak_ptr<Mailbox> weakMailbox;
};
} // namespace mbgl

View File

@@ -0,0 +1,60 @@
#pragma once
#include <mbgl/actor/mailbox.hpp>
#include <mbgl/actor/message.hpp>
#include <mbgl/actor/actor_ref.hpp>
#include <memory>
#include <future>
#include <type_traits>
#include <cassert>
namespace mbgl {
template <class Object>
class EstablishedActor;
template <class Object>
class Actor;
/*
An `AspiringActor<O>` is one half of the pair of types that comprise an actor (see `Actor<O>`),
the other half being `EstablishedActor<O>`. It is responsible for:
- ownership of the actor's `Mailbox`
- allocating the memory for (but *not* constructing) the target object `O`
Using these two pieces--the mailbox and a stable address for `O`--an `AspiringActor<O>` can
accept messages for the target object, or provide `ActorRef<O>`s that do so, before the object
has actually been constructed by the corresponding `EstablishedActor<O>`. (Such messages are
queued in the mailbox until after the object is constructed.)
This allows for an `AspiringActor<O>` to be created and safely used by a thread other than the
one on which the target object will (eventually) live.
*/
template <class Object>
class AspiringActor {
public:
AspiringActor() : mailbox(std::make_shared<Mailbox>()) {
// mailbox starts closed because the `Object` hasn't yet been constructed
assert(!mailbox->isOpen());
}
AspiringActor(const AspiringActor&) = delete;
ActorRef<std::decay_t<Object>> self() {
return ActorRef<std::decay_t<Object>>(object(), mailbox);
}
private:
std::shared_ptr<Mailbox> mailbox;
std::aligned_storage_t<sizeof(Object)> objectStorage;
Object& object() {
return *reinterpret_cast<Object *>(&objectStorage);
}
friend class EstablishedActor<Object>;
friend class Actor<Object>;
};
} // namespace mbgl

View File

@@ -0,0 +1,80 @@
#pragma once
#include <mbgl/actor/aspiring_actor.hpp>
#include <mbgl/actor/mailbox.hpp>
#include <mbgl/actor/message.hpp>
#include <mbgl/actor/actor_ref.hpp>
#include <memory>
#include <future>
#include <type_traits>
#include <cassert>
namespace mbgl {
/*
An `EstablishedActor<O>` is one half of the pair of types that comprise an actor (see `Actor<O>`),
the other half being `AspiringActor<O>`. It is responsible for managing the lifetime of the
target object `O` and the open/closed state of the parent's `mailbox`.
The `O` object's lifetime is contained by that of its owning `EstablishedActor<O>`: the
`EstablishedActor` constructor executes the `O` constructor via "placement new", constructing
it at the address provided by the parent `AspiringActor`, and the `~EstablishedActor` destructor
similarly executes the `~O` destructor (after closing the mailbox). `EstablishedActor` should
therefore live entirely on the thread intended to own `O`.
*/
template <class Object>
class EstablishedActor {
public:
// Construct the Object from a parameter pack `args` (i.e. `Object(args...)`)
template <typename U = Object, class... Args, typename std::enable_if<
std::is_constructible<U, Args...>::value ||
std::is_constructible<U, ActorRef<U>, Args...>::value
>::type * = nullptr>
EstablishedActor(Scheduler& scheduler, AspiringActor<Object>& parent_, Args&& ... args)
: parent(parent_) {
emplaceObject(std::forward<Args>(args)...);
parent.mailbox->open(scheduler);
}
// Construct the `Object` from a tuple containing the constructor arguments (i.e.
// `Object(std::get<0>(args), std::get<1>(args), ...)`)
template <class ArgsTuple, std::size_t ArgCount = std::tuple_size<std::decay_t<ArgsTuple>>::value>
EstablishedActor(Scheduler& scheduler, AspiringActor<Object>& parent_, ArgsTuple&& args)
: parent(parent_) {
emplaceObject(std::forward<ArgsTuple>(args), std::make_index_sequence<ArgCount>{});
parent.mailbox->open(scheduler);
}
EstablishedActor(const EstablishedActor&) = delete;
~EstablishedActor() {
parent.mailbox->close();
parent.object().~Object();
}
private:
// Enabled for Objects with a constructor taking ActorRef<Object> as the first parameter
template <typename U = Object, class... Args, typename std::enable_if<std::is_constructible<U, ActorRef<U>, Args...>::value>::type * = nullptr>
void emplaceObject(Args&&... args_) {
new (&parent.objectStorage) Object(parent.self(), std::forward<Args>(args_)...);
}
// Enabled for plain Objects
template <typename U = Object, class... Args, typename std::enable_if<std::is_constructible<U, Args...>::value>::type * = nullptr>
void emplaceObject(Args&&... args_) {
new (&parent.objectStorage) Object(std::forward<Args>(args_)...);
}
// Used to expand a tuple holding the constructor arguments
template <class ArgsTuple, std::size_t... I>
void emplaceObject(ArgsTuple&& args, std::index_sequence<I...>) {
emplaceObject(std::move(std::get<I>(std::forward<ArgsTuple>(args)))...);
(void) args; // mark args as used: if it's empty tuple, it's not actually used above.
}
AspiringActor<Object>& parent;
};
} // namespace mbgl

View File

@@ -0,0 +1,54 @@
#pragma once
#include <mbgl/util/optional.hpp>
#include <functional>
#include <memory>
#include <mutex>
#include <queue>
#include <mapbox/std/weak.hpp>
namespace mbgl {
class Scheduler;
class Message;
class Mailbox : public std::enable_shared_from_this<Mailbox> {
public:
// Create a "holding" mailbox, messages to which will remain queued,
// unconsumed, until the mailbox is associated with a Scheduler using
// start(). This allows a Mailbox object to be created on one thread and
// later transferred to a different target thread that may not yet exist.
Mailbox();
Mailbox(Scheduler&);
// Attach the given scheduler to this mailbox and begin processing messages
// sent to it. The mailbox must be a "holding" mailbox, as created by the
// default constructor Mailbox().
void open(Scheduler& scheduler_);
void close();
bool isOpen() const;
void push(std::unique_ptr<Message>);
void receive();
static void maybeReceive(const std::weak_ptr<Mailbox>&);
static std::function<void()> makeClosure(std::weak_ptr<Mailbox>);
private:
mapbox::base::WeakPtr<Scheduler> weakScheduler;
std::recursive_mutex receivingMutex;
std::mutex pushingMutex;
bool closed { false };
std::mutex queueMutex;
std::queue<std::unique_ptr<Message>> queue;
};
} // namespace mbgl

View File

@@ -0,0 +1,108 @@
#pragma once
#include <mbgl/util/optional.hpp>
#include <future>
#include <utility>
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 Message {
public:
virtual ~Message() = default;
virtual void operator()() = 0;
};
template <class Object, class MemberFn, class ArgsTuple>
class MessageImpl : public Message {
public:
MessageImpl(Object& object_, MemberFn memberFn_, ArgsTuple argsTuple_)
: object(object_),
memberFn(memberFn_),
argsTuple(std::move(argsTuple_)) {
}
void operator()() override {
invoke(std::make_index_sequence<std::tuple_size<ArgsTuple>::value>());
}
template <std::size_t... I>
void invoke(std::index_sequence<I...>) {
(object.*memberFn)(std::move(std::get<I>(argsTuple))...);
}
Object& object;
MemberFn memberFn;
ArgsTuple argsTuple;
};
template <class ResultType, class Object, class MemberFn, class ArgsTuple>
class AskMessageImpl : public Message {
public:
AskMessageImpl(std::promise<ResultType> promise_, Object& object_, MemberFn memberFn_, ArgsTuple argsTuple_)
: object(object_),
memberFn(memberFn_),
argsTuple(std::move(argsTuple_)),
promise(std::move(promise_)) {
}
void operator()() override {
promise.set_value(ask(std::make_index_sequence<std::tuple_size<ArgsTuple>::value>()));
}
template <std::size_t... I>
ResultType ask(std::index_sequence<I...>) {
return (object.*memberFn)(std::move(std::get<I>(argsTuple))...);
}
Object& object;
MemberFn memberFn;
ArgsTuple argsTuple;
std::promise<ResultType> promise;
};
template <class Object, class MemberFn, class ArgsTuple>
class AskMessageImpl<void, Object, MemberFn, ArgsTuple> : public Message {
public:
AskMessageImpl(std::promise<void> promise_, Object& object_, MemberFn memberFn_, ArgsTuple argsTuple_)
: object(object_),
memberFn(memberFn_),
argsTuple(std::move(argsTuple_)),
promise(std::move(promise_)) {
}
void operator()() override {
ask(std::make_index_sequence<std::tuple_size<ArgsTuple>::value>());
promise.set_value();
}
template <std::size_t... I>
void ask(std::index_sequence<I...>) {
(object.*memberFn)(std::move(std::get<I>(argsTuple))...);
}
Object& object;
MemberFn memberFn;
ArgsTuple argsTuple;
std::promise<void> promise;
};
namespace actor {
template <class Object, class MemberFn, class... Args>
std::unique_ptr<Message> makeMessage(Object& object, MemberFn memberFn, Args&&... args) {
auto tuple = std::make_tuple(std::forward<Args>(args)...);
return std::make_unique<MessageImpl<Object, MemberFn, decltype(tuple)>>(object, memberFn, std::move(tuple));
}
template <class ResultType, class Object, class MemberFn, class... Args>
std::unique_ptr<Message> makeMessage(std::promise<ResultType>&& promise, Object& object, MemberFn memberFn, Args&&... args) {
auto tuple = std::make_tuple(std::forward<Args>(args)...);
return std::make_unique<AskMessageImpl<ResultType, Object, MemberFn, decltype(tuple)>>(std::move(promise), object, memberFn, std::move(tuple));
}
} // namespace actor
} // namespace mbgl

View File

@@ -0,0 +1,105 @@
#pragma once
#include <mbgl/util/pass_types.hpp>
#include <mapbox/std/weak.hpp>
#include <functional>
#include <memory>
namespace mbgl {
class Mailbox;
/*
A `Scheduler` is responsible for coordinating the processing of messages by
one or more actors via their mailboxes. It's an abstract interface. Currently,
the following concrete implementations exist:
* `ThreadPool` can coordinate an unlimited number of actors over any number of
threads via a pool, preserving the following behaviors:
- Messages from each individual mailbox are processed in order
- Only a single message from a mailbox is processed at a time; there is no
concurrency within a mailbox
Subject to these constraints, processing can happen on whatever thread in the
pool is available.
* `Scheduler::GetCurrent()` is typically used to create a mailbox and `ActorRef`
for an object that lives on the main thread and is not itself wrapped an
`Actor`. The underlying implementation of this Scheduler should usually be
a `RunLoop`
auto mailbox = std::make_shared<Mailbox>(*Scheduler::Get());
Actor<Worker> worker(threadPool, ActorRef<Foo>(*this, mailbox));
*/
class Scheduler {
public:
virtual ~Scheduler() = default;
// Enqueues a function for execution.
virtual void schedule(std::function<void()>) = 0;
// Makes a weak pointer to this Scheduler.
virtual mapbox::base::WeakPtr<Scheduler> makeWeakPtr() = 0;
// Returns a closure wrapping the given one.
//
// When the returned closure is invoked for the first time, it schedules
// the given closure to this scheduler, the consequent calls of the
// returned closure are ignored.
//
// If this scheduler is already deleted by the time the returnded closure is
// first invoked, the call is ignored.
std::function<void()> bindOnce(std::function<void()>);
// Enqueues the given |task| for execution into this scheduler's task queue and
// then enqueues the |reply| with the captured task result to the current
// task queue.
//
// The |TaskFn| return type must be compatible with the |ReplyFn| argument type.
// Note: the task result is copied and passed by value.
template <typename TaskFn, typename ReplyFn>
void scheduleAndReplyValue(const TaskFn& task, const ReplyFn& reply) {
assert(GetCurrent());
scheduleAndReplyValue(task, reply, GetCurrent()->makeWeakPtr());
}
// Set/Get the current Scheduler for this thread
static Scheduler* GetCurrent();
static void SetCurrent(Scheduler*);
// Get the scheduler for asynchronous tasks. This method
// will lazily initialize a shared worker pool when ran
// from the first time.
// The scheduled tasks might run in parallel on different
// threads.
// TODO : Rename to GetPool()
static PassRefPtr<Scheduler> GetBackground();
// Get the *sequenced* scheduler for asynchronous tasks.
// Unlike the method above, the returned scheduler
// (once stored) represents a single thread, thus each
// newly scheduled task is guarantied to run after the
// previously scheduled one.
//
// Sequenced scheduler can be used for running tasks
// on the same thread-unsafe object.
static PassRefPtr<Scheduler> GetSequenced();
protected:
template <typename TaskFn, typename ReplyFn>
void scheduleAndReplyValue(const TaskFn& task,
const ReplyFn& reply,
mapbox::base::WeakPtr<Scheduler> replyScheduler) {
auto scheduled = [replyScheduler = std::move(replyScheduler), task, reply] {
auto lock = replyScheduler.lock();
if (!replyScheduler) return;
auto scheduledReply = [reply, result = task()] { reply(result); };
replyScheduler->schedule(std::move(scheduledReply));
};
schedule(std::move(scheduled));
}
};
} // namespace mbgl

View File

@@ -0,0 +1,70 @@
#pragma once
#include <mbgl/util/geometry.hpp>
#include <mbgl/util/variant.hpp>
#include <mbgl/util/color.hpp>
#include <mbgl/style/property_value.hpp>
#include <cstdint>
#include <vector>
#include <string>
namespace mbgl {
using AnnotationID = uint64_t;
using AnnotationIDs = std::vector<AnnotationID>;
class SymbolAnnotation {
public:
SymbolAnnotation(Point<double> geometry_, std::string icon_ = {}) : geometry(geometry_), icon(std::move(icon_)) {}
Point<double> geometry;
std::string icon;
};
using ShapeAnnotationGeometry = variant<
LineString<double>,
Polygon<double>,
MultiLineString<double>,
MultiPolygon<double>>;
class LineAnnotation {
public:
LineAnnotation(ShapeAnnotationGeometry geometry_,
style::PropertyValue<float> opacity_ = 1.0f,
style::PropertyValue<float> width_ = 1.0f,
style::PropertyValue<Color> color_ = Color::black())
: geometry(std::move(geometry_)),
opacity(std::move(opacity_)),
width(std::move(width_)),
color(std::move(color_)) {}
ShapeAnnotationGeometry geometry;
style::PropertyValue<float> opacity;
style::PropertyValue<float> width;
style::PropertyValue<Color> color;
};
class FillAnnotation {
public:
FillAnnotation(ShapeAnnotationGeometry geometry_,
style::PropertyValue<float> opacity_ = 1.0f,
style::PropertyValue<Color> color_ = Color::black(),
style::PropertyValue<Color> outlineColor_ = {})
: geometry(std::move(geometry_)),
opacity(std::move(opacity_)),
color(std::move(color_)),
outlineColor(std::move(outlineColor_)) {}
ShapeAnnotationGeometry geometry;
style::PropertyValue<float> opacity;
style::PropertyValue<Color> color;
style::PropertyValue<Color> outlineColor;
};
using Annotation = variant<
SymbolAnnotation,
LineAnnotation,
FillAnnotation>;
} // namespace mbgl

View File

@@ -0,0 +1,44 @@
#pragma once
#include <cstdint>
#include <cstdlib>
#include <memory>
namespace mbgl {
namespace gfx {
class Backend {
public:
enum class Type : uint8_t {
OpenGL,
};
static constexpr Type DefaultType = Type::OpenGL;
static void SetType(const Type value) {
if (Value(value) != value) {
abort(); // SetType must be called prior to any GetType calls.
}
}
static Type GetType() {
return Value(DefaultType);
}
template <typename T, typename... Args>
static std::unique_ptr<T> Create(Args... args) {
return Create<Type::OpenGL, T, Args...>(std::forward<Args>(args)...);
}
private:
template <Type, typename T, typename... Args>
static std::unique_ptr<T> Create(Args...);
static Type Value(Type value) {
static const Type type = value;
return type;
}
};
} // namespace gfx
} // namespace mbgl

View File

@@ -0,0 +1,37 @@
#pragma once
namespace mbgl {
namespace gfx {
class RendererBackend;
class BackendScope {
public:
// There are two types of scopes: Creating an "Implicit" scope tells Mapbox GL that the
// supporting windowing system has already activated the GL Backend and that no further actions
// are required. Creating an "Explicit" scope actually enables the GL Backend, and disables it
// when the BackendScope is destroyed.
enum class ScopeType : bool {
Implicit,
Explicit,
};
BackendScope(RendererBackend&, ScopeType = ScopeType::Explicit);
~BackendScope();
// Returns true when there is currently a BackendScope active in this thread.
static bool exists();
private:
void activate();
void deactivate();
BackendScope* priorScope;
BackendScope* nextScope;
RendererBackend& backend;
const ScopeType scopeType;
bool activated = false;
};
} // namespace gfx
} // namespace mbgl

View File

@@ -0,0 +1,47 @@
#pragma once
#include <mbgl/util/size.hpp>
#include <memory>
#include <cassert>
namespace mbgl {
namespace gfx {
class RenderableResource {
protected:
explicit RenderableResource() = default;
public:
virtual ~RenderableResource() = default;
RenderableResource(const RenderableResource&) = delete;
RenderableResource& operator=(const RenderableResource&) = delete;
};
class Renderable {
protected:
Renderable(const Size size_, std::unique_ptr<RenderableResource> resource_)
: size(size_), resource(std::move(resource_)) {
}
virtual ~Renderable() = default;
public:
Size getSize() const {
return size;
}
template <typename T>
T& getResource() const {
assert(resource);
return static_cast<T&>(*resource);
}
virtual void wait() {}
protected:
Size size;
std::unique_ptr<RenderableResource> resource;
};
} // namespace gfx
} // namespace mbgl

View File

@@ -0,0 +1,72 @@
#pragma once
#include <mbgl/util/util.hpp>
#include <memory>
#include <mutex>
namespace mbgl {
namespace gfx {
class Context;
class Renderable;
class BackendScope;
// We can make some optimizations if we know that the drawing context is not shared with other code.
enum class ContextMode : bool {
Unique,
Shared,
};
class RendererBackend {
protected:
explicit RendererBackend(ContextMode);
public:
virtual ~RendererBackend();
RendererBackend(const RendererBackend&) = delete;
RendererBackend& operator=(const RendererBackend&) = delete;
// Returns the device's context.
Context& getContext();
template <typename T>
T& getContext() {
return static_cast<T&>(getContext());
}
bool contextIsShared() const {
return contextMode == ContextMode::Shared;
}
// Returns a reference to the default surface that should be rendered on.
virtual Renderable& getDefaultRenderable() = 0;
protected:
virtual std::unique_ptr<Context> createContext() = 0;
// Called when the backend's GL context needs to be made active or inactive. These are called,
// as a matched pair, exclusively through BackendScope, in two situations:
//
// 1. When releasing GL resources during Renderer destruction
// (Including calling CustomLayerHost::deinitialize during RenderCustomLayer destruction)
// 2. When renderering through Renderer::render()
// (Including calling CustomLayerHost::initialize for newly added custom layers and
// CustomLayerHost::deinitialize on layer removal)
virtual void activate() = 0;
virtual void deactivate() = 0;
protected:
std::unique_ptr<Context> context;
const ContextMode contextMode;
std::once_flag initialized;
friend class BackendScope;
};
MBGL_CONSTEXPR bool operator==(const RendererBackend& a, const RendererBackend& b) {
return &a == &b;
}
} // namespace gfx
} // namespace mbgl

View File

@@ -0,0 +1,37 @@
#pragma once
namespace mbgl {
namespace gfx {
struct RenderingStats {
RenderingStats() = default;
bool isZero() const;
int numDrawCalls;
int numActiveTextures;
int numCreatedTextures;
int numBuffers;
int numFrameBuffers;
int memTextures;
int memIndexBuffers;
int memVertexBuffers;
RenderingStats& operator+=(const RenderingStats& right);
};
inline RenderingStats& RenderingStats::operator+=(const RenderingStats& r) {
numDrawCalls += r.numDrawCalls;
numActiveTextures += r.numActiveTextures;
numCreatedTextures += r.numCreatedTextures;
numBuffers += r.numBuffers;
numFrameBuffers += r.numFrameBuffers;
memTextures += r.memTextures;
memIndexBuffers += r.memIndexBuffers;
memVertexBuffers += r.memVertexBuffers;
return *this;
}
} // namespace gfx
} // namespace mbgl

View File

@@ -0,0 +1,84 @@
#pragma once
#include <mbgl/style/layer.hpp>
#include <array>
namespace mbgl {
namespace style {
/**
* Parameters that define the current camera position for a `CustomLayerHost::render()` function.
*/
struct CustomLayerRenderParameters {
double width;
double height;
double latitude;
double longitude;
double zoom;
double bearing;
double pitch;
double fieldOfView;
std::array<double, 16> projectionMatrix;
};
class CustomLayerHost {
public:
virtual ~CustomLayerHost() = default;
/**
* Initialize any GL state needed by the custom layer. This method is called once, from the
* main thread, at a point when the GL context is active but before rendering for the first
* time.
*
* Resources that are acquired in this method must be released in the `deinitialize` function.
*/
virtual void initialize() = 0;
/**
* Render the layer. This method is called once per frame. The implementation should not make
* any assumptions about the GL state (other than that the correct context is active). It may
* make changes to the state, and is not required to reset values such as the depth mask, stencil
* mask, and corresponding test flags to their original values.
* Make sure that you are drawing your fragments with a z value of 1 to take advantage of the
* opaque fragment culling in case there are opaque layers above your custom layer.
*/
virtual void render(const CustomLayerRenderParameters&) = 0;
/**
* Called when the system has destroyed the underlying GL context. The
* `deinitialize` function will not be called in this case, however
* `initialize` will be called instead to prepare for a new render.
*
*/
virtual void contextLost() = 0;
/**
* Destroy any GL state needed by the custom layer, and deallocate context, if necessary. This
* method is called once, from the main thread, at a point when the GL context is active.
*
* Note that it may be called even when the `initialize` function has not been called.
*/
virtual void deinitialize() = 0;
};
class CustomLayer final : public Layer {
public:
CustomLayer(const std::string& id,
std::unique_ptr<CustomLayerHost> host);
CustomLayer(const CustomLayer&) = delete;
~CustomLayer() final;
class Impl;
const Impl& impl() const;
Mutable<Impl> mutableImpl() const;
private:
optional<conversion::Error> setPropertyInternal(const std::string& name,
const conversion::Convertible& value) final;
StyleProperty getProperty(const std::string&) const final;
std::unique_ptr<Layer> cloneRef(const std::string& id) const final;
Mutable<Layer::Impl> mutableBaseImpl() const final;
};
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,17 @@
#pragma once
#include <mbgl/layermanager/layer_factory.hpp>
#include <mbgl/style/layer.hpp>
#include <array>
namespace mbgl {
class CustomLayerFactory : public LayerFactory {
protected:
const style::LayerTypeInfo* getTypeInfo() const noexcept final;
std::unique_ptr<style::Layer> createLayer(const std::string& id, const style::conversion::Convertible& value) noexcept final;
std::unique_ptr<RenderLayer> createRenderLayer(Immutable<style::Layer::Impl>) noexcept final;
};
} // namespace mbgl

View File

@@ -0,0 +1,24 @@
#pragma once
#include <mbgl/gfx/renderable.hpp>
#include <cstdlib>
namespace mbgl {
namespace gl {
class RenderableResource : public gfx::RenderableResource {
protected:
explicit RenderableResource() = default;
public:
virtual void bind() = 0;
virtual void swap() {
// Renderable resources that require a swap function to be called explicitly
// can override this method.
}
};
} // namespace gl
} // namespace mbgl

View File

@@ -0,0 +1,55 @@
#pragma once
#include <mbgl/gfx/renderer_backend.hpp>
#include <mbgl/util/image.hpp>
#include <mbgl/util/size.hpp>
#include <mbgl/util/util.hpp>
namespace mbgl {
namespace gl {
using ProcAddress = void (*)();
using FramebufferID = uint32_t;
class RendererBackend : public gfx::RendererBackend {
public:
RendererBackend(gfx::ContextMode);
~RendererBackend() override;
// Called prior to rendering to update the internally assumed OpenGL state.
virtual void updateAssumedState() = 0;
protected:
std::unique_ptr<gfx::Context> createContext() override;
// Called with the name of an OpenGL extension that should be loaded. RendererBackend implementations
// must call the API-specific version that obtains the function pointer for this function,
// or a null pointer if unsupported/unavailable.
virtual ProcAddress getExtensionFunctionPointer(const char*) = 0;
// Reads the color pixel data from the currently bound framebuffer.
PremultipliedImage readFramebuffer(const Size&);
// A constant to signal that a framebuffer is bound, but with an unknown ID.
static constexpr const FramebufferID ImplicitFramebufferBinding =
std::numeric_limits<FramebufferID>::max();
// Tells the renderer that OpenGL state has already been set by the windowing toolkit.
// It sets the internal assumed state to the supplied values.
void assumeFramebufferBinding(FramebufferID fbo);
void assumeViewport(int32_t x, int32_t y, const Size&);
void assumeScissorTest(bool);
// Returns true when assumed framebuffer binding hasn't changed from the implicit binding.
bool implicitFramebufferBound();
public:
// Triggers an OpenGL state update if the internal assumed state doesn't match the
// supplied values.
void setFramebufferBinding(FramebufferID fbo);
void setViewport(int32_t x, int32_t y, const Size&);
void setScissorTest(bool);
};
} // namespace gl
} // namespace mbgl

View File

@@ -0,0 +1,24 @@
#pragma once
#include <mbgl/util/optional.hpp>
#include <memory>
#include <string>
namespace mbgl {
namespace platform {
class Collator {
public:
explicit Collator(bool caseSensitive, bool diacriticSensitive, const optional<std::string>& locale = nullopt);
int compare(const std::string& lhs, const std::string& rhs) const;
std::string resolvedLocale() const;
bool operator==(const Collator& other) const;
private:
class Impl;
std::shared_ptr<Impl> impl;
};
} // namespace platform
} // namespace mbgl

View File

@@ -0,0 +1,15 @@
#pragma once
#include <string>
namespace mbgl {
namespace platform {
std::string formatNumber(double number,
const std::string& localeId,
const std::string& currency,
uint8_t minFractionDigits,
uint8_t maxFractionDigits);
} // namespace platform
} // namespace mbgl

View File

@@ -0,0 +1,14 @@
#pragma once
#include <mbgl/layermanager/layer_factory.hpp>
namespace mbgl {
class BackgroundLayerFactory : public LayerFactory {
protected:
const style::LayerTypeInfo* getTypeInfo() const noexcept final;
std::unique_ptr<style::Layer> createLayer(const std::string& id, const style::conversion::Convertible& value) noexcept final;
std::unique_ptr<RenderLayer> createRenderLayer(Immutable<style::Layer::Impl>) noexcept final;
};
} // namespace mbgl

View File

@@ -0,0 +1,17 @@
#pragma once
#include <mbgl/layermanager/layer_factory.hpp>
namespace mbgl {
class CircleLayerFactory : public LayerFactory {
protected:
const style::LayerTypeInfo* getTypeInfo() const noexcept final;
std::unique_ptr<style::Layer> createLayer(const std::string& id, const style::conversion::Convertible& value) noexcept final;
std::unique_ptr<Layout> createLayout(const LayoutParameters& parameters,
std::unique_ptr<GeometryTileLayer> tileLayer,
const std::vector<Immutable<style::LayerProperties>>& group) noexcept final;
std::unique_ptr<RenderLayer> createRenderLayer(Immutable<style::Layer::Impl>) noexcept final;
};
} // namespace mbgl

View File

@@ -0,0 +1,15 @@
#pragma once
#include <mbgl/layermanager/layer_factory.hpp>
namespace mbgl {
class FillExtrusionLayerFactory : public LayerFactory {
protected:
const style::LayerTypeInfo* getTypeInfo() const noexcept final;
std::unique_ptr<style::Layer> createLayer(const std::string& id, const style::conversion::Convertible& value) noexcept final;
std::unique_ptr<Layout> createLayout(const LayoutParameters&, std::unique_ptr<GeometryTileLayer>, const std::vector<Immutable<style::LayerProperties>>&) noexcept final;
std::unique_ptr<RenderLayer> createRenderLayer(Immutable<style::Layer::Impl>) noexcept final;
};
} // namespace mbgl

View File

@@ -0,0 +1,15 @@
#pragma once
#include <mbgl/layermanager/layer_factory.hpp>
namespace mbgl {
class FillLayerFactory : public LayerFactory {
protected:
const style::LayerTypeInfo* getTypeInfo() const noexcept final;
std::unique_ptr<style::Layer> createLayer(const std::string& id, const style::conversion::Convertible& value) noexcept final;
std::unique_ptr<Layout> createLayout(const LayoutParameters&, std::unique_ptr<GeometryTileLayer>, const std::vector<Immutable<style::LayerProperties>>&) noexcept final;
std::unique_ptr<RenderLayer> createRenderLayer(Immutable<style::Layer::Impl>) noexcept final;
};
} // namespace mbgl

View File

@@ -0,0 +1,15 @@
#pragma once
#include <mbgl/layermanager/layer_factory.hpp>
namespace mbgl {
class HeatmapLayerFactory : public LayerFactory {
protected:
const style::LayerTypeInfo* getTypeInfo() const noexcept final;
std::unique_ptr<style::Layer> createLayer(const std::string& id, const style::conversion::Convertible& value) noexcept final;
std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<Immutable<style::LayerProperties>>&) noexcept final;
std::unique_ptr<RenderLayer> createRenderLayer(Immutable<style::Layer::Impl>) noexcept final;
};
} // namespace mbgl

View File

@@ -0,0 +1,14 @@
#pragma once
#include <mbgl/layermanager/layer_factory.hpp>
namespace mbgl {
class HillshadeLayerFactory : public LayerFactory {
protected:
const style::LayerTypeInfo* getTypeInfo() const noexcept final;
std::unique_ptr<style::Layer> createLayer(const std::string& id, const style::conversion::Convertible& value) noexcept final;
std::unique_ptr<RenderLayer> createRenderLayer(Immutable<style::Layer::Impl>) noexcept final;
};
} // namespace mbgl

View File

@@ -0,0 +1,42 @@
#pragma once
#include <mbgl/style/layer.hpp>
#include <vector>
namespace mbgl {
namespace style {
class LayerProperties;
} // namespace style
class Bucket;
class BucketParameters;
class GeometryTileLayer;
class Layout;
class LayoutParameters;
class RenderLayer;
/**
* @brief The LayerFactory abstract class
*
* This class is responsible for creation of the layer objects that belong to a concrete layer type.
*/
class LayerFactory {
public:
virtual ~LayerFactory() = default;
/// Returns the layer type data.
virtual const style::LayerTypeInfo* getTypeInfo() const noexcept = 0;
/// Returns a new Layer instance on success call; returns `nullptr` otherwise.
virtual std::unique_ptr<style::Layer> createLayer(const std::string& id, const style::conversion::Convertible& value) noexcept = 0;
/// Returns a new RenderLayer instance.
virtual std::unique_ptr<RenderLayer> createRenderLayer(Immutable<style::Layer::Impl>) noexcept = 0;
/// Returns a new Bucket instance on success call; returns `nullptr` otherwise.
virtual std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<Immutable<style::LayerProperties>>&) noexcept;
/// Returns a new Layout instance on success call; returns `nullptr` otherwise.
virtual std::unique_ptr<Layout> createLayout(const LayoutParameters&, std::unique_ptr<GeometryTileLayer>, const std::vector<Immutable<style::LayerProperties>>&) noexcept;
protected:
optional<std::string> getSource(const style::conversion::Convertible& value) const noexcept;
};
} // namespace mbgl

View File

@@ -0,0 +1,70 @@
#pragma once
#include <mbgl/style/layer.hpp>
#include <vector>
namespace mbgl {
namespace style {
class LayerProperties;
} // namespace style
class GeometryTileLayer;
class LayerFactory;
class RenderLayer;
class Bucket;
class BucketParameters;
class Layout;
class LayoutParameters;
/**
* @brief A singleton class responsible for creating layer instances.
*
* The LayerManager has implementation per platform. The LayerManager implementation
* defines what layer types are available and it can also disable annotations.
*
* Linker excludes the unreachable code for the disabled annotations and layers
* from the binaries, significantly reducing their size.
*/
class LayerManager {
public:
/**
* @brief A singleton getter.
*
* @return LayerManager*
*/
static LayerManager* get() noexcept;
/// Returns a new Layer instance on success call; returns `nullptr` otherwise.
std::unique_ptr<style::Layer> createLayer(const std::string& type, const std::string& id,
const style::conversion::Convertible& value, style::conversion::Error& error) noexcept;
/// Returns a new RenderLayer instance on success call; returns `nullptr` otherwise.
std::unique_ptr<RenderLayer> createRenderLayer(Immutable<style::Layer::Impl>) noexcept;
/// Returns a new Bucket instance on success call; returns `nullptr` otherwise.
std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<Immutable<style::LayerProperties>>&) noexcept;
/// Returns a new Layout instance on success call; returns `nullptr` otherwise.
std::unique_ptr<Layout> createLayout(const LayoutParameters&, std::unique_ptr<GeometryTileLayer>,
const std::vector<Immutable<style::LayerProperties>>&) noexcept;
/**
* @brief a build-time flag to enable/disable annotations in mapbox-gl-native core.
*
* At the moment, the annotations implementation in core is creating concrete
* layer instances apart from LayerManager/LayerFactory code path.
*
* So, annotations must be disabled if the LayerManager implementation does
* not provide line, fill or symbol layers (those, used by the annotations
* implementation).
*
* Note: in future, annotations implemantation will be moved from the core to platform
* SDK (see https://github.com/mapbox/mapbox-plugins-android/tree/master/plugin-annotation)
* and this flag won't be needed any more.
*/
static const bool annotationsEnabled;
protected:
virtual ~LayerManager() = default;
virtual LayerFactory* getFactory(const std::string& type) noexcept = 0;
virtual LayerFactory* getFactory(const style::LayerTypeInfo*) noexcept = 0;
};
} // namespace mbgl

View File

@@ -0,0 +1,17 @@
#pragma once
#include <mbgl/layermanager/layer_factory.hpp>
namespace mbgl {
class LineLayerFactory : public LayerFactory {
protected:
const style::LayerTypeInfo* getTypeInfo() const noexcept final;
std::unique_ptr<style::Layer> createLayer(const std::string& id, const style::conversion::Convertible& value) noexcept final;
std::unique_ptr<Layout> createLayout(const LayoutParameters& parameters,
std::unique_ptr<GeometryTileLayer> tileLayer,
const std::vector<Immutable<style::LayerProperties>>& group) noexcept final;
std::unique_ptr<RenderLayer> createRenderLayer(Immutable<style::Layer::Impl>) noexcept final;
};
} // namespace mbgl

View File

@@ -0,0 +1,15 @@
#pragma once
#include <mbgl/layermanager/layer_factory.hpp>
namespace mbgl {
class LocationIndicatorLayerFactory : public LayerFactory {
protected:
const style::LayerTypeInfo* getTypeInfo() const noexcept final;
std::unique_ptr<style::Layer> createLayer(const std::string& id,
const style::conversion::Convertible& value) noexcept final;
std::unique_ptr<RenderLayer> createRenderLayer(Immutable<style::Layer::Impl>) noexcept final;
};
} // namespace mbgl

View File

@@ -0,0 +1,14 @@
#pragma once
#include <mbgl/layermanager/layer_factory.hpp>
namespace mbgl {
class RasterLayerFactory : public LayerFactory {
protected:
const style::LayerTypeInfo* getTypeInfo() const noexcept final;
std::unique_ptr<style::Layer> createLayer(const std::string& id, const style::conversion::Convertible& value) noexcept final;
std::unique_ptr<RenderLayer> createRenderLayer(Immutable<style::Layer::Impl>) noexcept final;
};
} // namespace mbgl

View File

@@ -0,0 +1,17 @@
#pragma once
#include <mbgl/layermanager/layer_factory.hpp>
namespace mbgl {
class SymbolLayerFactory : public LayerFactory {
protected:
const style::LayerTypeInfo* getTypeInfo() const noexcept final;
std::unique_ptr<style::Layer> createLayer(const std::string& id, const style::conversion::Convertible& value) noexcept final;
std::unique_ptr<Layout> createLayout(const LayoutParameters& parameters,
std::unique_ptr<GeometryTileLayer> tileLayer,
const std::vector<Immutable<style::LayerProperties>>& group) noexcept final;
std::unique_ptr<RenderLayer> createRenderLayer(Immutable<style::Layer::Impl>) noexcept final;
};
} // namespace mbgl

View File

@@ -0,0 +1,46 @@
#pragma once
#include <mbgl/util/geo.hpp>
#include <mbgl/util/optional.hpp>
namespace mbgl {
/**
* @brief Holds options to limit what parts of a map are visible. All fields are
* optional.
*/
struct BoundOptions {
/// Sets the latitude and longitude bounds to which the camera center are constrained
BoundOptions& withLatLngBounds(LatLngBounds b) { bounds = b; return *this; }
/// Sets the minimum zoom level
BoundOptions& withMinZoom(double z) { minZoom = z; return *this; }
/// Sets the maximum zoom level
BoundOptions& withMaxZoom(double z) { maxZoom = z; return *this; }
/// Sets the minimum pitch
BoundOptions& withMinPitch(double p) {
minPitch = p;
return *this;
}
/// Sets the maximum pitch
BoundOptions& withMaxPitch(double p) {
maxPitch = p;
return *this;
}
/// Constrain the center of the camera to be within these bounds.
optional<LatLngBounds> bounds;
/// Maximum zoom level allowed.
optional<double> maxZoom;
/// Minimum zoom level allowed.
optional<double> minZoom;
/// Maximum pitch allowed in degrees.
optional<double> maxPitch;
/// Minimum pitch allowed in degrees.
optional<double> minPitch;
};
} // namespace mbgl

141
include/mbgl/map/camera.hpp Normal file
View File

@@ -0,0 +1,141 @@
#pragma once
#include <mbgl/util/chrono.hpp>
#include <mbgl/util/geo.hpp>
#include <mbgl/util/optional.hpp>
#include <mbgl/util/unitbezier.hpp>
#include <mbgl/util/vectors.hpp>
#include <functional>
namespace mbgl {
/** Various options for describing the viewpoint of a map. All fields are
optional.
Anchor and center points are mutually exclusive, with preference for the
center point when both are set.
*/
struct CameraOptions {
CameraOptions& withCenter(const optional<LatLng>& o) { center = o; return *this; }
CameraOptions& withPadding(const optional<EdgeInsets>& p) { padding = p; return *this; }
CameraOptions& withAnchor(const optional<ScreenCoordinate>& o) { anchor = o; return *this; }
CameraOptions& withZoom(const optional<double>& o) { zoom = o; return *this; }
CameraOptions& withBearing(const optional<double>& o) { bearing = o; return *this; }
CameraOptions& withPitch(const optional<double>& o) { pitch = o; return *this; }
/** Coordinate at the center of the map. */
optional<LatLng> center;
/** Padding around the interior of the view that affects the frame of
reference for `center`. */
optional<EdgeInsets> padding;
/** Point of reference for `zoom` and `angle`, assuming an origin at the
top-left corner of the view. */
optional<ScreenCoordinate> anchor;
/** Zero-based zoom level. Constrained to the minimum and maximum zoom
levels. */
optional<double> zoom;
/** Bearing, measured in degrees from true north. Wrapped to [0, 360). */
optional<double> bearing;
/** Pitch toward the horizon measured in degrees , with 0 deg resulting in a
two-dimensional map. */
optional<double> pitch;
};
constexpr bool operator==(const CameraOptions& a, const CameraOptions& b) {
return a.center == b.center
&& a.padding == b.padding
&& a.anchor == b.anchor
&& a.zoom == b.zoom
&& a.bearing == b.bearing
&& a.pitch == b.pitch;
}
constexpr bool operator!=(const CameraOptions& a, const CameraOptions& b) {
return !(a == b);
}
/** Various options for describing a transition between viewpoints with
animation. All fields are optional; the default values depend on how this
struct is used. */
struct AnimationOptions {
/** Time to animate to the viewpoint defined herein. */
optional<Duration> duration;
/** Average velocity of a flyTo() transition, measured in screenfuls per
second, assuming a linear timing curve.
A <i>screenful</i> is the visible span in pixels. It does not correspond
to a fixed physical distance but rather varies by zoom level. */
optional<double> velocity;
/** Zero-based zoom level at the peak of the flyTo() transition’s flight
path. */
optional<double> minZoom;
/** The easing timing curve of the transition. */
optional<mbgl::util::UnitBezier> easing;
/** A function that is called on each frame of the transition, just before a
screen update, except on the last frame. The first parameter indicates
the elapsed time as a percentage of the duration. */
std::function<void(double)> transitionFrameFn;
/** A function that is called once on the last frame of the transition, just
before the corresponding screen update. */
std::function<void()> transitionFinishFn;
/** Creates an animation with no options specified. */
AnimationOptions() = default;
/** Creates an animation with the specified duration. */
AnimationOptions(Duration d)
: duration(d) {}
};
/** Various options for accessing physical properties of the underlying camera entity.
A direct access to these properties allows more flexible and precise controlling of the camera
while also being fully compatible and interchangeable with CameraOptions. All fields are optional. */
struct FreeCameraOptions {
/** Position of the camera in slightly modified web mercator coordinates
- The size of 1 unit is the width of the projected world instead of the "mercator meter".
Coordinate [0, 0, 0] is the north-west corner and [1, 1, 0] is the south-east corner.
- Z coordinate is conformal and must respect minimum and maximum zoom values.
- Zoom is automatically computed from the altitude (z)
*/
optional<vec3> position = nullopt;
/** Orientation of the camera represented as a unit quaternion [x, y, z, w].
The default pose of the camera is such that the forward vector is looking up the -Z axis and
the up vector is aligned with north orientation of the map:
forward: [0, 0, -1]
up: [0, -1, 0]
right [1, 0, 0]
Orientation can be set freely but certain constraints still apply
- Orientation must be representable with only pitch and bearing.
- Pitch has an upper limit */
optional<vec4> orientation = nullopt;
/** Helper function for setting the mercator position as Lat&Lng and altitude in meters */
void setLocation(const LatLngAltitude& location);
/** Helper function for converting mercator position into Lat&Lng and altitude in meters.
This function fails to return a value if `position` is invalid or is not set */
optional<LatLngAltitude> getLocation() const;
/** Helper function for setting orientation of the camera by defining a focus point
on the map. Up vector is required in certain scenarios where bearing can't be deduced
from the viewing direction */
void lookAtPoint(const LatLng& location, const optional<vec3>& upVector = nullopt);
/** Helper function for setting the orientation of the camera as a pitch and a bearing.
Both values are in degrees */
void setPitchBearing(double pitch, double bearing);
};
} // namespace mbgl

View File

@@ -0,0 +1,26 @@
#pragma once
#include <cstdint>
namespace mbgl {
enum MapChange : uint8_t {
MapChangeRegionWillChange = 0,
MapChangeRegionWillChangeAnimated = 1,
MapChangeRegionIsChanging = 2,
MapChangeRegionDidChange = 3,
MapChangeRegionDidChangeAnimated = 4,
MapChangeWillStartLoadingMap = 5,
MapChangeDidFinishLoadingMap = 6,
MapChangeDidFailLoadingMap = 7,
MapChangeWillStartRenderingFrame = 8,
MapChangeDidFinishRenderingFrame = 9,
MapChangeDidFinishRenderingFrameFullyRendered = 10,
MapChangeWillStartRenderingMap = 11,
MapChangeDidFinishRenderingMap = 12,
MapChangeDidFinishRenderingMapFullyRendered = 13,
MapChangeDidFinishLoadingStyle = 14,
MapChangeSourceDidChange = 15
};
} // namespace mbgl

154
include/mbgl/map/map.hpp Normal file
View File

@@ -0,0 +1,154 @@
#pragma once
#include <mbgl/util/optional.hpp>
#include <mbgl/util/chrono.hpp>
#include <mbgl/map/bound_options.hpp>
#include <mbgl/map/map_observer.hpp>
#include <mbgl/map/map_options.hpp>
#include <mbgl/map/mode.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/size.hpp>
#include <mbgl/annotation/annotation.hpp>
#include <mbgl/map/camera.hpp>
#include <mbgl/util/geometry.hpp>
#include <mbgl/map/projection_mode.hpp>
#include <mbgl/storage/resource_options.hpp>
#include <cstdint>
#include <string>
#include <functional>
#include <vector>
#include <memory>
namespace mbgl {
class RendererFrontend;
namespace style {
class Image;
class Style;
} // namespace style
class Map : private util::noncopyable {
public:
explicit Map(RendererFrontend&,
MapObserver&,
const MapOptions&,
const ResourceOptions&);
~Map();
// 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)>;
void renderStill(StillImageCallback);
void renderStill(const CameraOptions&, MapDebugOptions, StillImageCallback);
// Triggers a repaint.
void triggerRepaint();
style::Style& getStyle();
const style::Style& getStyle() const;
void setStyle(std::unique_ptr<style::Style>);
// Transition
void cancelTransitions();
void setGestureInProgress(bool);
bool isGestureInProgress() const;
bool isRotating() const;
bool isScaling() const;
bool isPanning() const;
// Camera
CameraOptions getCameraOptions(const optional<EdgeInsets>& = {}) const;
void jumpTo(const CameraOptions&);
void easeTo(const CameraOptions&, const AnimationOptions&);
void flyTo(const CameraOptions&, const AnimationOptions&);
void moveBy(const ScreenCoordinate&, const AnimationOptions& = {});
void scaleBy(double scale, const optional<ScreenCoordinate>& anchor, const AnimationOptions& animation = {});
void pitchBy(double pitch, const AnimationOptions& animation = {});
void rotateBy(const ScreenCoordinate& first, const ScreenCoordinate& second, const AnimationOptions& = {});
CameraOptions cameraForLatLngBounds(const LatLngBounds&,
const EdgeInsets&,
const optional<double>& bearing = {},
const optional<double>& pitch = {}) const;
CameraOptions cameraForLatLngs(const std::vector<LatLng>&,
const EdgeInsets&,
const optional<double>& bearing = {},
const optional<double>& pitch = {}) const;
CameraOptions cameraForGeometry(const Geometry<double>&,
const EdgeInsets&,
const optional<double>& bearing = {},
const optional<double>& pitch = {}) const;
LatLngBounds latLngBoundsForCamera(const CameraOptions&) const;
LatLngBounds latLngBoundsForCameraUnwrapped(const CameraOptions&) const;
/// @name Bounds
/// @{
void setBounds(const BoundOptions& options);
/// Returns the current map bound options. All optional fields in BoundOptions are set.
BoundOptions getBounds() const;
/// @}
// Map Options
void setNorthOrientation(NorthOrientation);
void setConstrainMode(ConstrainMode);
void setViewportMode(ViewportMode);
void setSize(Size);
MapOptions getMapOptions() const;
//Projection Mode
void setProjectionMode(const ProjectionMode&);
ProjectionMode getProjectionMode() const;
// Projection
ScreenCoordinate pixelForLatLng(const LatLng&) const;
LatLng latLngForPixel(const ScreenCoordinate&) const;
std::vector<ScreenCoordinate> pixelsForLatLngs(const std::vector<LatLng>&) const;
std::vector<LatLng> latLngsForPixels(const std::vector<ScreenCoordinate>&) const;
// Annotations
void addAnnotationImage(std::unique_ptr<style::Image>);
void removeAnnotationImage(const std::string&);
double getTopOffsetPixelsForAnnotationImage(const std::string&);
AnnotationID addAnnotation(const Annotation&);
void updateAnnotation(AnnotationID, const Annotation&);
void removeAnnotation(AnnotationID);
// Tile prefetching
//
// When loading a map, if `PrefetchZoomDelta` is set to any number greater than 0, the map will
// first request a tile for `zoom - delta` in a attempt to display a full map at lower
// resolution as quick as possible. It will get clamped at the tile source minimum zoom. The
// default `delta` is 4.
void setPrefetchZoomDelta(uint8_t delta);
uint8_t getPrefetchZoomDelta() const;
// Debug
void setDebug(MapDebugOptions);
MapDebugOptions getDebug() const;
bool isFullyLoaded() const;
void dumpDebugLogs() const;
// FreeCameraOptions provides more direct access to the underlying camera entity.
// For backwards compatibility the state set using this API must be representable with
// `CameraOptions` as well. Parameters are clamped to a valid range or discarded as invalid
// if the conversion to the pitch and bearing presentation is ambiguous. For example orientation
// can be invalid if it leads to the camera being upside down or the quaternion has zero length.
void setFreeCameraOptions(const FreeCameraOptions& camera);
FreeCameraOptions getFreeCameraOptions() const;
protected:
class Impl;
const std::unique_ptr<Impl> impl;
// For testing only.
Map(std::unique_ptr<Impl>);
};
} // namespace mbgl

View File

@@ -0,0 +1,62 @@
#pragma once
#include <mbgl/style/source.hpp>
#include <mbgl/style/image.hpp>
#include <cstdint>
#include <string>
namespace mbgl {
enum class MapLoadError {
StyleParseError,
StyleLoadError,
NotFoundError,
UnknownError,
};
class MapObserver {
public:
virtual ~MapObserver() = default;
static MapObserver& nullObserver() {
static MapObserver mapObserver;
return mapObserver;
}
enum class CameraChangeMode : uint32_t {
Immediate,
Animated
};
enum class RenderMode : uint32_t {
Partial,
Full
};
struct RenderFrameStatus {
RenderMode mode;
bool needsRepaint; // In continous mode, shows that there are ongoig transitions.
bool placementChanged;
};
virtual void onCameraWillChange(CameraChangeMode) {}
virtual void onCameraIsChanging() {}
virtual void onCameraDidChange(CameraChangeMode) {}
virtual void onWillStartLoadingMap() {}
virtual void onDidFinishLoadingMap() {}
virtual void onDidFailLoadingMap(MapLoadError, const std::string&) {}
virtual void onWillStartRenderingFrame() {}
virtual void onDidFinishRenderingFrame(RenderFrameStatus) {}
virtual void onWillStartRenderingMap() {}
virtual void onDidFinishRenderingMap(RenderMode) {}
virtual void onDidFinishLoadingStyle() {}
virtual void onSourceChanged(style::Source&) {}
virtual void onDidBecomeIdle() {}
virtual void onStyleImageMissing(const std::string&) {}
// This method should return true if unused image can be removed,
// false otherwise. By default, unused image will be removed.
virtual bool onCanRemoveUnusedStyleImage(const std::string&) { return true; }
};
} // namespace mbgl

View File

@@ -0,0 +1,142 @@
#pragma once
#include <mbgl/map/mode.hpp>
#include <mbgl/util/geo.hpp>
#include <mbgl/util/size.hpp>
#include <memory>
namespace mbgl {
/**
* @brief Holds values for Map options.
*/
class MapOptions final {
public:
/**
* @brief Constructs a MapOptions object with default values.
*/
MapOptions();
~MapOptions();
MapOptions(MapOptions&&) noexcept;
/**
* @brief Sets the map rendering mode. By default, it is set to Continuous
* so the map will render as data arrives from the network and react
* immediately to state changes.
*
* @param mode Map rendering mode.
* @return MapOptions for chaining options together.
*/
MapOptions& withMapMode(MapMode mode);
/**
* @brief Gets the previously set (or default) map mode.
*
* @return map mode.
*/
MapMode mapMode() const;
/**
* @brief Sets the map constrain mode. This can be used to limit the map
* to wrap around the globe horizontally. By default, it is set to
* HeightOnly.
*
* @param mode Map constrain mode.
* @return MapOptions for chaining options together.
*/
MapOptions& withConstrainMode(ConstrainMode mode);
/**
* @brief Gets the previously set (or default) constrain mode.
*
* @return constrain mode.
*/
ConstrainMode constrainMode() const;
/**
* @brief Sets the viewport mode. This can be used to flip the vertical
* orientation of the map as some devices may use inverted orientation.
*
* @param mode Viewport mode.
* @return MapOptions for chaining options together.
*/
MapOptions& withViewportMode(ViewportMode mode);
/**
* @brief Gets the previously set (or default) viewport mode.
*
* @return viewport mode.
*/
ViewportMode viewportMode() const;
/**
* @brief Specify whether to enable cross-source symbol collision detection
* or not. By default, it is set to true.
*
* @param enableCollisions true to enable, false to disable
* @return MapOptions for chaining options together.
*/
MapOptions& withCrossSourceCollisions(bool enableCollisions);
/**
* @brief Gets the previously set (or default) crossSourceCollisions value.
*
* @return true if ecross-source symbol collision detection enabled,
* false otherwise.
*/
bool crossSourceCollisions() const;
/**
* @brief Sets the orientation of the Map. By default, it is set to
* Upwards.
*
* @param orientation Orientation of the Map.
* @return reference to MapOptions for chaining options together.
*/
MapOptions& withNorthOrientation(NorthOrientation orientation);
/**
* @brief Gets the previously set (or default) orientation.
*
* @return Map orientation.
*/
NorthOrientation northOrientation() const;
/**
* @brief Sets the size to resize the map object and renderer backend.
*
* @param size_ A size given in logical pixels.
* @return reference to MapOptions for chaining options together.
*/
MapOptions& withSize(Size size_);
/**
* @brief Gets the previously set size.
*
* @return Size.
*/
Size size() const;
/**
* @brief Sets the custom pixel ratio. By default, it is set to 1.
*
* @param ratio Pixel ratio value.
* @return reference to MapOptions for chaining options together.
*/
MapOptions& withPixelRatio(float ratio);
/**
* @brief Gets the previously set (or default) pixel ratio value.
*
* @return pixel ratio value.
*/
float pixelRatio() const;
private:
class Impl;
std::unique_ptr<Impl> impl_;
};
} // namespace mbgl

64
include/mbgl/map/mode.hpp Normal file
View File

@@ -0,0 +1,64 @@
#pragma once
#include <mbgl/util/util.hpp>
#include <mbgl/util/traits.hpp>
#include <cstdint>
namespace mbgl {
using EnumType = uint32_t;
enum class MapMode : EnumType {
Continuous, // continually updating map
Static, // a once-off still image of an arbitrary viewport
Tile // a once-off still image of a single tile
};
// We can choose to constrain the map both horizontally or vertically, or only
// vertically e.g. while panning.
enum class ConstrainMode : EnumType {
None,
HeightOnly,
WidthAndHeight,
};
// Satisfies embedding platforms that requires the viewport coordinate systems
// to be set according to its standards.
enum class ViewportMode : EnumType {
Default,
FlippedY,
};
enum class MapDebugOptions : EnumType {
NoDebug = 0,
TileBorders = 1 << 1,
ParseStatus = 1 << 2,
Timestamps = 1 << 3,
Collision = 1 << 4,
Overdraw = 1 << 5,
StencilClip = 1 << 6,
DepthBuffer = 1 << 7,
};
MBGL_CONSTEXPR MapDebugOptions operator|(MapDebugOptions lhs, MapDebugOptions rhs) {
return MapDebugOptions(mbgl::underlying_type(lhs) | mbgl::underlying_type(rhs));
}
MBGL_CONSTEXPR MapDebugOptions& operator|=(MapDebugOptions& lhs, MapDebugOptions rhs) {
return (lhs = MapDebugOptions(mbgl::underlying_type(lhs) | mbgl::underlying_type(rhs)));
}
MBGL_CONSTEXPR bool operator&(MapDebugOptions lhs, MapDebugOptions rhs) {
return mbgl::underlying_type(lhs) & mbgl::underlying_type(rhs);
}
MBGL_CONSTEXPR MapDebugOptions& operator&=(MapDebugOptions& lhs, MapDebugOptions rhs) {
return (lhs = MapDebugOptions(mbgl::underlying_type(lhs) & mbgl::underlying_type(rhs)));
}
MBGL_CONSTEXPR MapDebugOptions operator~(MapDebugOptions value) {
return MapDebugOptions(~mbgl::underlying_type(value));
}
} // namespace mbgl

View File

@@ -0,0 +1,34 @@
#pragma once
#include <mbgl/util/optional.hpp>
#include <functional>
namespace mbgl {
/**
* @brief Holds values for Axonometric rendering. All fields are
* optional.
*/
struct ProjectionMode {
ProjectionMode& withAxonometric(bool o) { axonometric = o; return *this; }
ProjectionMode& withXSkew(double o) { xSkew = o; return *this; }
ProjectionMode& withYSkew(double o) { ySkew = o; return *this; }
/**
* @brief Set to True to enable axonometric rendering, false otherwise.
*/
optional<bool> axonometric;
/**
* @brief The X skew value represents how much to skew on the x-axis.
*/
optional<double> xSkew;
/**
* @brief The Y skew value represents how much to skew on the y-axis.
*/
optional<double> ySkew;
};
} // namespace mbgl

View File

@@ -0,0 +1,14 @@
#pragma once
#include <mbgl/math/minmax.hpp>
namespace mbgl {
namespace util {
template <typename T>
T clamp(T value, T min_, T max_) {
return max(min_, min(max_, value));
}
} // namespace util
} // namespace mbgl

View File

@@ -0,0 +1,41 @@
#pragma once
#include <cmath>
#include <cstdint>
#include <type_traits>
#if defined(__ANDROID__)
#include <android/api-level.h>
#endif
namespace mbgl {
namespace util {
// Computes the log2(x) rounded up to the next integer.
// (== number of bits required to store x)
uint32_t ceil_log2(uint64_t x);
template <typename T>
T log2(T x) {
// log2() is producing wrong results on ARMv5 binaries
// running on ARMv7+ CPUs.
#if defined(__ANDROID__)
return ::log(x) / M_LN2;
#else
return ::log2(x);
#endif
}
} // namespace util
} // namespace mbgl
// log2 is not available on Android before API 18.
#if defined(__ANDROID__) && defined(__GNUC__) && \
defined(__ANDROID_API__) && __ANDROID_API__ < 18
template <typename T>
typename std::enable_if_t<std::is_floating_point<T>::value, T> log2(T x) {
return ::log(x) / M_LN2;
}
#endif

View File

@@ -0,0 +1,41 @@
#pragma once
#include <type_traits>
#include <algorithm>
#include <cmath>
namespace mbgl {
namespace util {
template <typename T>
typename std::enable_if_t<std::is_integral<T>::value, T> max(T a, T b) {
return std::max(a, b);
}
template <typename T>
typename std::enable_if_t<std::is_floating_point<T>::value, T> max(T a, T b) {
return ::fmax(a, b);
}
template <typename T, typename... Ts>
typename std::enable_if_t<std::is_arithmetic<T>::value, T> max(T a, T b, Ts... args) {
return max(a, max(b, args...));
}
template <typename T>
typename std::enable_if_t<std::is_integral<T>::value, T> min(T a, T b) {
return std::min(a, b);
}
template <typename T>
typename std::enable_if_t<std::is_floating_point<T>::value, T> min(T a, T b) {
return ::fmin(a, b);
}
template <typename T, typename... Ts>
typename std::enable_if_t<std::is_arithmetic<T>::value, T> min(T a, T b, Ts... args) {
return min(a, min(b, args...));
}
} // namespace util
} // namespace mbgl

View File

@@ -0,0 +1,24 @@
#pragma once
#include <cmath>
namespace mbgl {
namespace util {
// Constrains n to the given range (including min, excluding max) via modular
// arithmetic.
template <typename T>
T wrap(T value, T min, T max) {
if (value >= min && value < max) {
return value;
} else if (value == max) {
return min;
}
const T delta = max - min;
const T wrapped = min + std::fmod(value - min, delta);
return value < min ? wrapped + delta : wrapped;
}
} // namespace util
} // namespace mbgl

View File

@@ -0,0 +1,337 @@
#pragma once
#include <cstddef>
// Pointers to OpenGL ES 2.0 functions. They must be
// initialized by the platform at linking time.
#ifndef NDEBUG
#define MBGL_CHECK_ERROR(cmd) ([&]() { struct __MBGL_CHECK_ERROR { ~__MBGL_CHECK_ERROR() noexcept(false) { mbgl::platform::glCheckError(#cmd, __FILE__, __LINE__); } } __MBGL_CHECK_ERROR; return cmd; }())
#else
#define MBGL_CHECK_ERROR(cmd) (cmd)
#endif
namespace mbgl {
namespace platform {
using GLbitfield = unsigned int;
using GLboolean = unsigned char;
using GLchar = char;
using GLdouble = double;
using GLenum = unsigned int;
using GLfloat = float;
using GLint = int;
using GLsizei = int;
using GLubyte = unsigned char;
using GLuint = unsigned int;
using GLvoid = void;
#if defined(_WIN32)
using GLintptr = long long;
using GLsizeiptr = long long;
#else
using GLintptr = long;
using GLsizeiptr = long;
#endif
/// Pointer to glActiveTexture OpenGL function.
extern void (* const glActiveTexture)(GLenum);
/// Pointer to glAttachShader OpenGL function.
extern void (* const glAttachShader)(GLuint, GLuint);
/// Pointer to glBindAttribLocation OpenGL function.
extern void (* const glBindAttribLocation)(GLuint, GLuint, const GLchar *);
/// Pointer to glBindBuffer OpenGL function.
extern void (* const glBindBuffer)(GLenum, GLuint);
/// Pointer to glBindFramebuffer OpenGL function.
extern void (* const glBindFramebuffer)(GLenum, GLuint);
/// Pointer to glBindRenderbuffer OpenGL function.
extern void (* const glBindRenderbuffer)(GLenum, GLuint);
/// Pointer to glBindTexture OpenGL function.
extern void (* const glBindTexture)(GLenum, GLuint);
/// Pointer to glBlendColor OpenGL function.
extern void (* const glBlendColor)(GLfloat, GLfloat, GLfloat, GLfloat);
/// Pointer to glBlendEquation OpenGL function.
extern void (* const glBlendEquation)(GLenum);
/// Pointer to glBlendEquationSeparate OpenGL function.
extern void (* const glBlendEquationSeparate)(GLenum, GLenum);
/// Pointer to glBlendFunc OpenGL function.
extern void (* const glBlendFunc)(GLenum, GLenum);
/// Pointer to glBlendFuncSeparate OpenGL function.
extern void (* const glBlendFuncSeparate)(GLenum, GLenum, GLenum, GLenum);
/// Pointer to glBufferData OpenGL function.
extern void (* const glBufferData)(GLenum, GLsizeiptr, const void *, GLenum);
/// Pointer to glBufferSubData OpenGL function.
extern void (* const glBufferSubData)(GLenum, GLintptr, GLsizeiptr, const void *);
/// Pointer to glCheckFramebufferStatus OpenGL function.
extern GLenum (* const glCheckFramebufferStatus)(GLenum);
/// Pointer to glClear OpenGL function.
extern void (* const glClear)(GLbitfield);
/// Pointer to glClearColor OpenGL function.
extern void (* const glClearColor)(GLfloat, GLfloat, GLfloat, GLfloat);
/// Pointer to glClearDepthf OpenGL function.
extern void (* const glClearDepthf)(GLfloat);
/// Pointer to glClearStencil OpenGL function.
extern void (* const glClearStencil)(GLint);
/// Pointer to glColorMask OpenGL function.
extern void (* const glColorMask)(GLboolean, GLboolean, GLboolean, GLboolean);
/// Pointer to glCompileShader OpenGL function.
extern void (* const glCompileShader)(GLuint);
/// Pointer to glCompressedTexImage2D OpenGL function.
extern void (* const glCompressedTexImage2D)(GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const void *);
/// Pointer to glCompressedTexSubImage2D OpenGL function.
extern void (* const glCompressedTexSubImage2D)(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const void *);
/// Pointer to glCopyTexImage2D OpenGL function.
extern void (* const glCopyTexImage2D)(GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint);
/// Pointer to glCopyTexSubImage2D OpenGL function.
extern void (* const glCopyTexSubImage2D)(GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei);
/// Pointer to glCreateProgram OpenGL function.
extern GLuint (* const glCreateProgram)();
/// Pointer to glCreateShader OpenGL function.
extern GLuint (* const glCreateShader)(GLenum);
/// Pointer to glCullFace OpenGL function.
extern void (* const glCullFace)(GLenum);
/// Pointer to glDeleteBuffers OpenGL function.
extern void (* const glDeleteBuffers)(GLsizei, const GLuint *);
/// Pointer to glDeleteFramebuffers OpenGL function.
extern void (* const glDeleteFramebuffers)(GLsizei, const GLuint *);
/// Pointer to glDeleteProgram OpenGL function.
extern void (* const glDeleteProgram)(GLuint);
/// Pointer to glDeleteRenderbuffers OpenGL function.
extern void (* const glDeleteRenderbuffers)(GLsizei, const GLuint *);
/// Pointer to glDeleteShader OpenGL function.
extern void (* const glDeleteShader)(GLuint);
/// Pointer to glDeleteTextures OpenGL function.
extern void (* const glDeleteTextures)(GLsizei, const GLuint *);
/// Pointer to glDepthFunc OpenGL function.
extern void (* const glDepthFunc)(GLenum);
/// Pointer to glDepthMask OpenGL function.
extern void (* const glDepthMask)(GLboolean);
/// Pointer to glDepthRangef OpenGL function.
extern void (* const glDepthRangef)(GLfloat, GLfloat);
/// Pointer to glDetachShader OpenGL function.
extern void (* const glDetachShader)(GLuint, GLuint);
/// Pointer to glDisable OpenGL function.
extern void (* const glDisable)(GLenum);
/// Pointer to glDisableVertexAttribArray OpenGL function.
extern void (* const glDisableVertexAttribArray)(GLuint);
/// Pointer to glDrawArrays OpenGL function.
extern void (* const glDrawArrays)(GLenum, GLint, GLsizei);
/// Pointer to glDrawElements OpenGL function.
extern void (* const glDrawElements)(GLenum, GLsizei, GLenum, const void *);
/// Pointer to glEnable OpenGL function.
extern void (* const glEnable)(GLenum);
/// Pointer to glEnableVertexAttribArray OpenGL function.
extern void (* const glEnableVertexAttribArray)(GLuint);
/// Pointer to glFinish OpenGL function.
extern void (* const glFinish)();
/// Pointer to glFlush OpenGL function.
extern void (* const glFlush)();
/// Pointer to glFramebufferRenderbuffer OpenGL function.
extern void (* const glFramebufferRenderbuffer)(GLenum, GLenum, GLenum, GLuint);
/// Pointer to glFramebufferTexture2D OpenGL function.
extern void (* const glFramebufferTexture2D)(GLenum, GLenum, GLenum, GLuint, GLint);
/// Pointer to glFrontFace OpenGL function.
extern void (* const glFrontFace)(GLenum);
/// Pointer to glGenBuffers OpenGL function.
extern void (* const glGenBuffers)(GLsizei, GLuint *);
/// Pointer to glGenerateMipmap OpenGL function.
extern void (* const glGenerateMipmap)(GLenum);
/// Pointer to glGenFramebuffers OpenGL function.
extern void (* const glGenFramebuffers)(GLsizei, GLuint *);
/// Pointer to glGenRenderbuffers OpenGL function.
extern void (* const glGenRenderbuffers)(GLsizei, GLuint *);
/// Pointer to glGenTextures OpenGL function.
extern void (* const glGenTextures)(GLsizei, GLuint *);
/// Pointer to glGetActiveAttrib OpenGL function.
extern void (* const glGetActiveAttrib)(GLuint, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLchar *);
/// Pointer to glGetActiveUniform OpenGL function.
extern void (* const glGetActiveUniform)(GLuint, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLchar *);
/// Pointer to glGetAttachedShaders OpenGL function.
extern void (* const glGetAttachedShaders)(GLuint, GLsizei, GLsizei *, GLuint *);
/// Pointer to glGetAttribLocation OpenGL function.
extern GLint (* const glGetAttribLocation)(GLuint, const GLchar *);
/// Pointer to glGetBooleanv OpenGL function.
extern void (* const glGetBooleanv)(GLenum, GLboolean *);
/// Pointer to glGetBufferParameteriv OpenGL function.
extern void (* const glGetBufferParameteriv)(GLenum, GLenum, GLint *);
/// Pointer to glGetError OpenGL function.
extern GLenum (* const glGetError)();
/// Pointer to glGetFloatv OpenGL function.
extern void (* const glGetFloatv)(GLenum, GLfloat *);
/// Pointer to glGetFramebufferAttachmentParameteriv OpenGL function.
extern void (* const glGetFramebufferAttachmentParameteriv)(GLenum, GLenum, GLenum, GLint *);
/// Pointer to glGetIntegerv OpenGL function.
extern void (* const glGetIntegerv)(GLenum, GLint *);
/// Pointer to glGetProgramInfoLog OpenGL function.
extern void (* const glGetProgramInfoLog)(GLuint, GLsizei, GLsizei *, GLchar *);
/// Pointer to glGetProgramiv OpenGL function.
extern void (* const glGetProgramiv)(GLuint, GLenum, GLint *);
/// Pointer to glGetRenderbufferParameteriv OpenGL function.
extern void (* const glGetRenderbufferParameteriv)(GLenum, GLenum, GLint *);
/// Pointer to glGetShaderInfoLog OpenGL function.
extern void (* const glGetShaderInfoLog)(GLuint, GLsizei, GLsizei *, GLchar *);
/// Pointer to glGetShaderiv OpenGL function.
extern void (* const glGetShaderiv)(GLuint, GLenum, GLint *);
/// Pointer to glGetShaderSource OpenGL function.
extern void (* const glGetShaderSource)(GLuint, GLsizei, GLsizei *, GLchar *);
/// Pointer to glGetString OpenGL function.
extern const GLubyte *(*glGetString)(GLenum);
/// Pointer to glGetTexParameterfv OpenGL function.
extern void (* const glGetTexParameterfv)(GLenum, GLenum, GLfloat *);
/// Pointer to glGetTexParameteriv OpenGL function.
extern void (* const glGetTexParameteriv)(GLenum, GLenum, GLint *);
/// Pointer to glGetUniformfv OpenGL function.
extern void (* const glGetUniformfv)(GLuint, GLint, GLfloat *);
/// Pointer to glGetUniformiv OpenGL function.
extern void (* const glGetUniformiv)(GLuint, GLint, GLint *);
/// Pointer to glGetUniformLocation OpenGL function.
extern GLint (* const glGetUniformLocation)(GLuint, const GLchar *);
/// Pointer to glGetVertexAttribfv OpenGL function.
extern void (* const glGetVertexAttribfv)(GLuint, GLenum, GLfloat *);
/// Pointer to glGetVertexAttribiv OpenGL function.
extern void (* const glGetVertexAttribiv)(GLuint, GLenum, GLint *);
/// Pointer to glGetVertexAttribPointerv OpenGL function.
extern void (* const glGetVertexAttribPointerv)(GLuint, GLenum, void **);
/// Pointer to glHint OpenGL function.
extern void (* const glHint)(GLenum, GLenum);
/// Pointer to glIsBuffer OpenGL function.
extern GLboolean (* const glIsBuffer)(GLuint);
/// Pointer to glIsEnabled OpenGL function.
extern GLboolean (* const glIsEnabled)(GLenum);
/// Pointer to glIsFramebuffer OpenGL function.
extern GLboolean (* const glIsFramebuffer)(GLuint);
/// Pointer to glIsProgram OpenGL function.
extern GLboolean (* const glIsProgram)(GLuint);
/// Pointer to glIsRenderbuffer OpenGL function.
extern GLboolean (* const glIsRenderbuffer)(GLuint);
/// Pointer to glIsShader OpenGL function.
extern GLboolean (* const glIsShader)(GLuint);
/// Pointer to glIsTexture OpenGL function.
extern GLboolean (* const glIsTexture)(GLuint);
/// Pointer to glLineWidth OpenGL function.
extern void (* const glLineWidth)(GLfloat);
/// Pointer to glLinkProgram OpenGL function.
extern void (* const glLinkProgram)(GLuint);
/// Pointer to glPixelStorei OpenGL function.
extern void (* const glPixelStorei)(GLenum, GLint);
/// Pointer to glPolygonOffset OpenGL function.
extern void (* const glPolygonOffset)(GLfloat, GLfloat);
/// Pointer to glReadPixels OpenGL function.
extern void (* const glReadPixels)(GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, void *);
/// Pointer to glRenderbufferStorage OpenGL function.
extern void (* const glRenderbufferStorage)(GLenum, GLenum, GLsizei, GLsizei);
/// Pointer to glSampleCoverage OpenGL function.
extern void (* const glSampleCoverage)(GLfloat, GLboolean);
/// Pointer to glScissor OpenGL function.
extern void (* const glScissor)(GLint, GLint, GLsizei, GLsizei);
/// Pointer to glShaderSource OpenGL function.
extern void (* const glShaderSource)(GLuint, GLsizei, const GLchar * const*, const GLint *);
/// Pointer to glStencilFunc OpenGL function.
extern void (* const glStencilFunc)(GLenum, GLint, GLuint);
/// Pointer to glStencilFuncSeparate OpenGL function.
extern void (* const glStencilFuncSeparate)(GLenum, GLenum, GLint, GLuint);
/// Pointer to glStencilMask OpenGL function.
extern void (* const glStencilMask)(GLuint);
/// Pointer to glStencilMaskSeparate OpenGL function.
extern void (* const glStencilMaskSeparate)(GLenum, GLuint);
/// Pointer to glStencilOp OpenGL function.
extern void (* const glStencilOp)(GLenum, GLenum, GLenum);
/// Pointer to glStencilOpSeparate OpenGL function.
extern void (* const glStencilOpSeparate)(GLenum, GLenum, GLenum, GLenum);
/// Pointer to glTexImage2D OpenGL function.
extern void (* const glTexImage2D)(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const void *);
/// Pointer to glTexParameterf OpenGL function.
extern void (* const glTexParameterf)(GLenum, GLenum, GLfloat);
/// Pointer to glTexParameterfv OpenGL function.
extern void (* const glTexParameterfv)(GLenum, GLenum, const GLfloat *);
/// Pointer to glTexParameteri OpenGL function.
extern void (* const glTexParameteri)(GLenum, GLenum, GLint);
/// Pointer to glTexParameteriv OpenGL function.
extern void (* const glTexParameteriv)(GLenum, GLenum, const GLint *);
/// Pointer to glTexSubImage2D OpenGL function.
extern void (* const glTexSubImage2D)(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const void *);
/// Pointer to glUniform1f OpenGL function.
extern void (* const glUniform1f)(GLint, GLfloat);
/// Pointer to glUniform1fv OpenGL function.
extern void (* const glUniform1fv)(GLint, GLsizei, const GLfloat *);
/// Pointer to glUniform1i OpenGL function.
extern void (* const glUniform1i)(GLint, GLint);
/// Pointer to glUniform1iv OpenGL function.
extern void (* const glUniform1iv)(GLint, GLsizei, const GLint *);
/// Pointer to glUniform2f OpenGL function.
extern void (* const glUniform2f)(GLint, GLfloat, GLfloat);
/// Pointer to glUniform2fv OpenGL function.
extern void (* const glUniform2fv)(GLint, GLsizei, const GLfloat *);
/// Pointer to glUniform2i OpenGL function.
extern void (* const glUniform2i)(GLint, GLint, GLint);
/// Pointer to glUniform2iv OpenGL function.
extern void (* const glUniform2iv)(GLint, GLsizei, const GLint *);
/// Pointer to glUniform3f OpenGL function.
extern void (* const glUniform3f)(GLint, GLfloat, GLfloat, GLfloat);
/// Pointer to glUniform3fv OpenGL function.
extern void (* const glUniform3fv)(GLint, GLsizei, const GLfloat *);
/// Pointer to glUniform3i OpenGL function.
extern void (* const glUniform3i)(GLint, GLint, GLint, GLint);
/// Pointer to glUniform3iv OpenGL function.
extern void (* const glUniform3iv)(GLint, GLsizei, const GLint *);
/// Pointer to glUniform4f OpenGL function.
extern void (* const glUniform4f)(GLint, GLfloat, GLfloat, GLfloat, GLfloat);
/// Pointer to glUniform4fv OpenGL function.
extern void (* const glUniform4fv)(GLint, GLsizei, const GLfloat *);
/// Pointer to glUniform4i OpenGL function.
extern void (* const glUniform4i)(GLint, GLint, GLint, GLint, GLint);
/// Pointer to glUniform4iv OpenGL function.
extern void (* const glUniform4iv)(GLint, GLsizei, const GLint *);
/// Pointer to glUniformMatrix2fv OpenGL function.
extern void (* const glUniformMatrix2fv)(GLint, GLsizei, GLboolean, const GLfloat *);
/// Pointer to glUniformMatrix3fv OpenGL function.
extern void (* const glUniformMatrix3fv)(GLint, GLsizei, GLboolean, const GLfloat *);
/// Pointer to glUniformMatrix4fv OpenGL function.
extern void (* const glUniformMatrix4fv)(GLint, GLsizei, GLboolean, const GLfloat *);
/// Pointer to glUseProgram OpenGL function.
extern void (* const glUseProgram)(GLuint);
/// Pointer to glValidateProgram OpenGL function.
extern void (* const glValidateProgram)(GLuint);
/// Pointer to glVertexAttrib1f OpenGL function.
extern void (* const glVertexAttrib1f)(GLuint, GLfloat);
/// Pointer to glVertexAttrib1fv OpenGL function.
extern void (* const glVertexAttrib1fv)(GLuint, const GLfloat *);
/// Pointer to glVertexAttrib2f OpenGL function.
extern void (* const glVertexAttrib2f)(GLuint, GLfloat, GLfloat);
/// Pointer to glVertexAttrib2fv OpenGL function.
extern void (* const glVertexAttrib2fv)(GLuint, const GLfloat *);
/// Pointer to glVertexAttrib3f OpenGL function.
extern void (* const glVertexAttrib3f)(GLuint, GLfloat, GLfloat, GLfloat);
/// Pointer to glVertexAttrib3fv OpenGL function.
extern void (* const glVertexAttrib3fv)(GLuint, const GLfloat *);
/// Pointer to glVertexAttrib4f OpenGL function.
extern void (* const glVertexAttrib4f)(GLuint, GLfloat, GLfloat, GLfloat, GLfloat);
/// Pointer to glVertexAttrib4fv OpenGL function.
extern void (* const glVertexAttrib4fv)(GLuint, const GLfloat *);
/// Pointer to glVertexAttribPointer OpenGL function.
extern void (* const glVertexAttribPointer)(GLuint, GLint, GLenum, GLboolean, GLsizei, const void *);
/// Pointer to glViewport OpenGL function.
extern void (* const glViewport)(GLint, GLint, GLsizei, GLsizei);
#ifndef MBGL_USE_GLES2
/// Pointer to glDrawPixels OpenGL function.
extern void (* const glDrawPixels)(GLsizei, GLsizei, GLenum, GLenum, const GLvoid *);
/// Pointer to glGetDoublev OpenGL function.
extern void (* const glGetDoublev)(GLenum, GLdouble *);
/// Pointer to glPixelTransferf OpenGL function.
extern void (* const glPixelTransferf)(GLenum, GLfloat);
/// Pointer to glPixelZoom OpenGL function.
extern void (* const glPixelZoom)(GLfloat, GLfloat);
/// Pointer to glPointSize OpenGL function.
extern void (* const glPointSize)(GLfloat);
/// Pointer to glRasterPos4d OpenGL function.
extern void (* const glRasterPos4d)(GLdouble, GLdouble, GLdouble, GLdouble);
#endif
#ifndef NDEBUG
/// Check for GL errors and print on the console.
void glCheckError(const char *cmd, const char *file, int line);
#endif
} // namespace platform
} // namespace mbgl

View File

@@ -0,0 +1,48 @@
#pragma once
#include <mapbox/compatibility/value.hpp>
#include <memory>
namespace mbgl {
namespace platform {
#define DECLARE_MAPBOX_SETTING(name, value) constexpr const char* name = "mapbox_" #value
// The value for EXPERIMENTAL_THREAD_PRIORITY_* keys, must be a double.
DECLARE_MAPBOX_SETTING(EXPERIMENTAL_THREAD_PRIORITY_WORKER, thread_priority_worker);
DECLARE_MAPBOX_SETTING(EXPERIMENTAL_THREAD_PRIORITY_FILE, thread_priority_file);
DECLARE_MAPBOX_SETTING(EXPERIMENTAL_THREAD_PRIORITY_NETWORK, thread_priority_network);
DECLARE_MAPBOX_SETTING(EXPERIMENTAL_THREAD_PRIORITY_DATABASE, thread_priority_database);
// Settings class provides non-persistent, in-process key-value storage.
class Settings final {
public:
// Returns singleton instance
static Settings& getInstance() noexcept;
// Sets setting value for a specified key.
void set(const std::string& key, mapbox::base::Value value) noexcept;
// Sets multiple setting values by merging current Settings object
// with provided `values` object.
void set(const mapbox::base::ValueObject& values) noexcept;
// Returns setting value for a specified key or NullValue if element
// for specified key is missing.
mapbox::base::Value get(const std::string& key) const noexcept;
// Returns values for settings whose keys are equal to the ones provided in `keys` argument.
// Null values would be provided for keys whose elements are missing in Settings.
mapbox::base::ValueObject get(const std::vector<std::string>& keys) const noexcept;
private:
Settings();
private:
class Impl;
std::unique_ptr<Impl> impl;
};
} // namespace platform
} // namespace mbgl

View File

@@ -0,0 +1,13 @@
#pragma once
namespace mbgl {
namespace platform {
// Called when a thread is created
void attachThread();
// Called when a thread is destroyed
void detachThread();
} // namespace platform
} // namespace mbgl

View File

@@ -0,0 +1,13 @@
#pragma once
#include <chrono>
namespace mbgl {
namespace platform {
// Returns the current time. Abstracted because some platforms
// will not allow direct access to the current time via syscall.
std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds> now();
} // namespace platform
} // namespace mbgl

View File

@@ -0,0 +1,43 @@
#pragma once
#include <mbgl/util/optional.hpp>
#include <mbgl/style/filter.hpp>
#include <string>
#include <vector>
namespace mbgl {
/**
* Options for query rendered features.
*/
class RenderedQueryOptions {
public:
RenderedQueryOptions(optional<std::vector<std::string>> layerIDs_ = {},
optional<style::Filter> filter_ = {})
: layerIDs(std::move(layerIDs_)),
filter(std::move(filter_)) {}
/** layerIDs to include in the query */
optional<std::vector<std::string>> layerIDs;
optional<style::Filter> filter;
};
/**
* Options for query source features
*/
class SourceQueryOptions {
public:
SourceQueryOptions(optional<std::vector<std::string>> sourceLayers_ = {},
optional<style::Filter> filter_ = {})
: sourceLayers(std::move(sourceLayers_)),
filter(std::move(filter_)) {}
// Required for VectorSource, ignored for GeoJSONSource
optional<std::vector<std::string>> sourceLayers;
optional<style::Filter> filter;
};
} // namespace mbgl

View File

@@ -0,0 +1,113 @@
#pragma once
#include <mbgl/renderer/query.hpp>
#include <mbgl/annotation/annotation.hpp>
#include <mbgl/util/geo.hpp>
#include <mbgl/util/geojson.hpp>
#include <functional>
#include <memory>
#include <string>
#include <vector>
namespace mbgl {
class RendererObserver;
class RenderedQueryOptions;
class SourceQueryOptions;
class UpdateParameters;
namespace gfx {
class RendererBackend;
} // namespace gfx
struct PlacedSymbolData {
// Contents of the label
std::u16string key;
// If symbol contains text, text collision box in viewport coordinates
optional<mapbox::geometry::box<float>> textCollisionBox;
// If symbol contains icon, icon collision box in viewport coordinates
optional<mapbox::geometry::box<float>> iconCollisionBox;
// Symbol text was placed
bool textPlaced;
// Symbol icon was placed
bool iconPlaced;
// Symbol text or icon collision box intersects tile borders
bool intersectsTileBorder;
// Viewport padding ({viewportPadding, viewportPadding} is a coordinate of the tile's top-left corner)
float viewportPadding;
// Layer id (leader of the symbol layout group)
std::string layer;
};
class Renderer {
public:
Renderer(gfx::RendererBackend&, float pixelRatio_, const optional<std::string>& localFontFamily = {});
~Renderer();
void markContextLost();
void setObserver(RendererObserver*);
void render(const std::shared_ptr<UpdateParameters>&);
// Feature queries
std::vector<Feature> queryRenderedFeatures(const ScreenLineString&, const RenderedQueryOptions& options = {}) const;
std::vector<Feature> queryRenderedFeatures(const ScreenCoordinate& point, const RenderedQueryOptions& options = {}) const;
std::vector<Feature> queryRenderedFeatures(const ScreenBox& box, const RenderedQueryOptions& options = {}) const;
std::vector<Feature> querySourceFeatures(const std::string& sourceID, const SourceQueryOptions& options = {}) const;
AnnotationIDs queryPointAnnotations(const ScreenBox& box) const;
AnnotationIDs queryShapeAnnotations(const ScreenBox& box) const;
AnnotationIDs getAnnotationIDs(const std::vector<Feature>&) const;
// Feature extension query
FeatureExtensionValue queryFeatureExtensions(const std::string& sourceID,
const Feature& feature,
const std::string& extension,
const std::string& extensionField,
const optional<std::map<std::string, Value>>& args = {}) const;
void setFeatureState(const std::string& sourceID, const optional<std::string>& sourceLayerID,
const std::string& featureID, const FeatureState& state);
void getFeatureState(FeatureState& state,
const std::string& sourceID,
const optional<std::string>& sourceLayerID,
const std::string& featureID) const;
void removeFeatureState(const std::string& sourceID,
const optional<std::string>& sourceLayerID,
const optional<std::string>& featureID,
const optional<std::string>& stateKey);
// Debug
void dumpDebugLogs();
/**
* @brief In Tile map mode, enables or disables collecting of the placed symbols data,
* which can be obtained with `getPlacedSymbolsData()`.
*
* The placed symbols data collecting is disabled by default.
*/
void collectPlacedSymbolData(bool enable);
/**
* @brief If collecting of the placed symbols data is enabled, returns the reference
* to the `PlacedSymbolData` vector holding the collected data.
*
* Note: the returned vector gets re-populated at every `render()` call.
*
* @return collected placed symbols data
*/
const std::vector<PlacedSymbolData>& getPlacedSymbolsData() const;
// Memory
void reduceMemoryUse();
void clearData();
private:
class Impl;
std::unique_ptr<Impl> impl;
};
} // namespace mbgl

View File

@@ -0,0 +1,31 @@
#pragma once
#include <memory>
namespace mbgl {
class RendererObserver;
class UpdateParameters;
// The RenderFrontend is the bridge between the Map and
// platform used to update and observer the Renderer
//
// It hides any threading specifics and always replies on
// the original thread.
class RendererFrontend {
public:
virtual ~RendererFrontend() = default;
// Must synchronously clean up the Renderer if set
virtual void reset() = 0;
// Implementer must bind the renderer observer to the renderer in a
// appropriate manner so that the callbacks occur on the main thread
virtual void setObserver(RendererObserver&) = 0;
// Coalescing updates is up to the implementer
virtual void update(std::shared_ptr<UpdateParameters>) = 0;
};
} // namespace mbgl

View File

@@ -0,0 +1,41 @@
#pragma once
#include <cstdint>
#include <exception>
namespace mbgl {
class RendererObserver {
public:
virtual ~RendererObserver() = default;
enum class RenderMode : uint32_t {
Partial,
Full
};
// Signals that a repaint is required
virtual void onInvalidate() {}
// Resource failed to download / parse
virtual void onResourceError(std::exception_ptr) {}
// First frame
virtual void onWillStartRenderingMap() {}
// Start of frame, initial is the first frame for this map
virtual void onWillStartRenderingFrame() {}
// End of frame, booleans flags that a repaint is required and that placement changed.
virtual void onDidFinishRenderingFrame(RenderMode, bool /*repaint*/, bool /*placementChanged*/) {}
// Final frame
virtual void onDidFinishRenderingMap() {}
// Style is missing an image
using StyleImageMissingCallback = std::function<void()>;
virtual void onStyleImageMissing(const std::string&, const StyleImageMissingCallback& done) { done(); }
virtual void onRemoveUnusedStyleImages(const std::vector<std::string>&) {}
};
} // namespace mbgl

View File

@@ -0,0 +1,36 @@
#pragma once
#include <mbgl/map/camera.hpp>
#include <mbgl/util/geo.hpp>
namespace mbgl {
class UpdateParameters;
/**
* RendererState acts as a Memento object that is able to extract data out of UpdateParameters (an opaque object
* from the public API perspective).
*/
class RendererState {
public:
// Obtains a CameraOptions out of a given UpdateParameters object.
static CameraOptions getCameraOptions(const UpdateParameters&, const EdgeInsets& = {});
// Returns whether an image with the given ID exists from a given UpdateParamters object.
static bool hasImage(const UpdateParameters&, const std::string& id);
// Returns whether a layer with the given ID exists from a given UpdateParamters object.
static bool hasLayer(const UpdateParameters&, const std::string& id);
// Returns whether a source with the given ID exists from a given UpdateParamters object.
static bool hasSource(const UpdateParameters&, const std::string& id);
// Obtains the geographical coordinate out of a given screen coordinate.
static ScreenCoordinate pixelForLatLng(const UpdateParameters&, const LatLng&);
// Obtains the screen coordinate out of a given geographical coordinate.
static LatLng latLngForPixel(const UpdateParameters&, const ScreenCoordinate&);
};
} // namespace mbgl

View File

@@ -0,0 +1,240 @@
#pragma once
#include <mbgl/storage/file_source.hpp>
#include <mbgl/storage/offline.hpp>
#include <mbgl/util/expected.hpp>
#include <mbgl/util/optional.hpp>
namespace mbgl {
class ResourceOptions;
// TODO: Split DatabaseFileSource into Ambient cache and Database interfaces.
class DatabaseFileSource : public FileSource {
public:
explicit DatabaseFileSource(const ResourceOptions& options);
~DatabaseFileSource() override;
// FileSource overrides
std::unique_ptr<AsyncRequest> request(const Resource&, Callback) override;
void forward(const Resource&, const Response&, std::function<void()> callback) override;
bool canRequest(const Resource&) const override;
void setProperty(const std::string&, const mapbox::base::Value&) override;
void pause() override;
void resume() override;
// Methods common to Ambient cache and Offline functionality
/*
* Sets path of a database to be used by DatabaseFileSource and invokes provided
* callback when a database path is set.
*/
virtual void setDatabasePath(const std::string&, std::function<void()> callback);
/*
* Delete existing database and re-initialize.
*
* When the operation is complete or encounters an error, the given callback will be
* executed on the database thread; it is the responsibility of the SDK bindings
* to re-execute a user-provided callback on the main thread.
*/
virtual void resetDatabase(std::function<void(std::exception_ptr)>);
/*
* Packs the existing database file into a minimal amount of disk space.
*
* This operation has a performance impact as it will vacuum the database,
* forcing it to move pages on the filesystem.
*
* When the operation is complete or encounters an error, the given callback will be
* executed on the database thread; it is the responsibility of the SDK bindings
* to re-execute a user-provided callback on the main thread.
*/
virtual void packDatabase(std::function<void(std::exception_ptr)> callback);
/*
* Sets whether packing the database file occurs automatically after an offline
* region is deleted (deleteOfflineRegion()) or the ambient cache is cleared
* (clearAmbientCache()).
*
* By default, packing is enabled. If disabled, disk space will not be freed
* after resources are removed unless packDatabase() is explicitly called.
*/
virtual void runPackDatabaseAutomatically(bool);
// Ambient cache
/*
* Insert the provided resource into the ambient cache
*
* Consumers of the resource will expect the uncompressed version; the
* OfflineDatabase will determine whether to compress the data on disk.
* This call is asynchronous: the data may not be immediately available
* for in-progress requests, although subsequent requests should have
* access to the cached data.
*/
virtual void put(const Resource&, const Response&);
/*
* Forces revalidation of the ambient cache.
*
* Forces Mapbox GL Native to revalidate resources stored in the ambient
* cache with the tile server before using them, making sure they
* are the latest version. This is more efficient than cleaning the
* cache because if the resource is considered valid after the server
* lookup, it will not get downloaded again.
*
* Resources overlapping with offline regions will not be affected
* by this call.
*/
virtual void invalidateAmbientCache(std::function<void(std::exception_ptr)>);
/*
* Erase resources from the ambient cache, freeing storage space.
*
* Erases the ambient cache, freeing resources.
*
* Note that this operation can be potentially slow if packing the database
* occurs automatically (see runPackDatabaseAutomatically() and packDatabase()).
*
* Resources overlapping with offline regions will not be affected
* by this call.
*/
virtual void clearAmbientCache(std::function<void(std::exception_ptr)>);
/*
* Sets the maximum size in bytes for the ambient cache.
*
* This call is potentially expensive because it will try
* to trim the data in case the database is larger than the
* size defined. The size of offline regions are not affected
* by this settings, but the ambient cache will always try
* to not exceed the maximum size defined, taking into account
* the current size for the offline regions.
*
* If the maximum size is set to 50 MB and 40 MB are already
* used by offline regions, the cache size will be effectively
* 10 MB.
*
* Setting the size to 0 will disable the cache if there is no
* offline region on the database.
*
* This method should always be called before using the database,
* otherwise the default maximum size will be used.
*/
virtual void setMaximumAmbientCacheSize(uint64_t size, std::function<void(std::exception_ptr)> callback);
// Offline
/*
* Retrieve all regions in the offline database.
*
* The query will be executed asynchronously and the results passed to the given
* callback, which will be executed on the database thread; it is the responsibility
* of the SDK bindings to re-execute a user-provided callback on the main thread.
*/
virtual void listOfflineRegions(std::function<void(expected<OfflineRegions, std::exception_ptr>)>);
/*
* Create an offline region in the database.
*
* When the initial database queries have completed, the provided callback will be
* executed on the database thread; it is the responsibility of the SDK bindings
* to re-execute a user-provided callback on the main thread.
*
* Note that the resulting region will be in an inactive download state; to begin
* downloading resources, call `setOfflineRegionDownloadState(OfflineRegionDownloadState::Active)`,
* optionally registering an `OfflineRegionObserver` beforehand.
*/
virtual void createOfflineRegion(const OfflineRegionDefinition& definition,
const OfflineRegionMetadata& metadata,
std::function<void(expected<OfflineRegion, std::exception_ptr>)>);
/*
* Update an offline region metadata in the database.
*/
virtual void updateOfflineMetadata(int64_t regionID,
const OfflineRegionMetadata& metadata,
std::function<void(expected<OfflineRegionMetadata, std::exception_ptr>)>);
/*
* Register an observer to be notified when the state of the region changes.
*/
virtual void setOfflineRegionObserver(const OfflineRegion&, std::unique_ptr<OfflineRegionObserver>);
/*
* Pause or resume downloading of regional resources.
*/
virtual void setOfflineRegionDownloadState(const OfflineRegion&, OfflineRegionDownloadState);
/*
* Retrieve the current status of the region. The query will be executed
* asynchronously and the results passed to the given callback, which will be
* executed on the database thread; it is the responsibility of the SDK bindings
* to re-execute a user-provided callback on the main thread.
*/
virtual void getOfflineRegionStatus(const OfflineRegion&,
std::function<void(expected<OfflineRegionStatus, std::exception_ptr>)>) const;
/*
* Merge offline regions from a secondary database into the main offline database.
*
* When the database merge is completed, the provided callback will be
* executed on the database thread; it is the responsibility of the SDK bindings
* to re-execute a user-provided callback on the main thread.
*
* The secondary database may need to be upgraded to the latest schema. This is done
* in-place and requires write-access to `sideDatabasePath`; it is the
* responsibility of the SDK bindings to ensure that this path is writeable.
*
* Only resources and tiles that belong to a region will be copied over. Identical
* regions will be flattened into a single new region in the main database.
*
* Invokes the callback with a `MapboxOfflineTileCountExceededException` error if
* the merge operation would result in the offline tile count limit being exceeded.
*
* Merged regions may not be in a completed status if the secondary database
* does not contain all the tiles or resources required by the region definition.
*/
virtual void mergeOfflineRegions(const std::string& sideDatabasePath,
std::function<void(expected<OfflineRegions, std::exception_ptr>)>);
/*
* Remove an offline region from the database and perform any resources evictions
* necessary as a result.
*
* Eviction works by removing the least-recently requested resources not also required
* by other regions, until the database shrinks below a certain size.
*
* Note that this method takes ownership of the input, reflecting the fact that once
* region deletion is initiated, it is not legal to perform further actions with the
* region.
*
* Note that this operation can be potentially slow if packing the database occurs
* automatically (see runPackDatabaseAutomatically() and packDatabase()).
*
* When the operation is complete or encounters an error, the given callback will be
* executed on the database thread; it is the responsibility of the SDK bindings
* to re-execute a user-provided callback on the main thread.
*/
virtual void deleteOfflineRegion(const OfflineRegion&, std::function<void(std::exception_ptr)>);
/*
* Invalidate all the tiles from an offline region forcing Mapbox GL to revalidate
* the tiles with the server before using. This is more efficient than deleting the
* offline region and downloading it again because if the data on the cache matches
* the server, no new data gets transmitted.
*/
virtual void invalidateOfflineRegion(const OfflineRegion&, std::function<void(std::exception_ptr)>);
/*
* Changing or bypassing this limit without permission from Mapbox is prohibited
* by the Mapbox Terms of Service.
*/
virtual void setOfflineMapboxTileCountLimit(uint64_t) const;
private:
class Impl;
const std::unique_ptr<Impl> impl;
};
} // namespace mbgl

View File

@@ -0,0 +1,113 @@
#pragma once
#include <mbgl/storage/resource_transform.hpp>
#include <mbgl/storage/response.hpp>
#include <mapbox/compatibility/value.hpp>
#include <functional>
#include <memory>
namespace mbgl {
class AsyncRequest;
class Resource;
// TODO: Rename to ResourceProviderType
enum FileSourceType : uint8_t {
Asset,
// TODO: split to separate types
// - Cache for fast KV store (FASTER, LevelDB, RocksDB)
// - Database for read-only offline use-cases
Database,
FileSystem,
Network,
// Resource loader acts as a proxy and has logic
// for request delegation to Asset, Cache, and other
// file sources.
ResourceLoader
};
// TODO: Rename to ResourceProvider to avoid confusion with
// GeoJSONSource, RasterSource, VectorSource, CustomGeometrySource and other *Sources.
class FileSource {
public:
FileSource(const FileSource&) = delete;
FileSource& operator=(const FileSource&) = delete;
virtual ~FileSource() = default;
using Callback = std::function<void (Response)>;
// 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 AsyncRequest.
// If the request is cancelled before the callback is executed, the callback will
// not be executed.
virtual std::unique_ptr<AsyncRequest> request(const Resource&, Callback) = 0;
// Allows to forward response from one source to another.
// Optionally, callback can be provided to receive notification for forward
// operation.
//
// NOLINTNEXTLINE(performance-unnecessary-value-param)
virtual void forward(const Resource&, const Response&, std::function<void()>) {}
// When a file source supports consulting a local cache only, it must return true.
// Cache-only requests are requests that aren't as urgent, but could be useful, e.g.
// to cover part of the map while loading. The FileSource should only do cheap actions to
// retrieve the data, e.g. load it from a cache, but not from the internet.
virtual bool supportsCacheOnlyRequests() const { return false; }
// Checks whether a resource could be requested from this file source.
virtual bool canRequest(const Resource&) const = 0;
/*
* Pause file request activity.
*
* If pause is called then no revalidation or network request activity
* will occur.
*/
virtual void pause() {}
/*
* Resume file request activity.
*
* Calling resume will unpause the file source and process any tasks that
* expired while the file source was paused.
*/
virtual void resume() {}
/*
* Generic property setter / getter methods.
*/
virtual void setProperty(const std::string&, const mapbox::base::Value&){};
virtual mapbox::base::Value getProperty(const std::string&) const { return {}; };
// When supported, sets the modifier of the requested resources.
virtual void setResourceTransform(ResourceTransform) {} // NOLINT(performance-unnecessary-value-param)
protected:
FileSource() = default;
};
// Properties that may be supported by online file sources:
// Property name to set / get an access token.
// type: std::string
constexpr const char* ACCESS_TOKEN_KEY = "access-token";
// Property name to set / get base url.
// type: std::string
constexpr const char* API_BASE_URL_KEY = "api-base-url";
// Property name to set / get maximum number of concurrent requests.
// type: unsigned
constexpr const char* MAX_CONCURRENT_REQUESTS_KEY = "max-concurrent-requests";
// Properties that may be supported by database file sources:
// Property to set database mode. When set, database opens in read-only mode; database opens in read-write-create mode
// otherwise. type: bool
constexpr const char* READ_ONLY_MODE_KEY = "read-only-mode";
} // namespace mbgl

View File

@@ -0,0 +1,51 @@
#pragma once
#include <mbgl/storage/file_source.hpp>
#include <mbgl/util/pass_types.hpp>
namespace mbgl {
class ResourceOptions;
/**
* @brief A singleton class responsible for managing file sources.
*
* The FileSourceManager provides following functionality:
*
* - provides access to file sources of a specific type and configuration
* - caches previously created file sources of a (type, configuration) tuples
* - allows to register and unregister file source factories
*/
class FileSourceManager {
public:
using FileSourceFactory = std::function<std::unique_ptr<FileSource>(const ResourceOptions&)>;
/**
* @brief A singleton getter.
*
* @return FileSourceManager*
*/
static FileSourceManager* get() noexcept;
// Returns shared instance of a file source for (type, options) tuple.
// Creates new instance via registered factory if needed. If new instance cannot be
// created, nullptr would be returned.
PassRefPtr<FileSource> getFileSource(FileSourceType, const ResourceOptions&) noexcept;
// Registers file source factory for a provided FileSourceType type. If factory for the
// same type was already registered, will unregister previously registered factory.
// Provided factory must not be null.
virtual void registerFileSourceFactory(FileSourceType, FileSourceFactory&&) noexcept;
// Unregisters file source factory. If there are no registered factories for a FileSourceType
// invocation has no effect.
virtual FileSourceFactory unRegisterFileSourceFactory(FileSourceType) noexcept;
protected:
FileSourceManager();
class Impl;
std::unique_ptr<Impl> impl;
virtual ~FileSourceManager();
};
} // namespace mbgl

View File

@@ -0,0 +1,34 @@
#pragma once
#include <atomic>
#include <mutex>
#include <unordered_set>
namespace mbgl {
namespace util {
class AsyncTask;
} // namespace util
class NetworkStatus {
public:
enum class Status : uint8_t {
Online,
Offline,
};
static Status Get();
static void Set(Status);
static void Reachable();
static void Subscribe(util::AsyncTask* async);
static void Unsubscribe(util::AsyncTask* async);
private:
static std::atomic<bool> online;
static std::mutex mtx;
static std::unordered_set<util::AsyncTask*> observers;
};
} // namespace mbgl

View File

@@ -0,0 +1,235 @@
#pragma once
#include <mbgl/util/geo.hpp>
#include <mbgl/util/geometry.hpp>
#include <mbgl/util/range.hpp>
#include <mbgl/util/optional.hpp>
#include <mbgl/util/variant.hpp>
#include <mbgl/style/types.hpp>
#include <mbgl/storage/response.hpp>
#include <string>
#include <vector>
#include <functional>
namespace mbgl {
class TileID;
/*
* An offline region defined by a style URL, geographic bounding box, zoom range, and
* device pixel ratio.
*
* Both minZoom and maxZoom must be ≥ 0, and maxZoom must be ≥ minZoom.
*
* maxZoom may be ∞, in which case for each tile source, the region will include
* tiles from minZoom up to the maximum zoom level provided by that source.
*
* pixelRatio must be ≥ 0 and should typically be 1.0 or 2.0.
*/
class OfflineTilePyramidRegionDefinition {
public:
OfflineTilePyramidRegionDefinition(std::string, LatLngBounds, double, double, float, bool);
/* Private */
std::string styleURL;
LatLngBounds bounds;
double minZoom;
double maxZoom;
float pixelRatio;
bool includeIdeographs;
};
/*
* An offline region defined by a style URL, geometry, zoom range, and
* device pixel ratio.
*
* Both minZoom and maxZoom must be ≥ 0, and maxZoom must be ≥ minZoom.
*
* maxZoom may be ∞, in which case for each tile source, the region will include
* tiles from minZoom up to the maximum zoom level provided by that source.
*
* pixelRatio must be ≥ 0 and should typically be 1.0 or 2.0.
*/
class OfflineGeometryRegionDefinition {
public:
OfflineGeometryRegionDefinition(std::string styleURL, Geometry<double>, double minZoom, double maxZoom, float pixelRatio, bool includeIdeographs);
/* Private */
std::string styleURL;
Geometry<double> geometry;
double minZoom;
double maxZoom;
float pixelRatio;
bool includeIdeographs;
};
/*
* The offline region definition types supported
*/
using OfflineRegionDefinition = variant<OfflineTilePyramidRegionDefinition, OfflineGeometryRegionDefinition>;
/*
* The encoded format is private.
*/
std::string encodeOfflineRegionDefinition(const OfflineRegionDefinition&);
OfflineRegionDefinition decodeOfflineRegionDefinition(const std::string&);
/*
* Arbitrary binary region metadata. The contents are opaque to the mbgl implementation;
* it just stores and retrieves a BLOB. SDK bindings should leave the interpretation of
* this data up to the application; they _should not_ enforce a higher-level data format.
* In the future we want offline database to be portable across target platforms, and a
* platform-specific metadata format would prevent that.
*/
using OfflineRegionMetadata = std::vector<uint8_t>;
/*
* A region is either inactive (not downloading, but previously-downloaded
* resources are available for use), or active (resources are being downloaded
* or will be downloaded, if necessary, when network access is available).
*
* This state is independent of whether or not the complete set of resources
* is currently available for offline use. To check if that is the case, use
* `OfflineRegionStatus::complete()`.
*/
enum class OfflineRegionDownloadState {
Inactive,
Active
};
/*
* A region's status includes its active/inactive state as well as counts
* of the number of resources that have completed downloading, their total
* size in bytes, and the total number of resources that are required.
*
* Note that the total required size in bytes is not currently available. A
* future API release may provide an estimate of this number.
*/
class OfflineRegionStatus {
public:
OfflineRegionDownloadState downloadState = OfflineRegionDownloadState::Inactive;
/**
* The number of resources that have been fully downloaded and are ready for
* offline access.
*/
uint64_t completedResourceCount = 0;
/**
* The cumulative size, in bytes, of all resources (inclusive of tiles) that have
* been fully downloaded.
*/
uint64_t completedResourceSize = 0;
/**
* The number of tiles that are known to be required for this region. This is a
* subset of `completedResourceCount`.
*/
uint64_t completedTileCount = 0;
/**
* The number of tiles that are known to be required for this region.
*/
uint64_t requiredTileCount = 0;
/**
* The cumulative size, in bytes, of all tiles that have been fully downloaded.
* This is a subset of `completedResourceSize`.
*/
uint64_t completedTileSize = 0;
/**
* The number of resources that are known to be required for this region. See the
* documentation for `requiredResourceCountIsPrecise` for an important caveat
* about this number.
*/
uint64_t requiredResourceCount = 0;
/**
* This property is true when the value of requiredResourceCount is a precise
* count of the number of required resources, and false when it is merely a lower
* bound.
*
* Specifically, it is false during early phases of an offline download. Once
* style and tile sources have been downloaded, it is possible to calculate the
* precise number of required resources, at which point it is set to true.
*/
bool requiredResourceCountIsPrecise = false;
bool complete() const {
return completedResourceCount >= requiredResourceCount;
}
};
/*
* A region can have a single observer, which gets notified whenever a change
* to the region's status occurs.
*/
class OfflineRegionObserver {
public:
virtual ~OfflineRegionObserver() = default;
/*
* Implement this method to be notified of a change in the status of an
* offline region. Status changes include any change in state of the members
* of OfflineRegionStatus.
*
* Note that this method will be executed on the database thread; it is the
* responsibility of the SDK bindings to wrap this object in an interface that
* re-executes the user-provided implementation on the main thread.
*/
virtual void statusChanged(OfflineRegionStatus) {}
/*
* Implement this method to be notified of errors encountered while downloading
* regional resources. Such errors may be recoverable; for example the implementation
* will attempt to re-request failed resources based on an exponential backoff
* algorithm, or when it detects that network access has been restored.
*
* Note that this method will be executed on the database thread; it is the
* responsibility of the SDK bindings to wrap this object in an interface that
* re-executes the user-provided implementation on the main thread.
*/
virtual void responseError(Response::Error) {} // NOLINT(performance-unnecessary-value-param)
/*
* Implement this method to be notified when the limit on the number of Mapbox
* tiles stored for offline regions has been reached.
*
* Once the limit has been reached, the SDK will not download further offline
* tiles from Mapbox APIs until existing tiles have been removed.
*
* This limit does not apply to non-Mapbox tile sources.
*
* Note that this method will be executed on the database thread; it is the
* responsibility of the SDK bindings to wrap this object in an interface that
* re-executes the user-provided implementation on the main thread.
*/
virtual void mapboxTileCountLimitExceeded(uint64_t /* limit */) {}
};
class OfflineRegion {
public:
~OfflineRegion();
OfflineRegion() = delete;
int64_t getID() const;
const OfflineRegionDefinition& getDefinition() const;
const OfflineRegionMetadata& getMetadata() const;
private:
friend class OfflineDatabase;
OfflineRegion(int64_t id,
OfflineRegionDefinition,
OfflineRegionMetadata);
int64_t id;
OfflineRegionDefinition definition;
OfflineRegionMetadata metadata;
};
using OfflineRegions = std::vector<OfflineRegion>;
} // namespace mbgl

View File

@@ -0,0 +1,27 @@
#pragma once
#include <mbgl/storage/file_source.hpp>
#include <mbgl/util/optional.hpp>
namespace mbgl {
class OnlineFileSource : public FileSource {
public:
OnlineFileSource();
~OnlineFileSource() override;
private:
// FileSource overrides
std::unique_ptr<AsyncRequest> request(const Resource&, Callback) override;
bool canRequest(const Resource&) const override;
void pause() override;
void resume() override;
void setProperty(const std::string&, const mapbox::base::Value&) override;
mapbox::base::Value getProperty(const std::string&) const override;
void setResourceTransform(ResourceTransform) override;
class Impl;
const std::unique_ptr<Impl> impl;
};
} // namespace mbgl

View File

@@ -0,0 +1,108 @@
#pragma once
#include <mbgl/storage/response.hpp>
#include <mbgl/util/bitmask_operations.hpp>
#include <mbgl/util/optional.hpp>
#include <mbgl/util/font_stack.hpp>
#include <mbgl/util/tileset.hpp>
#include <string>
namespace mbgl {
class Resource {
public:
enum Kind : uint8_t {
Unknown = 0,
Style,
Source,
Tile,
Glyphs,
SpriteImage,
SpriteJSON,
Image
};
enum class Priority : bool {
Regular,
Low
};
enum class Usage : bool {
Online,
Offline
};
enum class StoragePolicy : bool { Permanent, Volatile };
struct TileData {
std::string urlTemplate;
uint8_t pixelRatio;
int32_t x;
int32_t y;
int8_t z;
};
enum class LoadingMethod : uint8_t {
None = 0b00,
Cache = 0b01,
Network = 0b10,
CacheOnly = Cache,
NetworkOnly = Network,
All = Cache | Network,
};
Resource(Kind kind_,
std::string url_,
optional<TileData> tileData_ = {},
LoadingMethod loadingMethod_ = LoadingMethod::All)
: kind(kind_),
loadingMethod(loadingMethod_),
url(std::move(url_)),
tileData(std::move(tileData_)) {
}
void setPriority(Priority p) { priority = p; }
void setUsage(Usage u) { usage = u; }
bool hasLoadingMethod(LoadingMethod method) const;
static Resource style(const std::string& url);
static Resource source(const std::string& url);
static Resource tile(const std::string& urlTemplate,
float pixelRatio,
int32_t x,
int32_t y,
int8_t z,
Tileset::Scheme scheme,
LoadingMethod = LoadingMethod::All);
static Resource glyphs(const std::string& urlTemplate,
const FontStack& fontStack,
const std::pair<uint16_t, uint16_t>& glyphRange);
static Resource spriteImage(const std::string& base, float pixelRatio);
static Resource spriteJSON(const std::string& base, float pixelRatio);
static Resource image(const std::string& url);
Kind kind;
LoadingMethod loadingMethod;
Usage usage{ Usage::Online };
Priority priority{ Priority::Regular };
std::string url;
// Includes auxiliary data if this is a tile request.
optional<TileData> tileData;
optional<Timestamp> priorModified = {};
optional<Timestamp> priorExpires = {};
optional<std::string> priorEtag = {};
std::shared_ptr<const std::string> priorData;
Duration minimumUpdateInterval{Duration::zero()};
StoragePolicy storagePolicy{StoragePolicy::Permanent};
};
inline bool Resource::hasLoadingMethod(Resource::LoadingMethod method) const {
return (loadingMethod & method);
}
} // namespace mbgl

View File

@@ -0,0 +1,122 @@
#pragma once
#include <memory>
#include <string>
namespace mbgl {
/**
* @brief Holds values for resource options.
*/
class ResourceOptions final {
public:
/**
* @brief Constructs a ResourceOptions object with default values.
*/
ResourceOptions();
~ResourceOptions();
ResourceOptions(ResourceOptions&&) noexcept;
ResourceOptions clone() const;
/**
* @brief Sets the Mapbox access token - see https://docs.mapbox.com/help/how-mapbox-works/access-tokens/ for details.
*
* @param token Mapbox access token.
* @return ResourceOptions for chaining options together.
*/
ResourceOptions& withAccessToken(std::string token);
/**
* @brief Gets the previously set (or default) Mapbox access token.
*
* @return const std::string& Mapbox access token.
*/
const std::string& accessToken() const;
/**
* @brief Sets the API base URL. Default is https://api.mapbox.com for Mapbox.
*
* @param baseURL API base URL.
* @return ResourceOptions for chaining options together.
*/
ResourceOptions& withBaseURL(std::string baseURL);
/**
* @brief Gets the previously set (or default) API base URL.
*
* @return const std::string& API base URL.
*/
const std::string& baseURL() const;
/**
* @brief Sets the cache path.
*
* @param path Cache path.
* @return ResourceOptions for chaining options together.
*/
ResourceOptions& withCachePath(std::string path);
/**
* @brief Gets the previously set (or default) cache path.
*
* @return cache path
*/
const std::string& cachePath() const;
/**
* @brief Sets the asset path, which is the root directory from where
* the asset:// scheme gets resolved in a style.
*
* @param path Asset path.
* @return ResourceOptions for chaining options together.
*/
ResourceOptions& withAssetPath(std::string path);
/**
* @brief Gets the previously set (or default) asset path.
*
* @return asset path
*/
const std::string& assetPath() const;
/**
* @brief Sets the maximum cache size.
*
* @param size Cache maximum size in bytes.
* @return reference to ResourceOptions for chaining options together.
*/
ResourceOptions& withMaximumCacheSize(uint64_t size);
/**
* @brief Gets the previously set (or default) maximum allowed cache size.
*
* @return maximum allowed cache database size in bytes.
*/
uint64_t maximumCacheSize() const;
/**
* @brief Sets the platform context. A platform context is usually an object
* that assists the creation of a file source.
*
* @param context Platform context.
* @return reference to ResourceOptions for chaining options together.
*/
ResourceOptions& withPlatformContext(void* context);
/**
* @brief Gets the previously set (or default) platform context.
*
* @return Platform context.
*/
void* platformContext() const;
private:
ResourceOptions(const ResourceOptions&);
class Impl;
std::unique_ptr<Impl> impl_;
};
} // namespace mbgl

View File

@@ -0,0 +1,23 @@
#pragma once
#include <mbgl/storage/resource.hpp>
#include <functional>
#include <string>
namespace mbgl {
class ResourceTransform {
public:
using FinishedCallback = std::function<void(const std::string&)>;
using TransformCallback = std::function<void(Resource::Kind kind, const std::string& url, FinishedCallback)>;
ResourceTransform(TransformCallback = {});
void transform(Resource::Kind, const std::string& url, FinishedCallback);
explicit operator bool() const { return bool(transformCallback); }
private:
TransformCallback transformCallback;
};
} // namespace mbgl

View File

@@ -0,0 +1,72 @@
#pragma once
#include <mbgl/util/chrono.hpp>
#include <mbgl/util/optional.hpp>
#include <string>
#include <memory>
namespace mbgl {
class Response {
public:
Response() = default;
Response(const Response&);
Response& operator=(const Response&);
public:
class Error;
// When this object is empty, the response was successful.
std::unique_ptr<const Error> error;
// This is set to true for 204 Not Modified responses, and, for backward compatibility,
// for 404 Not Found responses for tiles.
bool noContent = false;
// This is set to true for 304 Not Modified responses.
bool notModified = false;
// This is set to true when the server requested that no expired resources be used by
// specifying "Cache-Control: must-revalidate".
bool mustRevalidate = false;
// The actual data of the response. Present only for non-error, non-notModified responses.
std::shared_ptr<const std::string> data;
optional<Timestamp> modified;
optional<Timestamp> expires;
optional<std::string> etag;
bool isFresh() const {
return expires ? *expires > util::now() : !error;
}
// Indicates whether we are allowed to use this response according to HTTP caching rules.
// It may or may not be stale.
bool isUsable() const {
return !mustRevalidate || (expires && *expires > util::now());
}
};
class Response::Error {
public:
enum class Reason : uint8_t {
Success = 1,
NotFound = 2,
Server = 3,
Connection = 4,
RateLimit = 5,
Other = 6,
} reason = Reason::Other;
// An error message from the request handler, e.g. a server message or a system message
// informing the user about the reason for the failure.
std::string message;
optional<Timestamp> retryAfter;
public:
Error(Reason, std::string = "", optional<Timestamp> = {});
};
} // namespace mbgl

View File

@@ -0,0 +1,49 @@
#pragma once
#include <mbgl/util/variant.hpp>
#include <mbgl/style/undefined.hpp>
#include <mbgl/style/expression/expression.hpp>
namespace mbgl {
namespace style {
/*
* Special-case implementation of (a subset of) the PropertyValue<T> interface
* used for building the HeatmapColor paint property traits class.
*/
class ColorRampPropertyValue {
private:
std::shared_ptr<expression::Expression> value;
friend bool operator==(const ColorRampPropertyValue& lhs, const ColorRampPropertyValue& rhs) {
return (lhs.isUndefined() && rhs.isUndefined()) || (lhs.value && rhs.value && *(lhs.value) == *(rhs.value));
}
friend bool operator!=(const ColorRampPropertyValue& lhs, const ColorRampPropertyValue& rhs) {
return !(lhs == rhs);
}
public:
ColorRampPropertyValue() : value(nullptr) {}
ColorRampPropertyValue(std::shared_ptr<expression::Expression> value_) : value(std::move(value_)) {}
bool isUndefined() const { return value == nullptr; }
// noop, needed for batch evaluation of paint property values to compile
template <typename Evaluator>
Color evaluate(const Evaluator&, TimePoint = {}) const { return {}; }
Color evaluate(double rampEvaluationParameter) const {
const auto result = value->evaluate(expression::EvaluationContext({}, nullptr, {rampEvaluationParameter}));
return *expression::fromExpressionValue<Color>(*result);
}
bool isDataDriven() const { return false; }
bool hasDataDrivenPropertyDifference(const ColorRampPropertyValue&) const { return false; }
const expression::Expression& getExpression() const { return *value; }
};
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,29 @@
#pragma once
#include <string>
namespace mbgl {
namespace style {
namespace conversion {
// This is a forward-declaration only header intended to minimize dependencies and to improve
// compilation speed. In order to specialize implementations and get access to the actual
// implementation, include <mbgl/style/conversion_impl.hpp>.
struct Error { std::string message; };
template <typename T>
class ConversionTraits;
class Convertible;
template <typename T, typename Enable = void>
struct Converter;
template <typename T, typename Enable = void>
struct ValueFactory;
} // namespace conversion
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,17 @@
#pragma once
#include <mbgl/style/color_ramp_property_value.hpp>
#include <mbgl/style/conversion.hpp>
namespace mbgl {
namespace style {
namespace conversion {
template <>
struct Converter<ColorRampPropertyValue> {
optional<ColorRampPropertyValue> operator()(const Convertible& value, Error& error, bool /* allowDataExpressions */ = false, bool /* convertTokens */ = false) const;
};
} // namespace conversion
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,69 @@
#pragma once
#include <mbgl/style/conversion.hpp>
#include <mbgl/style/types.hpp>
#include <mbgl/util/color.hpp>
#include <mbgl/util/enum.hpp>
#include <mbgl/util/string.hpp>
#include <array>
#include <string>
#include <vector>
namespace mbgl {
namespace style {
namespace conversion {
template <>
struct Converter<bool> {
optional<bool> operator()(const Convertible& value, Error& error) const;
};
template <>
struct Converter<float> {
optional<float> operator()(const Convertible& value, Error& error) const;
};
template <>
struct Converter<std::string> {
optional<std::string> operator()(const Convertible& value, Error& error) const;
};
template <class T>
struct Converter<T, typename std::enable_if_t<std::is_enum<T>::value>> {
optional<T> operator()(const Convertible& value, Error& error) const;
};
template <class T>
struct Converter<std::vector<T>, typename std::enable_if_t<std::is_enum<T>::value>> {
optional<std::vector<T>> operator()(const Convertible& value, Error& error) const;
};
template <>
struct Converter<Color> {
optional<Color> operator()(const Convertible& value, Error& error) const;
};
template <size_t N>
struct Converter<std::array<float, N>> {
optional<std::array<float, N>> operator()(const Convertible& value, Error& error) const;
};
template <>
struct Converter<std::vector<float>> {
optional<std::vector<float>> operator()(const Convertible& value, Error& error) const;
};
template <size_t N>
struct Converter<std::array<double, N>> {
optional<std::array<double, N>> operator()(const Convertible& value, Error& error) const;
};
template <>
struct Converter<std::vector<std::string>> {
optional<std::vector<std::string>> operator()(const Convertible& value, Error& error) const;
};
} // namespace conversion
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,19 @@
#pragma once
#include <mbgl/style/conversion.hpp>
#include <mbgl/util/geo.hpp>
#include <mbgl/util/optional.hpp>
namespace mbgl {
namespace style {
namespace conversion {
template<>
struct Converter<LatLng> {
public:
optional<LatLng> operator() (const Convertible& value, Error& error) const;
};
} // namespace conversion
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,18 @@
#pragma once
#include <mbgl/style/conversion.hpp>
#include <mbgl/style/sources/custom_geometry_source.hpp>
#include <mbgl/util/optional.hpp>
namespace mbgl {
namespace style {
namespace conversion {
template <>
struct Converter<CustomGeometrySource::Options> {
optional<CustomGeometrySource::Options> operator()(const Convertible& value, Error& error) const;
};
} // namespace conversion
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,19 @@
#pragma once
#include <mbgl/style/filter.hpp>
#include <mbgl/style/conversion.hpp>
#include <mbgl/util/optional.hpp>
namespace mbgl {
namespace style {
namespace conversion {
template <>
struct Converter<Filter> {
public:
optional<Filter> operator()(const Convertible& value, Error& error) const;
};
} // namespace conversion
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,25 @@
#pragma once
#include <mbgl/style/property_expression.hpp>
#include <mbgl/style/conversion/constant.hpp>
#include <mbgl/style/conversion.hpp>
#include <mbgl/style/expression/expression.hpp>
#include <mbgl/style/expression/value.hpp>
namespace mbgl {
namespace style {
namespace conversion {
bool hasTokens(const std::string&);
std::unique_ptr<expression::Expression> convertTokenStringToFormatExpression(const std::string&);
std::unique_ptr<expression::Expression> convertTokenStringToImageExpression(const std::string&);
std::unique_ptr<expression::Expression> convertTokenStringToExpression(const std::string&);
optional<std::unique_ptr<expression::Expression>> convertFunctionToExpression(expression::type::Type, const Convertible&, Error&, bool convertTokens);
template <class T>
optional<PropertyExpression<T>> convertFunctionToExpression(const Convertible& value, Error& error, bool convertTokens);
} // namespace conversion
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,22 @@
#pragma once
#include <mbgl/util/geojson.hpp>
#include <mbgl/style/conversion.hpp>
#include <mbgl/util/optional.hpp>
namespace mbgl {
namespace style {
namespace conversion {
// Workaround until https://github.com/mapbox/mapbox-gl-native/issues/5623 is done.
optional<GeoJSON> parseGeoJSON(const std::string&, Error&);
template <>
struct Converter<GeoJSON> {
public:
optional<GeoJSON> operator()(const Convertible&, Error&) const;
};
} // namespace conversion
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,18 @@
#pragma once
#include <mbgl/style/sources/geojson_source.hpp>
#include <mbgl/style/conversion.hpp>
#include <mbgl/util/optional.hpp>
namespace mbgl {
namespace style {
namespace conversion {
template <>
struct Converter<GeoJSONOptions> {
optional<GeoJSONOptions> operator()(const Convertible& value, Error& error) const;
};
} // namespace conversion
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,14 @@
#pragma once
#include <mbgl/style/conversion.hpp>
#include <string>
namespace mbgl {
namespace style {
namespace conversion {
std::string getJSONType(const Convertible& value);
} // namespace conversion
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,23 @@
#pragma once
#include <mbgl/style/layer.hpp>
#include <mbgl/style/conversion.hpp>
#include <mbgl/util/optional.hpp>
#include <memory>
namespace mbgl {
namespace style {
namespace conversion {
template <>
struct Converter<std::unique_ptr<Layer>> {
public:
optional<std::unique_ptr<Layer>> operator()(const Convertible& value, Error& error) const;
};
optional<Error> setPaintProperties(Layer& layer, const Convertible& value);
} // namespace conversion
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,19 @@
#pragma once
#include <mbgl/style/light.hpp>
#include <mbgl/style/conversion.hpp>
#include <mbgl/util/optional.hpp>
namespace mbgl {
namespace style {
namespace conversion {
template <>
struct Converter<Light> {
public:
optional<Light> operator()(const Convertible& value, Error& error) const;
};
} // namespace conversion
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,18 @@
#pragma once
#include <mbgl/style/position.hpp>
#include <mbgl/style/conversion.hpp>
#include <mbgl/util/optional.hpp>
namespace mbgl {
namespace style {
namespace conversion {
template <>
struct Converter<Position> {
optional<Position> operator()(const Convertible& value, Error& error) const;
};
} // namespace conversion
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,56 @@
#pragma once
#include <mbgl/style/property_value.hpp>
#include <mbgl/style/conversion/constant.hpp>
#include <mbgl/style/conversion/function.hpp>
#include <mbgl/style/conversion.hpp>
#include <mbgl/style/expression/value.hpp>
#include <mbgl/style/expression/is_constant.hpp>
#include <mbgl/style/expression/is_expression.hpp>
#include <mbgl/style/expression/parsing_context.hpp>
#include <mbgl/style/expression/literal.hpp>
namespace mbgl {
namespace style {
namespace conversion {
template <class T>
struct Converter<PropertyValue<T>> {
optional<PropertyValue<T>> operator()(const Convertible& value, Error& error, bool allowDataExpressions, bool convertTokens) const;
template <class S>
PropertyValue<T> maybeConvertTokens(const S& t) const {
return PropertyValue<T>(t);
};
PropertyValue<T> maybeConvertTokens(const std::string& t) const {
return hasTokens(t)
? PropertyValue<T>(PropertyExpression<T>(convertTokenStringToExpression(t)))
: PropertyValue<T>(t);
}
PropertyValue<T> maybeConvertTokens(const expression::Formatted& t) const {
// This only works with a single-section `Formatted` created automatically
// by parsing a plain-text `text-field` property.
// Token conversion happens later than the initial string->Formatted conversion
// General purpose `format` expressions with embedded tokens are not supported
const std::string& firstUnformattedSection = t.sections[0].text;
return hasTokens(firstUnformattedSection)
? PropertyValue<T>(PropertyExpression<T>(convertTokenStringToFormatExpression(firstUnformattedSection)))
: PropertyValue<T>(t);
}
PropertyValue<T> maybeConvertTokens(const expression::Image& image) const {
return hasTokens(image.id())
? PropertyValue<T>(PropertyExpression<T>(convertTokenStringToImageExpression(image.id())))
: PropertyValue<T>(image);
}
};
template <>
struct Converter<PropertyValue<std::array<double, 3>>, void> {
optional<PropertyValue<std::array<double, 3>>> operator()(const Convertible& value, Error& error, bool, bool) const;
};
} // namespace conversion
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,18 @@
#pragma once
#include <mbgl/style/conversion.hpp>
#include <mbgl/style/rotation.hpp>
#include <mbgl/util/optional.hpp>
namespace mbgl {
namespace style {
namespace conversion {
template <>
struct Converter<style::Rotation> {
optional<style::Rotation> operator()(const Convertible& value, Error& error) const;
};
} // namespace conversion
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,21 @@
#pragma once
#include <mbgl/style/source.hpp>
#include <mbgl/style/conversion.hpp>
#include <mbgl/util/optional.hpp>
#include <memory>
namespace mbgl {
namespace style {
namespace conversion {
template <>
struct Converter<std::unique_ptr<Source>> {
public:
optional<std::unique_ptr<Source>> operator()(const Convertible& value, Error& error, const std::string& id) const;
};
} // namespace conversion
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,19 @@
#pragma once
#include <mbgl/util/tileset.hpp>
#include <mbgl/style/conversion.hpp>
#include <mbgl/util/optional.hpp>
namespace mbgl {
namespace style {
namespace conversion {
template <>
struct Converter<Tileset> {
public:
optional<Tileset> operator()(const Convertible& value, Error& error) const;
};
} // namespace conversion
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,19 @@
#pragma once
#include <mbgl/style/transition_options.hpp>
#include <mbgl/style/conversion.hpp>
#include <mbgl/util/optional.hpp>
namespace mbgl {
namespace style {
namespace conversion {
template <>
struct Converter<TransitionOptions> {
public:
optional<TransitionOptions> operator()(const Convertible& value, Error& error) const;
};
} // namespace conversion
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,384 @@
#pragma once
#include <mbgl/style/color_ramp_property_value.hpp>
#include <mbgl/style/conversion.hpp>
#include <mbgl/style/expression/image.hpp>
#include <mbgl/style/layer.hpp>
#include <mbgl/style/property_value.hpp>
#include <mbgl/style/rotation.hpp>
#include <mbgl/style/transition_options.hpp>
#include <mbgl/util/feature.hpp>
#include <mbgl/util/geojson.hpp>
#include <mbgl/util/optional.hpp>
#include <mbgl/util/traits.hpp>
#include <mapbox/compatibility/value.hpp>
#include <array>
#include <chrono>
#include <string>
#include <type_traits>
namespace mbgl {
namespace style {
namespace conversion {
/*
The `conversion` namespace defines conversions from JSON structures conforming to the schema defined by
the Mapbox Style Specification, to the various C++ types that form the C++ model of that domain:
* `std::unique_ptr<Source>`
* `std::unique_ptr<Layer>`
* `Filter`
* `PropertyValue<T>`
A single template function serves as the public interface:
template <class T>
optional<T> convert(const Convertible& input, Error& error);
Where `T` is one of the above types. If the conversion fails, the result is empty, and the
error parameter includes diagnostic text suitable for presentation to a library user. Otherwise,
a filled optional is returned.
`Convertible` is a type that encapsulates a special form of polymorphism over various underlying types that
can serve as input to the conversion algorithm. For instance, on macOS, we need to support
conversion from both RapidJSON types, and a JSON structure represented with `NSArray`/`NSDictionary`/etc.
On Qt, we need to support conversion from RapidJSON types and QVariant.
We don't want to use traditional forms of polymorphism to accomplish this:
* Compile time polymorphism using a template parameter for the actual value type leads to
excessive code bloat and long compile times.
* Runtime polymorphism using virtual methods requires extra heap allocation and ubiquitous
use of std::unique_ptr, unsuitable for this performance-sensitive code.
Therefore, we're using a custom implementation of runtime polymorphism where we manually create and
dispatch through a table of function pointers (vtable), while keeping the storage for any of the possible
underlying types inline on the stack, using `std::aligned_storage`.
For a given underlying type T, an explicit specialization of `ConversionTraits<T>` must be provided. This
specialization must provide the following static methods:
* `isUndefined(v)` -- returns a boolean indication whether `v` is undefined or a JSON null
* `isArray(v)` -- returns a boolean indicating whether `v` represents a JSON array
* `arrayLength(v)` -- called only if `isArray(v)`; returns a size_t length
* `arrayMember(v)` -- called only if `isArray(v)`; returns `V` or `V&`
* `isObject(v)` -- returns a boolean indicating whether `v` represents a JSON object
* `objectMember(v, name)` -- called only if `isObject(v)`; `name` is `const char *`; return value:
* is true when evaluated in a boolean context iff the named member exists
* is convertable to a `V` or `V&` when dereferenced
* `eachMember(v, [] (const std::string&, const V&) -> optional<Error> {...})` -- called
only if `isObject(v)`; calls the provided lambda once for each key and value of the object;
short-circuits if any call returns an `Error`
* `toBool(v)` -- returns `optional<bool>`, absence indicating `v` is not a JSON boolean
* `toNumber(v)` -- returns `optional<float>`, absence indicating `v` is not a JSON number
* `toDouble(v)` -- returns `optional<double>`, absence indicating `v` is not a JSON number
* `toString(v)` -- returns `optional<std::string>`, absence indicating `v` is not a JSON string
* `toValue(v)` -- returns `optional<Value>`, a variant type, for generic conversion,
absence indicating `v` is not a boolean, number, or string. Numbers should be converted to
unsigned integer, signed integer, or floating point, in descending preference.
In addition, the type T must be move-constructable. And finally, `Convertible::Storage`, a typedef for
`std::aligned_storage_t`, must be large enough to satisfy the memory requirements for any of the
possible underlying types. (A static assert will fail if this is not the case.)
`Convertible` itself is movable, but not copyable. A moved-from `Convertible` is in an invalid state;
you must not do anything with it except let it go out of scope.
*/
template <typename T>
class ConversionTraits;
class Convertible {
public:
template <typename T>
// NOLINTNEXTLINE(bugprone-forwarding-reference-overload)
Convertible(T&& value) : vtable(vtableForType<std::decay_t<T>>()) {
static_assert(sizeof(Storage) >= sizeof(std::decay_t<T>), "Storage must be large enough to hold value type");
new (static_cast<void*>(&storage)) std::decay_t<T>(std::forward<T>(value));
}
Convertible(Convertible&& v) noexcept : vtable(v.vtable) {
// NOLINTNEXTLINE(performance-move-const-arg)
vtable->move(std::move(v.storage), storage);
}
~Convertible() {
vtable->destroy(storage);
}
Convertible& operator=(Convertible&& v) noexcept {
if (this != &v) {
vtable->destroy(storage);
vtable = v.vtable;
// NOLINTNEXTLINE(performance-move-const-arg)
vtable->move(std::move(v.storage), storage);
}
return *this;
}
Convertible() = delete;
Convertible(const Convertible&) = delete;
Convertible& operator=(const Convertible&) = delete;
friend inline bool isUndefined(const Convertible& v) {
assert(v.vtable);
return v.vtable->isUndefined(v.storage);
}
friend inline bool isArray(const Convertible& v) {
assert(v.vtable);
return v.vtable->isArray(v.storage);
}
friend inline std::size_t arrayLength(const Convertible& v) {
assert(v.vtable);
return v.vtable->arrayLength(v.storage);
}
friend inline Convertible arrayMember(const Convertible& v, std::size_t i) {
assert(v.vtable);
return v.vtable->arrayMember(v.storage, i);
}
friend inline bool isObject(const Convertible& v) {
assert(v.vtable);
return v.vtable->isObject(v.storage);
}
friend inline optional<Convertible> objectMember(const Convertible& v, const char * name) {
assert(v.vtable);
return v.vtable->objectMember(v.storage, name);
}
friend inline optional<Error> eachMember(const Convertible& v, const std::function<optional<Error> (const std::string&, const Convertible&)>& fn) {
assert(v.vtable);
return v.vtable->eachMember(v.storage, fn);
}
friend inline optional<bool> toBool(const Convertible& v) {
assert(v.vtable);
return v.vtable->toBool(v.storage);
}
friend inline optional<float> toNumber(const Convertible& v) {
assert(v.vtable);
return v.vtable->toNumber(v.storage);
}
friend inline optional<double> toDouble(const Convertible& v) {
assert(v.vtable);
return v.vtable->toDouble(v.storage);
}
friend inline optional<std::string> toString(const Convertible& v) {
assert(v.vtable);
return v.vtable->toString(v.storage);
}
friend inline optional<Value> toValue(const Convertible& v) {
assert(v.vtable);
return v.vtable->toValue(v.storage);
}
friend inline optional<GeoJSON> toGeoJSON(const Convertible& v, Error& error) {
assert(v.vtable);
return v.vtable->toGeoJSON(v.storage, error);
}
private:
#if __ANDROID__
// Android: JSValue* or mbgl::android::Value
using Storage = std::aligned_storage_t<32, 8>;
#elif __QT__
// Qt: JSValue* or QVariant
using Storage = std::aligned_storage_t<32, 8>;
#else
// Node: JSValue* or v8::Local<v8::Value>
// iOS/macOS: JSValue* or id
using Storage = std::aligned_storage_t<8, 8>;
#endif
struct VTable {
void (*move) (Storage&& src, Storage& dest);
void (*destroy) (Storage&);
bool (*isUndefined) (const Storage&);
bool (*isArray) (const Storage&);
std::size_t (*arrayLength) (const Storage&);
Convertible (*arrayMember) (const Storage&, std::size_t);
bool (*isObject) (const Storage&);
optional<Convertible> (*objectMember) (const Storage&, const char *);
optional<Error> (*eachMember) (const Storage&, const std::function<optional<Error> (const std::string&, const Convertible&)>&);
optional<bool> (*toBool) (const Storage&);
optional<float> (*toNumber) (const Storage&);
optional<double> (*toDouble) (const Storage&);
optional<std::string> (*toString) (const Storage&);
optional<Value> (*toValue) (const Storage&);
// https://github.com/mapbox/mapbox-gl-native/issues/5623
optional<GeoJSON> (*toGeoJSON) (const Storage&, Error&);
};
// Extracted this function from the table below to work around a GCC bug with differing
// visibility settings for capturing lambdas: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80947
template <typename T>
static auto vtableEachMember(const Storage& s, const std::function<optional<Error>(const std::string&, const Convertible&)>& fn) {
return ConversionTraits<T>::eachMember(reinterpret_cast<const T&>(s), [&](const std::string& k, T&& v) {
return fn(k, Convertible(std::move(v)));
});
}
template <typename T>
static VTable* vtableForType() {
using Traits = ConversionTraits<T>;
static VTable vtable = {
[] (Storage&& src, Storage& dest) {
new (static_cast<void*>(&dest)) T(reinterpret_cast<T&&>(src));
},
[] (Storage& s) {
reinterpret_cast<T&>(s).~T();
},
[] (const Storage& s) {
return Traits::isUndefined(reinterpret_cast<const T&>(s));
},
[] (const Storage& s) {
return Traits::isArray(reinterpret_cast<const T&>(s));
},
[] (const Storage& s) {
return Traits::arrayLength(reinterpret_cast<const T&>(s));
},
[] (const Storage& s, std::size_t i) {
return Convertible(Traits::arrayMember(reinterpret_cast<const T&>(s), i));
},
[] (const Storage& s) {
return Traits::isObject(reinterpret_cast<const T&>(s));
},
[] (const Storage& s, const char * key) {
optional<T> member = Traits::objectMember(reinterpret_cast<const T&>(s), key);
if (member) {
return optional<Convertible>(Convertible(std::move(*member)));
} else {
return optional<Convertible>();
}
},
vtableEachMember<T>,
[] (const Storage& s) {
return Traits::toBool(reinterpret_cast<const T&>(s));
},
[] (const Storage& s) {
return Traits::toNumber(reinterpret_cast<const T&>(s));
},
[] (const Storage& s) {
return Traits::toDouble(reinterpret_cast<const T&>(s));
},
[] (const Storage& s) {
return Traits::toString(reinterpret_cast<const T&>(s));
},
[] (const Storage& s) {
return Traits::toValue(reinterpret_cast<const T&>(s));
},
[] (const Storage& s, Error& err) {
return Traits::toGeoJSON(reinterpret_cast<const T&>(s), err);
}
};
return &vtable;
}
VTable* vtable;
Storage storage;
};
template <class T, class...Args>
optional<T> convert(const Convertible& value, Error& error, Args&&...args) {
return Converter<T>()(value, error, std::forward<Args>(args)...);
}
template <>
struct ValueFactory<ColorRampPropertyValue> {
static Value make(const ColorRampPropertyValue& value) { return value.getExpression().serialize(); }
};
template <>
struct ValueFactory<TransitionOptions> {
static Value make(const TransitionOptions& value) { return value.serialize(); }
};
template <>
struct ValueFactory<Color> {
static Value make(const Color& color) { return color.serialize(); }
};
template <typename T>
struct ValueFactory<T, typename std::enable_if<(!std::is_enum<T>::value && !is_linear_container<T>::value)>::type> {
static Value make(const T& arg) { return {arg}; }
};
template <typename T>
struct ValueFactory<T, typename std::enable_if<std::is_enum<T>::value>::type> {
static Value make(T arg) { return {Enum<T>::toString(arg)}; }
};
template <typename T>
struct ValueFactory<T, typename std::enable_if<is_linear_container<T>::value>::type> {
static Value make(const T& arg) {
mapbox::base::ValueArray result;
result.reserve(arg.size());
for (const auto& item : arg) {
result.emplace_back(ValueFactory<std::decay_t<decltype(item)>>::make(item));
}
return result;
}
};
template <>
struct ValueFactory<Position> {
static Value make(const Position& position) {
return ValueFactory<std::array<float, 3>>::make(position.getSpherical());
}
};
template <>
struct ValueFactory<Rotation> {
static Value make(const Rotation& rotation) { return {rotation.getAngle()}; }
};
template <typename T>
Value makeValue(T&& arg) {
return ValueFactory<std::decay_t<T>>::make(std::forward<T>(arg));
}
template <typename T>
StyleProperty makeStyleProperty(const PropertyValue<T>& value) {
return value.match([](const Undefined&) -> StyleProperty { return {}; },
[](const Color& c) -> StyleProperty {
return {makeValue(c), StyleProperty::Kind::Expression};
},
[](const PropertyExpression<T>& fn) -> StyleProperty {
return {fn.getExpression().serialize(), StyleProperty::Kind::Expression};
},
[](const auto& t) -> StyleProperty {
return {makeValue(t), StyleProperty::Kind::Constant};
});
}
inline StyleProperty makeStyleProperty(const TransitionOptions& value) {
if (!value.isDefined()) return {};
return {makeValue(value), StyleProperty::Kind::Transition};
}
inline StyleProperty makeStyleProperty(const ColorRampPropertyValue& value) {
if (value.isUndefined()) return {};
return {makeValue(value), StyleProperty::Kind::Expression};
}
} // namespace conversion
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,36 @@
#pragma once
#include <mbgl/style/expression/expression.hpp>
#include <mbgl/style/expression/parsing_context.hpp>
#include <mbgl/style/conversion.hpp>
#include <memory>
#include <vector>
namespace mbgl {
namespace style {
namespace expression {
class Assertion : public Expression {
public:
Assertion(type::Type type_, std::vector<std::unique_ptr<Expression>> inputs_);
static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext& ctx);
EvaluationResult evaluate(const EvaluationContext& params) const override;
void eachChild(const std::function<void(const Expression&)>& visit) const override;
bool operator==(const Expression& e) const override;
std::vector<optional<Value>> possibleOutputs() const override;
mbgl::Value serialize() const override;
std::string getOperator() const override;
private:
std::vector<std::unique_ptr<Expression>> inputs;
};
} // namespace expression
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,45 @@
#pragma once
#include <mbgl/style/expression/expression.hpp>
#include <mbgl/style/conversion.hpp>
#include <memory>
namespace mbgl {
namespace style {
namespace expression {
class At : public Expression {
public:
At(std::unique_ptr<Expression> index_, std::unique_ptr<Expression> input_) :
Expression(Kind::At, input_->getType().get<type::Array>().itemType),
index(std::move(index_)),
input(std::move(input_))
{}
static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext& ctx);
EvaluationResult evaluate(const EvaluationContext& params) const override;
void eachChild(const std::function<void(const Expression&)>&) const override;
bool operator==(const Expression& e) const override {
if (e.getKind() == Kind::At) {
auto rhs = static_cast<const At*>(&e);
return *index == *(rhs->index) && *input == *(rhs->input);
}
return false;
}
std::vector<optional<Value>> possibleOutputs() const override {
return { nullopt };
}
std::string getOperator() const override { return "at"; }
private:
std::unique_ptr<Expression> index;
std::unique_ptr<Expression> input;
};
} // namespace expression
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,52 @@
#pragma once
#include <mbgl/style/expression/expression.hpp>
#include <mbgl/style/conversion.hpp>
#include <memory>
namespace mbgl {
namespace style {
namespace expression {
class Any : public Expression {
public:
Any(std::vector<std::unique_ptr<Expression>> inputs_) :
Expression(Kind::Any, type::Boolean),
inputs(std::move(inputs_))
{}
static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext& ctx);
EvaluationResult evaluate(const EvaluationContext& params) const override;
void eachChild(const std::function<void(const Expression&)>& visit) const override;
bool operator==(const Expression& e) const override;
std::vector<optional<Value>> possibleOutputs() const override;
std::string getOperator() const override { return "any"; }
private:
std::vector<std::unique_ptr<Expression>> inputs;
};
class All : public Expression {
public:
All(std::vector<std::unique_ptr<Expression>> inputs_) :
Expression(Kind::All, type::Boolean),
inputs(std::move(inputs_))
{}
static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext& ctx);
EvaluationResult evaluate(const EvaluationContext& params) const override;
void eachChild(const std::function<void(const Expression&)>& visit) const override;
bool operator==(const Expression& e) const override;
std::vector<optional<Value>> possibleOutputs() const override;
std::string getOperator() const override { return "all"; }
private:
std::vector<std::unique_ptr<Expression>> inputs;
};
} // namespace expression
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,39 @@
#pragma once
#include <mbgl/style/expression/expression.hpp>
#include <mbgl/style/expression/parsing_context.hpp>
#include <mbgl/style/conversion.hpp>
#include <memory>
#include <utility>
#include <vector>
namespace mbgl {
namespace style {
namespace expression {
class Case : public Expression {
public:
using Branch = std::pair<std::unique_ptr<Expression>, std::unique_ptr<Expression>>;
Case(type::Type type_, std::vector<Branch> branches_, std::unique_ptr<Expression> otherwise_)
: Expression(Kind::Case, std::move(type_)), branches(std::move(branches_)), otherwise(std::move(otherwise_)) {}
static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext& ctx);
EvaluationResult evaluate(const EvaluationContext& params) const override;
void eachChild(const std::function<void(const Expression&)>& visit) const override;
bool operator==(const Expression& e) const override;
std::vector<optional<Value>> possibleOutputs() const override;
std::string getOperator() const override { return "case"; }
private:
std::vector<Branch> branches;
std::unique_ptr<Expression> otherwise;
};
} // namespace expression
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,17 @@
#pragma once
#include <mbgl/style/expression/type.hpp>
#include <mbgl/util/optional.hpp>
#include <memory>
namespace mbgl {
namespace style {
namespace expression {
namespace type {
optional<std::string> checkSubtype(const Type& expected, const Type& t);
} // namespace type
} // namespace expression
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,48 @@
#pragma once
#include <mbgl/style/expression/expression.hpp>
#include <mbgl/style/expression/parsing_context.hpp>
#include <mbgl/style/conversion.hpp>
#include <memory>
#include <map>
namespace mbgl {
namespace style {
namespace expression {
class Coalesce : public Expression {
public:
using Args = std::vector<std::unique_ptr<Expression>>;
Coalesce(const type::Type& type_, Args args_) :
Expression(Kind::Coalesce, type_),
args(std::move(args_))
{}
static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext& ctx);
EvaluationResult evaluate(const EvaluationContext& params) const override;
void eachChild(const std::function<void(const Expression&)>& visit) const override;
bool operator==(const Expression& e) const override;
std::vector<optional<Value>> possibleOutputs() const override;
std::size_t getLength() const {
return args.size();
}
Expression* getChild(std::size_t i) const {
return args.at(i).get();
}
std::string getOperator() const override { return "coalesce"; }
private:
Args args;
};
} // namespace expression
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,37 @@
#pragma once
#include <mbgl/style/expression/expression.hpp>
#include <mbgl/style/conversion.hpp>
#include <memory>
#include <vector>
namespace mbgl {
namespace style {
namespace expression {
class Coercion : public Expression {
public:
Coercion(type::Type type_, std::vector<std::unique_ptr<Expression>> inputs_);
static ParseResult parse(const mbgl::style::conversion::Convertible& value, ParsingContext& ctx);
EvaluationResult evaluate(const EvaluationContext& params) const override;
void eachChild(const std::function<void(const Expression&)>& visit) const override;
mbgl::Value serialize() const override;
bool operator==(const Expression& e) const override;
std::vector<optional<Value>> possibleOutputs() const override;
std::string getOperator() const override;
private:
EvaluationResult (*coerceSingleValue) (const Value& v);
std::vector<std::unique_ptr<Expression>> inputs;
};
} // namespace expression
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,27 @@
#pragma once
#include <mbgl/i18n/collator.hpp>
#include <mbgl/util/optional.hpp>
#include <string>
namespace mbgl {
namespace style {
namespace expression {
class Collator {
public:
Collator(bool caseSensitive, bool diacriticSensitive, const optional<std::string>& locale = {});
bool operator==(const Collator& other) const;
int compare(const std::string& lhs, const std::string& rhs) const;
std::string resolvedLocale() const;
private:
platform::Collator collator;
};
} // namespace expression
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,44 @@
#pragma once
#include <mbgl/style/expression/expression.hpp>
#include <mbgl/style/expression/parsing_context.hpp>
#include <mbgl/style/conversion.hpp>
#include <memory>
namespace mbgl {
namespace style {
namespace expression {
class CollatorExpression : public Expression {
public:
CollatorExpression(std::unique_ptr<Expression> caseSensitive,
std::unique_ptr<Expression> diacriticSensitive,
optional<std::unique_ptr<Expression>> locale);
EvaluationResult evaluate(const EvaluationContext&) const override;
static ParseResult parse(const mbgl::style::conversion::Convertible&, ParsingContext&);
void eachChild(const std::function<void(const Expression&)>&) const override;
bool operator==(const Expression& e) const override;
std::vector<optional<Value>> possibleOutputs() const override {
// Technically the set of possible outputs is the combinatoric set of Collators produced
// by all possibleOutputs of locale/caseSensitive/diacriticSensitive
// But for the primary use of Collators in comparison operators, we ignore the Collator's
// possibleOutputs anyway, so we can get away with leaving this undefined for now.
return { nullopt };
}
mbgl::Value serialize() const override;
std::string getOperator() const override { return "collator"; }
private:
std::unique_ptr<Expression> caseSensitive;
std::unique_ptr<Expression> diacriticSensitive;
optional<std::unique_ptr<Expression>> locale;
};
} // namespace expression
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,68 @@
#pragma once
#include <mbgl/style/expression/collator_expression.hpp>
#include <mbgl/style/expression/expression.hpp>
#include <mbgl/style/expression/parsing_context.hpp>
#include <mbgl/style/conversion.hpp>
#include <memory>
namespace mbgl {
namespace style {
namespace expression {
ParseResult parseComparison(const mbgl::style::conversion::Convertible&, ParsingContext&);
class BasicComparison : public Expression {
public:
using CompareFunctionType = bool (*)(const Value&, const Value&);
BasicComparison(
std::string op,
std::unique_ptr<Expression> lhs,
std::unique_ptr<Expression> rhs);
void eachChild(const std::function<void(const Expression&)>& visit) const override;
bool operator==(const Expression&) const override;
EvaluationResult evaluate(const EvaluationContext&) const override;
std::vector<optional<Value>> possibleOutputs() const override;
std::string getOperator() const override;
private:
std::string op;
CompareFunctionType compare;
std::unique_ptr<Expression> lhs;
std::unique_ptr<Expression> rhs;
bool needsRuntimeTypeCheck;
};
class CollatorComparison : public Expression {
public:
using CompareFunctionType = bool (*)(const std::string&, const std::string&, const Collator&);
CollatorComparison(
std::string op,
std::unique_ptr<Expression> lhs,
std::unique_ptr<Expression> rhs,
std::unique_ptr<Expression> collator);
void eachChild(const std::function<void(const Expression&)>& visit) const override;
bool operator==(const Expression&) const override;
EvaluationResult evaluate(const EvaluationContext&) const override;
std::vector<optional<Value>> possibleOutputs() const override;
std::string getOperator() const override;
private:
std::string op;
CompareFunctionType compare;
std::unique_ptr<Expression> lhs;
std::unique_ptr<Expression> rhs;
std::unique_ptr<Expression> collator;
bool needsRuntimeTypeCheck;
};
} // namespace expression
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,59 @@
#pragma once
#include <mbgl/style/expression/expression.hpp>
#include <mbgl/style/expression/parsing_context.hpp>
#include <mbgl/style/expression/type.hpp>
#include <mbgl/style/expression/value.hpp>
#include <mbgl/style/conversion.hpp>
#include <mbgl/util/optional.hpp>
#include <memory>
#include <vector>
namespace mbgl {
namespace style {
namespace expression {
namespace detail {
struct SignatureBase;
} // namespace detail
/*
CompoundExpression provides a mechanism for implementing an expression
simply by providing a list of pure functions of the form
(const T0& arg0, const T1& arg1, ...) -> Result<U> where T0, T1, ..., U are
member types of mbgl::style::expression::Value.
The majority of expressions specified in the style-spec are implemented in
this fashion (see compound_expression.cpp).
*/
class CompoundExpression : public Expression {
public:
CompoundExpression(const detail::SignatureBase&, std::vector<std::unique_ptr<Expression>>);
std::string getOperator() const override;
EvaluationResult evaluate(const EvaluationContext& evaluationParams) const override;
std::vector<optional<Value>> possibleOutputs() const override;
void eachChild(const std::function<void(const Expression&)>& visit) const override;
bool operator==(const Expression& e) const override;
optional<std::size_t> getParameterCount() const;
static bool exists(const std::string& name);
protected:
const detail::SignatureBase& signature;
std::vector<std::unique_ptr<Expression>> args;
};
ParseResult parseCompoundExpression(const std::string& name,
const mbgl::style::conversion::Convertible& value,
ParsingContext& ctx);
ParseResult createCompoundExpression(const std::string& name,
std::vector<std::unique_ptr<Expression>> args,
ParsingContext& ctx);
} // namespace expression
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,37 @@
#pragma once
#include <mapbox/cheap_ruler.hpp>
#include <mbgl/style/expression/expression.hpp>
#include <mbgl/util/geojson.hpp>
namespace mbgl {
namespace style {
namespace expression {
class Distance final : public Expression {
public:
Distance(GeoJSON geoJSONSource_, Feature::geometry_type geometries_);
~Distance() override;
EvaluationResult evaluate(const EvaluationContext&) const override;
static ParseResult parse(const mbgl::style::conversion::Convertible&, ParsingContext&);
void eachChild(const std::function<void(const Expression&)>&) const override {}
bool operator==(const Expression& e) const override;
std::vector<optional<Value>> possibleOutputs() const override;
mbgl::Value serialize() const override;
std::string getOperator() const override;
private:
GeoJSON geoJSONSource;
Feature::geometry_type geometries;
};
} // namespace expression
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,99 @@
#pragma once
#include <mbgl/style/expression/expression.hpp>
#include <mbgl/style/expression/interpolator.hpp>
#include <mbgl/style/expression/value.hpp>
#include <mbgl/util/ignore.hpp>
#include <initializer_list>
#include <memory>
#include <string>
namespace mbgl {
namespace style {
namespace expression {
namespace dsl {
// This convenience API does little to no expression validation or type-checking, and is intended for
// use only by test and other non-production code.
template <class... Args>
std::vector<std::unique_ptr<Expression>> vec(Args... args) {
std::vector<std::unique_ptr<Expression>> result;
util::ignore({ (result.push_back(std::move(args)), 0)... });
return result;
}
std::unique_ptr<Expression> createExpression(const char* expr);
std::unique_ptr<Expression> createExpression(const mbgl::style::conversion::Convertible& expr);
std::unique_ptr<Expression> error(std::string);
std::unique_ptr<Expression> literal(const char* value);
std::unique_ptr<Expression> literal(const Value& value);
std::unique_ptr<Expression> literal(std::initializer_list<double> value);
std::unique_ptr<Expression> literal(std::initializer_list<const char*> value);
std::unique_ptr<Expression> assertion(const type::Type&,
std::unique_ptr<Expression>,
std::unique_ptr<Expression> def = nullptr);
std::unique_ptr<Expression> number(std::unique_ptr<Expression>,
std::unique_ptr<Expression> def = nullptr);
std::unique_ptr<Expression> string(std::unique_ptr<Expression>,
std::unique_ptr<Expression> def = nullptr);
std::unique_ptr<Expression> boolean(std::unique_ptr<Expression>,
std::unique_ptr<Expression> def = nullptr);
std::unique_ptr<Expression> toColor(std::unique_ptr<Expression>,
std::unique_ptr<Expression> def = nullptr);
std::unique_ptr<Expression> toString(std::unique_ptr<Expression>,
std::unique_ptr<Expression> def = nullptr);
std::unique_ptr<Expression> toFormatted(std::unique_ptr<Expression>,
std::unique_ptr<Expression> def = nullptr);
std::unique_ptr<Expression> toImage(std::unique_ptr<Expression>, std::unique_ptr<Expression> def = nullptr);
std::unique_ptr<Expression> get(const char* value);
std::unique_ptr<Expression> get(std::unique_ptr<Expression>);
std::unique_ptr<Expression> id();
std::unique_ptr<Expression> zoom();
std::unique_ptr<Expression> eq(std::unique_ptr<Expression>, std::unique_ptr<Expression>);
std::unique_ptr<Expression> ne(std::unique_ptr<Expression>, std::unique_ptr<Expression>);
std::unique_ptr<Expression> gt(std::unique_ptr<Expression>, std::unique_ptr<Expression>);
std::unique_ptr<Expression> lt(std::unique_ptr<Expression>, std::unique_ptr<Expression>);
std::unique_ptr<Expression> step(std::unique_ptr<Expression> input,
std::unique_ptr<Expression> output0,
double input1, std::unique_ptr<Expression> output1);
Interpolator linear();
Interpolator exponential(double base);
Interpolator cubicBezier(double x1, double y1, double x2, double y2);
std::unique_ptr<Expression> interpolate(Interpolator interpolator,
std::unique_ptr<Expression> input,
double input1, std::unique_ptr<Expression> output1);
std::unique_ptr<Expression> interpolate(Interpolator interpolator,
std::unique_ptr<Expression> input,
double input1, std::unique_ptr<Expression> output1,
double input2, std::unique_ptr<Expression> output2);
std::unique_ptr<Expression> interpolate(Interpolator interpolator,
std::unique_ptr<Expression> input,
double input1, std::unique_ptr<Expression> output1,
double input2, std::unique_ptr<Expression> output2,
double input3, std::unique_ptr<Expression> output3);
std::unique_ptr<Expression> concat(std::vector<std::unique_ptr<Expression>> inputs);
std::unique_ptr<Expression> format(const char* value);
std::unique_ptr<Expression> format(std::unique_ptr<Expression>);
std::unique_ptr<Expression> image(const char* value);
std::unique_ptr<Expression> image(std::unique_ptr<Expression>);
} // namespace dsl
} // namespace expression
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,39 @@
#pragma once
#include <mbgl/style/expression/expression.hpp>
#include <string>
namespace mbgl {
namespace style {
namespace expression {
class Error : public Expression {
public:
Error(std::string message_)
: Expression(Kind::Error, type::Error),
message(std::move(message_)) {}
void eachChild(const std::function<void(const Expression&)>&) const override {}
bool operator==(const Expression& e) const override {
return e.getKind() == Kind::Error;
}
EvaluationResult evaluate(const EvaluationContext&) const override {
return EvaluationError{message};
}
std::vector<optional<Value>> possibleOutputs() const override {
return {};
}
std::string getOperator() const override { return "error"; }
private:
std::string message;
};
} // namespace expression
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,262 @@
#pragma once
#include <mbgl/style/expression/parsing_context.hpp>
#include <mbgl/style/expression/type.hpp>
#include <mbgl/style/expression/value.hpp>
#include <mbgl/tile/tile_id.hpp>
#include <mbgl/util/color.hpp>
#include <mbgl/util/optional.hpp>
#include <mbgl/util/variant.hpp>
#include <array>
#include <vector>
#include <memory>
namespace mbgl {
class GeometryTileFeature;
namespace style {
namespace expression {
class EvaluationError {
public:
std::string message;
};
class EvaluationContext {
public:
EvaluationContext() = default;
explicit EvaluationContext(float zoom_) : zoom(zoom_) {}
explicit EvaluationContext(GeometryTileFeature const * feature_) : feature(feature_) {}
EvaluationContext(float zoom_, GeometryTileFeature const* feature_) : zoom(zoom_), feature(feature_) {}
EvaluationContext(optional<mbgl::Value> accumulated_, GeometryTileFeature const * feature_) :
accumulated(std::move(accumulated_)), feature(feature_)
{}
EvaluationContext(float zoom_, GeometryTileFeature const* feature_, const FeatureState* state_)
: zoom(zoom_), feature(feature_), featureState(state_) {}
EvaluationContext(optional<float> zoom_, GeometryTileFeature const * feature_, optional<double> colorRampParameter_) :
zoom(std::move(zoom_)), feature(feature_), colorRampParameter(std::move(colorRampParameter_))
{}
EvaluationContext& withFormattedSection(const Value* formattedSection_) noexcept {
formattedSection = formattedSection_;
return *this;
};
EvaluationContext& withFeatureState(const FeatureState* featureState_) noexcept {
featureState = featureState_;
return *this;
};
EvaluationContext& withAvailableImages(const std::set<std::string>* availableImages_) noexcept {
availableImages = availableImages_;
return *this;
};
EvaluationContext& withCanonicalTileID(const mbgl::CanonicalTileID* canonical_) noexcept {
canonical = canonical_;
return *this;
};
optional<float> zoom;
optional<mbgl::Value> accumulated;
GeometryTileFeature const* feature = nullptr;
optional<double> colorRampParameter;
// Contains formatted section object, std::unordered_map<std::string, Value>.
const Value* formattedSection = nullptr;
const FeatureState* featureState = nullptr;
const std::set<std::string>* availableImages = nullptr;
const mbgl::CanonicalTileID* canonical = nullptr;
};
template <typename T>
class Result : private variant<EvaluationError, T> {
public:
using variant<EvaluationError, T>::variant;
using Value = T;
Result() = default;
explicit operator bool () const {
return this->template is<T>();
}
// optional does some type trait magic for this one, so this might
// be problematic as is.
const T* operator->() const {
assert(this->template is<T>());
return std::addressof(this->template get<T>());
}
T* operator->() {
assert(this->template is<T>());
return std::addressof(this->template get<T>());
}
T& operator*() {
assert(this->template is<T>());
return this->template get<T>();
}
const T& operator*() const {
assert(this->template is<T>());
return this->template get<T>();
}
const EvaluationError& error() const {
assert(this->template is<EvaluationError>());
return this->template get<EvaluationError>();
}
};
class EvaluationResult : public Result<Value> {
public:
using Result::Result; // NOLINT
EvaluationResult() = default;
EvaluationResult(const std::array<double, 4>& arr) :
Result(toExpressionValue(arr))
{}
// used only for the special (private) "error" expression
EvaluationResult(const type::ErrorType&) {
assert(false);
}
};
/*
Expression is an abstract class that serves as an interface and base class
for particular expression implementations.
CompoundExpression implements the majority of expressions in the spec by
inferring the argument and output from a simple function (const T0& arg0,
const T1& arg1, ...) -> Result<U> where T0, T1, ..., U are member types of
mbgl::style::expression::Value.
The other Expression subclasses (Let, Curve, Match, etc.) exist in order to
implement expressions that need specialized parsing, type checking, or
evaluation logic that can't be handled by CompoundExpression's inference
mechanism.
Each Expression subclass also provides a static
ParseResult ExpressionClass::parse(const V&, ParsingContext),
which handles parsing a style-spec JSON representation of the expression.
*/
enum class Kind : int32_t {
Coalesce,
CompoundExpression,
Literal,
At,
Interpolate,
Assertion,
Length,
Step,
Let,
Var,
CollatorExpression,
Coercion,
Match,
Error,
Case,
Any,
All,
Comparison,
FormatExpression,
FormatSectionOverride,
NumberFormat,
ImageExpression,
In,
Within,
Distance
};
class Expression {
public:
Expression(Kind kind_, type::Type type_) : kind(kind_), type(std::move(type_)) {}
virtual ~Expression() = default;
virtual EvaluationResult evaluate(const EvaluationContext& params) const = 0;
virtual void eachChild(const std::function<void(const Expression&)>&) const = 0;
virtual bool operator==(const Expression&) const = 0;
bool operator!=(const Expression& rhs) const {
return !operator==(rhs);
}
Kind getKind() const { return kind; };
type::Type getType() const { return type; };
EvaluationResult evaluate(optional<float> zoom, const Feature& feature, optional<double> colorRampParameter) const;
EvaluationResult evaluate(optional<float> zoom,
const Feature& feature,
optional<double> colorRampParameter,
const std::set<std::string>& availableImages) const;
EvaluationResult evaluate(optional<float> zoom,
const Feature& feature,
optional<double> colorRampParameter,
const std::set<std::string>& availableImages,
const CanonicalTileID& canonical) const;
EvaluationResult evaluate(optional<mbgl::Value> accumulated, const Feature& feature) const;
/**
* Statically analyze the expression, attempting to enumerate possible outputs. Returns
* an array of values plus the sentinel null optional value, used to indicate that the
* complete set of outputs is statically undecidable.
*/
virtual std::vector<optional<Value>> possibleOutputs() const = 0;
virtual mbgl::Value serialize() const {
std::vector<mbgl::Value> serialized;
serialized.emplace_back(getOperator());
eachChild([&](const Expression &child) {
serialized.emplace_back(child.serialize());
});
return serialized;
};
virtual std::string getOperator() const = 0;
protected:
template <typename T>
static bool childrenEqual(const T& lhs, const T& rhs) {
if (lhs.size() != rhs.size()) return false;
for (auto leftChild = lhs.begin(), rightChild = rhs.begin();
leftChild != lhs.end();
leftChild++, rightChild++)
{
if (!Expression::childEqual(*leftChild, *rightChild)) return false;
}
return true;
}
static bool childEqual(const std::unique_ptr<Expression>& lhs, const std::unique_ptr<Expression>& rhs) {
return *lhs == *rhs;
}
template <typename T>
static bool childEqual(const std::pair<T, std::unique_ptr<Expression>>& lhs,
const std::pair<T, std::unique_ptr<Expression>>& rhs) {
return lhs.first == rhs.first && *(lhs.second) == *(rhs.second);
}
template <typename T>
static bool childEqual(const std::pair<T, std::shared_ptr<Expression>>& lhs,
const std::pair<T, std::shared_ptr<Expression>>& rhs) {
return lhs.first == rhs.first && *(lhs.second) == *(rhs.second);
}
static bool childEqual(const std::pair<std::unique_ptr<Expression>, std::unique_ptr<Expression>>& lhs,
const std::pair<std::unique_ptr<Expression>, std::unique_ptr<Expression>>& rhs) {
return *(lhs.first) == *(rhs.first) && *(lhs.second) == *(rhs.second);
}
private:
Kind kind;
type::Type type;
};
} // namespace expression
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,20 @@
#pragma once
#include <mbgl/style/expression/parsing_context.hpp>
#include <mbgl/style/expression/interpolate.hpp>
#include <mbgl/style/expression/step.hpp>
#include <mbgl/util/variant.hpp>
#include <mbgl/util/optional.hpp>
namespace mbgl {
namespace style {
namespace expression {
optional<variant<const Interpolate*, const Step*, ParsingError>> findZoomCurve(const expression::Expression* e);
variant<std::nullptr_t, const Interpolate*, const Step*> findZoomCurveChecked(const expression::Expression* e);
} // namespace expression
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,53 @@
#pragma once
#include <mbgl/style/expression/expression.hpp>
#include <mbgl/style/expression/parsing_context.hpp>
namespace mbgl {
namespace style {
namespace expression {
struct FormatExpressionSection {
explicit FormatExpressionSection(std::unique_ptr<Expression> content_);
void setTextSectionOptions(optional<std::unique_ptr<Expression>> fontScale_,
optional<std::unique_ptr<Expression>> textFont_,
optional<std::unique_ptr<Expression>> textColor_);
// Content can be expression that evaluates to String or Image.
std::shared_ptr<Expression> content;
// Text related section options.
optional<std::shared_ptr<Expression>> fontScale;
optional<std::shared_ptr<Expression>> textFont;
optional<std::shared_ptr<Expression>> textColor;
};
class FormatExpression final : public Expression {
public:
explicit FormatExpression(std::vector<FormatExpressionSection> sections);
EvaluationResult evaluate(const EvaluationContext&) const override;
static ParseResult parse(const mbgl::style::conversion::Convertible&, ParsingContext&);
void eachChild(const std::function<void(const Expression&)>&) const override;
bool operator==(const Expression& e) const override;
std::vector<optional<Value>> possibleOutputs() const override {
// Technically the combinatoric set of all children
// Usually, this.text will be undefined anyway
return { nullopt };
}
const std::vector<FormatExpressionSection>& getSections() const { return sections; }
mbgl::Value serialize() const override;
std::string getOperator() const override { return "format"; }
private:
std::vector<FormatExpressionSection> sections;
};
} // namespace expression
} // namespace style
} // namespace mbgl

View File

@@ -0,0 +1,86 @@
#pragma once
#include <mbgl/style/expression/expression.hpp>
#include <mbgl/renderer/possibly_evaluated_property_value.hpp>
namespace mbgl {
namespace style {
namespace expression {
template<class T>
class FormatSectionOverride final : public Expression {
public:
FormatSectionOverride(const type::Type& type_,
PossiblyEvaluatedPropertyValue<T> defaultValue_,
std::string propertyName_) :
Expression(Kind::FormatSectionOverride, type_),
defaultValue(std::move(defaultValue_)),
propertyName(std::move(propertyName_))
{}
EvaluationResult evaluate(const EvaluationContext& context) const final {
using Object = std::unordered_map<std::string, expression::Value>;
if (context.formattedSection &&
context.formattedSection->is<Object>()) {
const auto& section = context.formattedSection->get<Object>();
if (section.find(propertyName) != section.end()) {
return section.at(propertyName);
}
}
return defaultValue.match(
[&context] (const style::PropertyExpression<T>& e) { return e.getExpression().evaluate(context); },
[] (const T& t) -> EvaluationResult { return t; }
);
}
void eachChild(const std::function<void(const Expression&)>& fn) const final {
defaultValue.match([&fn] (const style::PropertyExpression<T>& e) { fn(e.getExpression()); },
[] (const T&) {});
}
bool operator==(const Expression& e) const final {
if (e.getKind() == Kind::FormatSectionOverride) {
const auto* other = static_cast<const FormatSectionOverride*>(&e);
if (getType() != other->getType() || propertyName != other->propertyName) {
return false;
}
// Check that default values or property expressions are equal.
return defaultValue.match(
[other] (const style::PropertyExpression<T>& thisExpr) {
return other->defaultValue.match([&thisExpr] (const style::PropertyExpression<T>& otherExpr) {
return thisExpr == otherExpr;
},
[] (const T&) {
return false;
});
},
[other] (const T& thisValue) {
return other->defaultValue.match([&thisValue] (const T& otherValue) {
return thisValue == otherValue;
},
[] (const style::PropertyExpression<T>&) {
return false;
});
});
}
return false;
}
std::vector<optional<Value>> possibleOutputs() const final {
return {nullopt};
}
std::string getOperator() const final { return "format-section-override"; }
private:
PossiblyEvaluatedPropertyValue<T> defaultValue;
std::string propertyName;
};
} // namespace expression
} // namespace style
} // namespace mbgl

Some files were not shown because too many files have changed in this diff Show More