diff options
author | Sudarsana Babu Nagineni <sudarsana.babu@mapbox.com> | 2018-07-30 15:30:57 +0300 |
---|---|---|
committer | Sudarsana Babu Nagineni <sudarsana.babu@mapbox.com> | 2018-08-06 16:55:30 +0300 |
commit | 0130c58fdd74edbbfe668f3125a9377554d7d605 (patch) | |
tree | 6be1c1d25d146e9273f04f40f2283e18048c17ac /platform/qt/src | |
parent | 7373abef92ed4911b91f9fca3d97784ed0d9e02e (diff) | |
download | qtlocation-mapboxgl-0130c58fdd74edbbfe668f3125a9377554d7d605.tar.gz |
Bump Mapbox GL Native
Bump version.
mapbox-gl-native @ 377a6e42d687c419e6ae1012b8626336f5dfc1b6
Diffstat (limited to 'platform/qt/src')
-rw-r--r-- | platform/qt/src/qmapboxgl.cpp | 108 | ||||
-rw-r--r-- | platform/qt/src/qmapboxgl_map_renderer.cpp | 67 | ||||
-rw-r--r-- | platform/qt/src/qmapboxgl_map_renderer.hpp | 11 | ||||
-rw-r--r-- | platform/qt/src/qmapboxgl_scheduler.cpp | 38 | ||||
-rw-r--r-- | platform/qt/src/qmapboxgl_scheduler.hpp | 34 | ||||
-rw-r--r-- | platform/qt/src/qt_geojson.cpp | 7 | ||||
-rw-r--r-- | platform/qt/src/sqlite3.cpp | 107 |
7 files changed, 275 insertions, 97 deletions
diff --git a/platform/qt/src/qmapboxgl.cpp b/platform/qt/src/qmapboxgl.cpp index 8c3355dc09..09479581bb 100644 --- a/platform/qt/src/qmapboxgl.cpp +++ b/platform/qt/src/qmapboxgl.cpp @@ -55,6 +55,10 @@ #include <QString> #include <QStringList> #include <QThreadStorage> +#include <QVariant> +#include <QVariantList> +#include <QVariantMap> +#include <QColor> #include <memory> @@ -703,7 +707,7 @@ double QMapboxGL::scale() const void QMapboxGL::setScale(double scale_, const QPointF ¢er) { - d_ptr->mapObj->setZoom(mbgl::util::log2(scale_), mbgl::ScreenCoordinate { center.x(), center.y() }); + d_ptr->mapObj->setZoom(::log2(scale_), mbgl::ScreenCoordinate { center.x(), center.y() }); } /*! @@ -1111,7 +1115,7 @@ void QMapboxGL::moveBy(const QPointF &offset) can be used for implementing a pinch gesture. */ void QMapboxGL::scaleBy(double scale_, const QPointF ¢er) { - d_ptr->mapObj->setZoom(d_ptr->mapObj->getZoom() + mbgl::util::log2(scale_), mbgl::ScreenCoordinate { center.x(), center.y() }); + d_ptr->mapObj->setZoom(d_ptr->mapObj->getZoom() + ::log2(scale_), mbgl::ScreenCoordinate { center.x(), center.y() }); } /*! @@ -1466,6 +1470,23 @@ void QMapboxGL::removeLayer(const QString& id) } /*! + List of all existing layer ids from the current style. +*/ +QList<QString> QMapboxGL::layerIds() const +{ + const auto &layers = d_ptr->mapObj->getStyle().getLayers(); + + QList<QString> layerIds; + layerIds.reserve(layers.size()); + + for (const mbgl::style::Layer *layer : layers) { + layerIds.append(QString::fromStdString(layer->getID())); + } + + return layerIds; +} + +/*! Adds the \a image with the identifier \a id that can be used later by a symbol layer. @@ -1492,7 +1513,7 @@ void QMapboxGL::removeImage(const QString &id) /*! Adds a \a filter to a style \a layer using the format described in the \l - {https://www.mapbox.com/mapbox-gl-style-spec/#types-filter}{Mapbox style specification}. + {https://www.mapbox.com/mapbox-gl-js/style-spec/#other-filter}{Mapbox style specification}. Given a layer \c marker from an arbitrary GeoJSON source containing features of type \b "Point" and \b "LineString", this example shows how to make sure the layer will only tag @@ -1500,14 +1521,14 @@ void QMapboxGL::removeImage(const QString &id) \code QVariantList filterExpression; - filterExpression.append("=="); - filterExpression.append("$type"); - filterExpression.append("Point"); + filterExpression.push_back(QLatin1String("==")); + filterExpression.push_back(QLatin1String("$type")); + filterExpression.push_back(QLatin1String("Point")); QVariantList filter; - filter.append(filterExpression); + filter.push_back(filterExpression); - map->setFilter("marker", filter); + map->setFilter(QLatin1String("marker"), filter); \endcode */ void QMapboxGL::setFilter(const QString& layer, const QVariant& filter) @@ -1555,6 +1576,77 @@ void QMapboxGL::setFilter(const QString& layer, const QVariant& filter) qWarning() << "Layer doesn't support filters"; } +QVariant QVariantFromValue(const mbgl::Value &value) { + return value.match( + [](const mbgl::NullValue) { + return QVariant(); + }, [](const bool value_) { + return QVariant(value_); + }, [](const float value_) { + return QVariant(value_); + }, [](const int64_t value_) { + return QVariant(static_cast<qlonglong>(value_)); + }, [](const double value_) { + return QVariant(value_); + }, [](const std::string &value_) { + return QVariant(value_.c_str()); + }, [](const mbgl::Color &value_) { + return QColor(value_.r, value_.g, value_.b, value_.a); + }, [&](const std::vector<mbgl::Value> &vector) { + QVariantList list; + list.reserve(vector.size()); + for (const auto &value_ : vector) { + list.push_back(QVariantFromValue(value_)); + } + return list; + }, [&](const std::unordered_map<std::string, mbgl::Value> &map) { + QVariantMap varMap; + for (auto &item : map) { + varMap.insert(item.first.c_str(), QVariantFromValue(item.second)); + } + return varMap; + }, [](const auto &) { + return QVariant(); + }); +} + +/*! + Returns the current \a expression-based filter value applied to a style + \layer, if any. + + Filter value types are described in the {https://www.mapbox.com/mapbox-gl-js/style-spec/#types}{Mapbox style specification}. +*/ +QVariant QMapboxGL::getFilter(const QString &layer) const { + using namespace mbgl::style; + using namespace mbgl::style::conversion; + + Layer* layer_ = d_ptr->mapObj->getStyle().getLayer(layer.toStdString()); + if (!layer_) { + qWarning() << "Layer not found:" << layer; + return QVariant(); + } + + Filter filter_; + + if (layer_->is<FillLayer>()) { + filter_ = layer_->as<FillLayer>()->getFilter(); + } else if (layer_->is<LineLayer>()) { + filter_ = layer_->as<LineLayer>()->getFilter(); + } else if (layer_->is<SymbolLayer>()) { + filter_ = layer_->as<SymbolLayer>()->getFilter(); + } else if (layer_->is<CircleLayer>()) { + filter_ = layer_->as<CircleLayer>()->getFilter(); + } else if (layer_->is<FillExtrusionLayer>()) { + filter_ = layer_->as<FillExtrusionLayer>()->getFilter(); + } else { + qWarning() << "Layer doesn't support filters"; + return QVariant(); + } + + auto serialized = filter_.serialize(); + return QVariantFromValue(serialized); +} + /*! Creates the infrastructure needed for rendering the map. It should be called before any call to render(). diff --git a/platform/qt/src/qmapboxgl_map_renderer.cpp b/platform/qt/src/qmapboxgl_map_renderer.cpp index 7a9d1f6f78..acc4194498 100644 --- a/platform/qt/src/qmapboxgl_map_renderer.cpp +++ b/platform/qt/src/qmapboxgl_map_renderer.cpp @@ -1,12 +1,47 @@ #include "qmapboxgl_map_renderer.hpp" +#include "qmapboxgl_scheduler.hpp" +#include <QThreadStorage> #include <QtGlobal> +static bool needsToForceScheduler() { + static QThreadStorage<bool> force; + + if (!force.hasLocalData()) { + force.setLocalData(mbgl::Scheduler::GetCurrent() == nullptr); + } + + return force.localData(); +}; + +static auto *getScheduler() { + static QThreadStorage<std::shared_ptr<QMapboxGLScheduler>> scheduler; + + if (!scheduler.hasLocalData()) { + scheduler.setLocalData(std::make_shared<QMapboxGLScheduler>()); + } + + return scheduler.localData().get(); +}; + QMapboxGLMapRenderer::QMapboxGLMapRenderer(qreal pixelRatio, mbgl::DefaultFileSource &fs, mbgl::ThreadPool &tp, QMapboxGLSettings::GLContextMode mode) : m_renderer(std::make_unique<mbgl::Renderer>(m_backend, pixelRatio, fs, tp, static_cast<mbgl::GLContextMode>(mode))) - , m_threadWithScheduler(Scheduler::GetCurrent() != nullptr) + , m_forceScheduler(needsToForceScheduler()) { + // If we don't have a Scheduler on this thread, which + // is usually the case for render threads, use a shared + // dummy scheduler that needs to be explicitly forced to + // process events. + if (m_forceScheduler) { + auto scheduler = getScheduler(); + + if (mbgl::Scheduler::GetCurrent() == nullptr) { + mbgl::Scheduler::SetCurrent(scheduler); + } + + connect(scheduler, SIGNAL(needsProcessing()), this, SIGNAL(needsRendering())); + } } QMapboxGLMapRenderer::~QMapboxGLMapRenderer() @@ -14,16 +49,6 @@ QMapboxGLMapRenderer::~QMapboxGLMapRenderer() MBGL_VERIFY_THREAD(tid); } -void QMapboxGLMapRenderer::schedule(std::weak_ptr<mbgl::Mailbox> mailbox) -{ - std::lock_guard<std::mutex> lock(m_taskQueueMutex); - m_taskQueue.push(mailbox); - - // Need to force the main thread to wake - // up this thread and process the events. - emit needsRendering(); -} - void QMapboxGLMapRenderer::updateParameters(std::shared_ptr<mbgl::UpdateParameters> newParameters) { std::lock_guard<std::mutex> lock(m_updateMutex); @@ -57,26 +82,10 @@ void QMapboxGLMapRenderer::render() // The OpenGL implementation automatically enables the OpenGL context for us. mbgl::BackendScope scope(m_backend, mbgl::BackendScope::ScopeType::Implicit); - // If we don't have a Scheduler on this thread, which - // is usually the case for render threads, use this - // object as scheduler. - if (!m_threadWithScheduler) { - Scheduler::SetCurrent(this); - } - m_renderer->render(*params); - if (!m_threadWithScheduler) { - std::queue<std::weak_ptr<mbgl::Mailbox>> taskQueue; - { - std::unique_lock<std::mutex> lock(m_taskQueueMutex); - std::swap(taskQueue, m_taskQueue); - } - - while (!taskQueue.empty()) { - mbgl::Mailbox::maybeReceive(taskQueue.front()); - taskQueue.pop(); - } + if (m_forceScheduler) { + getScheduler()->processEvents(); } } diff --git a/platform/qt/src/qmapboxgl_map_renderer.hpp b/platform/qt/src/qmapboxgl_map_renderer.hpp index adba11de51..0b17542e2f 100644 --- a/platform/qt/src/qmapboxgl_map_renderer.hpp +++ b/platform/qt/src/qmapboxgl_map_renderer.hpp @@ -14,7 +14,6 @@ #include <memory> #include <mutex> -#include <queue> namespace mbgl { class Renderer; @@ -23,7 +22,7 @@ class UpdateParameters; class QMapboxGLRendererBackend; -class QMapboxGLMapRenderer : public QObject, public mbgl::Scheduler +class QMapboxGLMapRenderer : public QObject { Q_OBJECT @@ -32,9 +31,6 @@ public: mbgl::ThreadPool &, QMapboxGLSettings::GLContextMode); virtual ~QMapboxGLMapRenderer(); - // mbgl::Scheduler implementation. - void schedule(std::weak_ptr<mbgl::Mailbox> scheduled) final; - void render(); void updateFramebuffer(quint32 fbo, const mbgl::Size &size); void setObserver(std::shared_ptr<mbgl::RendererObserver>); @@ -56,8 +52,5 @@ private: QMapboxGLRendererBackend m_backend; std::unique_ptr<mbgl::Renderer> m_renderer; - std::mutex m_taskQueueMutex; - std::queue<std::weak_ptr<mbgl::Mailbox>> m_taskQueue; - - bool m_threadWithScheduler; + bool m_forceScheduler; }; diff --git a/platform/qt/src/qmapboxgl_scheduler.cpp b/platform/qt/src/qmapboxgl_scheduler.cpp new file mode 100644 index 0000000000..e2d39703ee --- /dev/null +++ b/platform/qt/src/qmapboxgl_scheduler.cpp @@ -0,0 +1,38 @@ +#include "qmapboxgl_scheduler.hpp" + +#include <mbgl/util/util.hpp> + +#include <cassert> + +QMapboxGLScheduler::QMapboxGLScheduler() +{ +} + +QMapboxGLScheduler::~QMapboxGLScheduler() +{ + MBGL_VERIFY_THREAD(tid); +} + +void QMapboxGLScheduler::schedule(std::weak_ptr<mbgl::Mailbox> mailbox) +{ + std::lock_guard<std::mutex> lock(m_taskQueueMutex); + m_taskQueue.push(mailbox); + + // Need to force the main thread to wake + // up this thread and process the events. + emit needsProcessing(); +} + +void QMapboxGLScheduler::processEvents() +{ + std::queue<std::weak_ptr<mbgl::Mailbox>> taskQueue; + { + std::unique_lock<std::mutex> lock(m_taskQueueMutex); + std::swap(taskQueue, m_taskQueue); + } + + while (!taskQueue.empty()) { + mbgl::Mailbox::maybeReceive(taskQueue.front()); + taskQueue.pop(); + } +} diff --git a/platform/qt/src/qmapboxgl_scheduler.hpp b/platform/qt/src/qmapboxgl_scheduler.hpp new file mode 100644 index 0000000000..68636d0d11 --- /dev/null +++ b/platform/qt/src/qmapboxgl_scheduler.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include <mbgl/actor/mailbox.hpp> +#include <mbgl/actor/scheduler.hpp> +#include <mbgl/util/util.hpp> + +#include <QObject> + +#include <memory> +#include <mutex> +#include <queue> + +class QMapboxGLScheduler : public QObject, public mbgl::Scheduler +{ + Q_OBJECT + +public: + QMapboxGLScheduler(); + virtual ~QMapboxGLScheduler(); + + // mbgl::Scheduler implementation. + void schedule(std::weak_ptr<mbgl::Mailbox> scheduled) final; + + void processEvents(); + +signals: + void needsProcessing(); + +private: + MBGL_STORE_THREAD(tid); + + std::mutex m_taskQueueMutex; + std::queue<std::weak_ptr<mbgl::Mailbox>> m_taskQueue; +}; diff --git a/platform/qt/src/qt_geojson.cpp b/platform/qt/src/qt_geojson.cpp index 80377de64d..9d0a3e96eb 100644 --- a/platform/qt/src/qt_geojson.cpp +++ b/platform/qt/src/qt_geojson.cpp @@ -72,10 +72,8 @@ mbgl::Value asMapboxGLPropertyValue(const QVariant &value) { auto valueMap = [](const QVariantMap &map) { std::unordered_map<std::string, mbgl::Value> mbglMap; mbglMap.reserve(map.size()); - auto it = map.constBegin(); - while (it != map.constEnd()) { + for (auto it = map.constBegin(); it != map.constEnd(); ++it) { mbglMap.emplace(std::make_pair(it.key().toStdString(), asMapboxGLPropertyValue(it.value()))); - ++it; } return mbglMap; }; @@ -132,8 +130,7 @@ mbgl::FeatureIdentifier asMapboxGLFeatureIdentifier(const QVariant &id) { mbgl::Feature asMapboxGLFeature(const QMapbox::Feature &feature) { mbgl::PropertyMap properties; properties.reserve(feature.properties.size()); - auto it = feature.properties.constBegin(); - while (it != feature.properties.constEnd()) { + for (auto it = feature.properties.constBegin(); it != feature.properties.constEnd(); ++it) { properties.emplace(std::make_pair(it.key().toStdString(), asMapboxGLPropertyValue(it.value()))); } diff --git a/platform/qt/src/sqlite3.cpp b/platform/qt/src/sqlite3.cpp index 4bcaea0e31..2ca09fd3ad 100644 --- a/platform/qt/src/sqlite3.cpp +++ b/platform/qt/src/sqlite3.cpp @@ -52,15 +52,6 @@ void checkDatabaseError(const QSqlDatabase &db) { } } -void checkDatabaseOpenError(const QSqlDatabase &db) { - // Assume every error when opening the data as CANTOPEN. Qt - // always returns -1 for `nativeErrorCode()` on database errors. - QSqlError lastError = db.lastError(); - if (lastError.type() != QSqlError::NoError) { - throw Exception { ResultCode::CantOpen, "Error opening the database." }; - } -} - namespace { QString incrementCounter() { static QAtomicInt count = 0; @@ -70,32 +61,9 @@ namespace { class DatabaseImpl { public: - DatabaseImpl(const char* filename, int flags) - : connectionName(QString::number(uint64_t(QThread::currentThread())) + incrementCounter()) + DatabaseImpl(QString connectionName_) + : connectionName(std::move(connectionName_)) { - if (!QSqlDatabase::drivers().contains("QSQLITE")) { - throw Exception { ResultCode::CantOpen, "SQLite driver not found." }; - } - - assert(!QSqlDatabase::contains(connectionName)); - auto db = QSqlDatabase::addDatabase("QSQLITE", connectionName); - - QString connectOptions = db.connectOptions(); - if (flags & OpenFlag::ReadOnly) { - if (!connectOptions.isEmpty()) connectOptions.append(';'); - connectOptions.append("QSQLITE_OPEN_READONLY"); - } - if (flags & OpenFlag::SharedCache) { - if (!connectOptions.isEmpty()) connectOptions.append(';'); - connectOptions.append("QSQLITE_ENABLE_SHARED_CACHE"); - } - - db.setConnectOptions(connectOptions); - db.setDatabaseName(QString(filename)); - - if (!db.open()) { - checkDatabaseOpenError(db); - } } ~DatabaseImpl() { @@ -104,6 +72,9 @@ public: checkDatabaseError(db); } + void setBusyTimeout(std::chrono::milliseconds timeout); + void exec(const std::string& sql); + QString connectionName; }; @@ -127,12 +98,47 @@ public: template <typename T> using optional = std::experimental::optional<T>; +mapbox::util::variant<Database, Exception> Database::tryOpen(const std::string &filename, int flags) { + if (!QSqlDatabase::drivers().contains("QSQLITE")) { + return Exception { ResultCode::CantOpen, "SQLite driver not found." }; + } -Database::Database(const std::string& file, int flags) - : impl(std::make_unique<DatabaseImpl>(file.c_str(), flags)) { - assert(impl); + QString connectionName = QString::number(uint64_t(QThread::currentThread())) + incrementCounter(); + + assert(!QSqlDatabase::contains(connectionName)); + auto db = QSqlDatabase::addDatabase("QSQLITE", connectionName); + + QString connectOptions = db.connectOptions(); + if (flags & OpenFlag::ReadOnly) { + if (!connectOptions.isEmpty()) connectOptions.append(';'); + connectOptions.append("QSQLITE_OPEN_READONLY"); + } + + db.setConnectOptions(connectOptions); + db.setDatabaseName(QString(filename.c_str())); + + if (!db.open()) { + // Assume every error when opening the data as CANTOPEN. Qt + // always returns -1 for `nativeErrorCode()` on database errors. + return Exception { ResultCode::CantOpen, "Error opening the database." }; + } + + return Database(std::make_unique<DatabaseImpl>(connectionName)); } +Database Database::open(const std::string &filename, int flags) { + auto result = tryOpen(filename, flags); + if (result.is<Exception>()) { + throw result.get<Exception>(); + } else { + return std::move(result.get<Database>()); + } +} + +Database::Database(std::unique_ptr<DatabaseImpl> impl_) + : impl(std::move(impl_)) +{} + Database::Database(Database &&other) : impl(std::move(other.impl)) { assert(impl); @@ -149,12 +155,15 @@ Database::~Database() { void Database::setBusyTimeout(std::chrono::milliseconds timeout) { assert(impl); + impl->setBusyTimeout(timeout); +} +void DatabaseImpl::setBusyTimeout(std::chrono::milliseconds timeout) { // std::chrono::milliseconds.count() is a long and Qt will cast // internally to int, so we need to make sure the limits apply. std::string timeoutStr = mbgl::util::toString(timeout.count() & INT_MAX); - auto db = QSqlDatabase::database(impl->connectionName); + auto db = QSqlDatabase::database(connectionName); QString connectOptions = db.connectOptions(); if (connectOptions.isEmpty()) { if (!connectOptions.isEmpty()) connectOptions.append(';'); @@ -165,19 +174,25 @@ void Database::setBusyTimeout(std::chrono::milliseconds timeout) { } db.setConnectOptions(connectOptions); if (!db.open()) { - checkDatabaseOpenError(db); + // Assume every error when opening the data as CANTOPEN. Qt + // always returns -1 for `nativeErrorCode()` on database errors. + throw Exception { ResultCode::CantOpen, "Error opening the database." }; } } void Database::exec(const std::string &sql) { assert(impl); + impl->exec(sql); +} + +void DatabaseImpl::exec(const std::string& sql) { QStringList statements = QString::fromStdString(sql).split(';', QString::SkipEmptyParts); statements.removeAll("\n"); for (QString statement : statements) { if (!statement.endsWith(';')) { statement.append(';'); } - QSqlQuery query(QSqlDatabase::database(impl->connectionName)); + QSqlQuery query(QSqlDatabase::database(connectionName)); query.prepare(statement); if (!query.exec()) { @@ -424,16 +439,16 @@ uint64_t Query::changes() const { } Transaction::Transaction(Database& db_, Mode mode) - : db(db_) { + : dbImpl(*db_.impl) { switch (mode) { case Deferred: - db.exec("BEGIN DEFERRED TRANSACTION"); + dbImpl.exec("BEGIN DEFERRED TRANSACTION"); break; case Immediate: - db.exec("BEGIN IMMEDIATE TRANSACTION"); + dbImpl.exec("BEGIN IMMEDIATE TRANSACTION"); break; case Exclusive: - db.exec("BEGIN EXCLUSIVE TRANSACTION"); + dbImpl.exec("BEGIN EXCLUSIVE TRANSACTION"); break; } } @@ -450,12 +465,12 @@ Transaction::~Transaction() { void Transaction::commit() { needRollback = false; - db.exec("COMMIT TRANSACTION"); + dbImpl.exec("COMMIT TRANSACTION"); } void Transaction::rollback() { needRollback = false; - db.exec("ROLLBACK TRANSACTION"); + dbImpl.exec("ROLLBACK TRANSACTION"); } } // namespace sqlite |