diff options
Diffstat (limited to 'platform/qt/src')
-rw-r--r-- | platform/qt/src/headless_backend_qt.cpp | 36 | ||||
-rw-r--r-- | platform/qt/src/http_file_source.cpp | 3 | ||||
-rw-r--r-- | platform/qt/src/http_request.cpp | 7 | ||||
-rw-r--r-- | platform/qt/src/http_request.hpp | 2 | ||||
-rw-r--r-- | platform/qt/src/qmapboxgl.cpp | 65 | ||||
-rw-r--r-- | platform/qt/src/qmapboxgl_p.hpp | 9 | ||||
-rw-r--r-- | platform/qt/src/qt_conversion.hpp | 191 | ||||
-rw-r--r-- | platform/qt/src/qt_geojson.cpp | 166 | ||||
-rw-r--r-- | platform/qt/src/qt_geojson.hpp | 194 | ||||
-rw-r--r-- | platform/qt/src/qt_image.cpp | 5 | ||||
-rwxr-xr-x | platform/qt/src/qt_logging.cpp | 12 | ||||
-rw-r--r-- | platform/qt/src/sqlite3.cpp | 87 |
12 files changed, 445 insertions, 332 deletions
diff --git a/platform/qt/src/headless_backend_qt.cpp b/platform/qt/src/headless_backend_qt.cpp index 5f95b2f96a..ad3fa42290 100644 --- a/platform/qt/src/headless_backend_qt.cpp +++ b/platform/qt/src/headless_backend_qt.cpp @@ -12,19 +12,11 @@ namespace mbgl { -struct QtImpl : public HeadlessBackend::Impl { - void activateContext() final { - widget.makeCurrent(); - } +class QtBackendImpl : public HeadlessBackend::Impl { +public: + ~QtBackendImpl() final = default; - void deactivateContext() final { - widget.doneCurrent(); - } - - QGLWidget widget; -}; - -gl::ProcAddress HeadlessBackend::initializeExtension(const char* name) { + gl::ProcAddress getExtensionFunctionPointer(const char* name) final { #if QT_VERSION >= 0x050000 QOpenGLContext* thisContext = QOpenGLContext::currentContext(); return thisContext->getProcAddress(name); @@ -32,15 +24,23 @@ gl::ProcAddress HeadlessBackend::initializeExtension(const char* name) { const QGLContext* thisContext = QGLContext::currentContext(); return reinterpret_cast<gl::ProcAddress>(thisContext->getProcAddress(name)); #endif -} + } + + void activateContext() final { + widget.makeCurrent(); + } -bool HeadlessBackend::hasDisplay() { - return true; + void deactivateContext() final { + widget.doneCurrent(); + } + +private: + QGLWidget widget; }; -void HeadlessBackend::createContext() { - assert(!hasContext()); - impl.reset(new QtImpl); +void HeadlessBackend::createImpl() { + assert(!impl); + impl = std::make_unique<QtBackendImpl>(); } } // namespace mbgl diff --git a/platform/qt/src/http_file_source.cpp b/platform/qt/src/http_file_source.cpp index 573b707c27..6e70693241 100644 --- a/platform/qt/src/http_file_source.cpp +++ b/platform/qt/src/http_file_source.cpp @@ -80,9 +80,10 @@ void HTTPFileSource::Impl::onReplyFinished() return; } + QByteArray data = reply->readAll(); QVector<HTTPRequest*>& requestsVector = it.value().second; for (auto req : requestsVector) { - req->handleNetworkReply(reply); + req->handleNetworkReply(reply, data); } m_pending.erase(it); diff --git a/platform/qt/src/http_request.cpp b/platform/qt/src/http_request.cpp index 386a2d9ef4..ea3f388bd5 100644 --- a/platform/qt/src/http_request.cpp +++ b/platform/qt/src/http_request.cpp @@ -52,7 +52,7 @@ QNetworkRequest HTTPRequest::networkRequest() const return req; } -void HTTPRequest::handleNetworkReply(QNetworkReply *reply) +void HTTPRequest::handleNetworkReply(QNetworkReply *reply, const QByteArray& data) { m_handled = true; @@ -98,11 +98,10 @@ void HTTPRequest::handleNetworkReply(QNetworkReply *reply) switch(responseCode) { case 200: { - QByteArray bytes = reply->readAll(); - if (bytes.isEmpty()) { + if (data.isEmpty()) { response.data = std::make_shared<std::string>(); } else { - response.data = std::make_shared<std::string>(bytes.constData(), bytes.size()); + response.data = std::make_shared<std::string>(data.constData(), data.size()); } break; } diff --git a/platform/qt/src/http_request.hpp b/platform/qt/src/http_request.hpp index 959f97759a..b4d476d586 100644 --- a/platform/qt/src/http_request.hpp +++ b/platform/qt/src/http_request.hpp @@ -20,7 +20,7 @@ public: QUrl requestUrl() const; QNetworkRequest networkRequest() const; - void handleNetworkReply(QNetworkReply *); + void handleNetworkReply(QNetworkReply *, const QByteArray& data); private: HTTPFileSource::Impl* m_context; diff --git a/platform/qt/src/qmapboxgl.cpp b/platform/qt/src/qmapboxgl.cpp index e79c6af56a..2675d87862 100644 --- a/platform/qt/src/qmapboxgl.cpp +++ b/platform/qt/src/qmapboxgl.cpp @@ -14,7 +14,17 @@ #include <mbgl/style/conversion.hpp> #include <mbgl/style/conversion/layer.hpp> #include <mbgl/style/conversion/source.hpp> +#include <mbgl/style/conversion/filter.hpp> +#include <mbgl/style/conversion/geojson.hpp> +#include <mbgl/style/filter.hpp> #include <mbgl/style/layers/custom_layer.hpp> +#include <mbgl/style/layers/background_layer.hpp> +#include <mbgl/style/layers/circle_layer.hpp> +#include <mbgl/style/layers/fill_layer.hpp> +#include <mbgl/style/layers/fill_extrusion_layer.hpp> +#include <mbgl/style/layers/line_layer.hpp> +#include <mbgl/style/layers/raster_layer.hpp> +#include <mbgl/style/layers/symbol_layer.hpp> #include <mbgl/style/sources/geojson_source.hpp> #include <mbgl/style/transition_options.hpp> #include <mbgl/style/image.hpp> @@ -29,6 +39,7 @@ #include <mbgl/util/run_loop.hpp> #include <mbgl/util/shared_thread_pool.hpp> #include <mbgl/util/traits.hpp> +#include <mbgl/actor/scheduler.hpp> #if QT_VERSION >= 0x050000 #include <QGuiApplication> @@ -100,8 +111,13 @@ std::unique_ptr<mbgl::style::Image> toStyleImage(const QString &id, const QImage .rgbSwapped() .convertToFormat(QImage::Format_ARGB32_Premultiplied); +#if QT_VERSION >= 0x051000 + auto img = std::make_unique<uint8_t[]>(swapped.sizeInBytes()); + memcpy(img.get(), swapped.constBits(), swapped.sizeInBytes()); +#else auto img = std::make_unique<uint8_t[]>(swapped.byteCount()); memcpy(img.get(), swapped.constBits(), swapped.byteCount()); +#endif return std::make_unique<mbgl::style::Image>( id.toStdString(), @@ -139,9 +155,11 @@ std::unique_ptr<mbgl::style::Image> toStyleImage(const QString &id, const QImage reset before each rendering. Use this mode if the intention is to only draw a fullscreen map. - \value SharedGLContext The OpenGL context is shared and the state will be restored - before rendering. This mode is safer when OpenGL calls are performed prior of after - we call QMapboxGL::render for rendering a map. + \value SharedGLContext The OpenGL context is shared and the state will be + marked dirty - which invalidates any previously assumed GL state. The + embedder is responsible for clearing up the viewport prior to calling + QMapboxGL::render. The embedder is also responsible for resetting its own + GL state after QMapboxGL::render has finished, if needed. \sa contextMode() */ @@ -362,6 +380,27 @@ void QMapboxGLSettings::setApiBaseUrl(const QString& url) } /*! + Returns resource transformation callback used to transform requested URLs. +*/ +std::function<std::string(const std::string &&)> QMapboxGLSettings::resourceTransform() const +{ + return m_resourceTransform; +} + +/*! + Sets the resource \a transform callback. + + When given, resource transformation callback will be used to transform the + requested resource URLs before they are requested from internet. This can be + used add or remove custom parameters, or reroute certain requests to other + servers or endpoints. +*/ +void QMapboxGLSettings::setResourceTransform(const std::function<std::string(const std::string &&)> &transform) +{ + m_resourceTransform = transform; +} + +/*! \class QMapboxGL \brief The QMapboxGL class is a Qt wrapper for the Mapbox GL Native engine. @@ -850,7 +889,7 @@ void QMapboxGL::removeAnnotation(QMapbox::AnnotationID id) } /*! - Sets a layout \a property \a value to an existing \a layer. The \a property_ string can be any + Sets a layout \a property_ \a value to an existing \a layer. The \a property_ string can be any as defined by the \l {https://www.mapbox.com/mapbox-gl-style-spec/} {Mapbox style specification} for layout properties. @@ -901,7 +940,7 @@ void QMapboxGL::setLayoutProperty(const QString& layer, const QString& property_ } /*! - Sets a paint \a property_ \a value to an existing \a layer. The \a property string can be any + Sets a paint \a property_ \a value to an existing \a layer. The \a property_ string can be any as defined by the \l {https://www.mapbox.com/mapbox-gl-style-spec/} {Mapbox style specification} for paint properties. @@ -1499,6 +1538,18 @@ QMapboxGLPrivate::QMapboxGLPrivate(QMapboxGL *q, const QMapboxGLSettings &settin settings.cacheDatabaseMaximumSize())) , threadPool(mbgl::sharedThreadPool()) { + // Setup resource transform if needed + if (settings.resourceTransform()) { + m_resourceTransform = + std::make_unique< mbgl::Actor<mbgl::ResourceTransform> >( *mbgl::Scheduler::GetCurrent(), + [callback = settings.resourceTransform()] + (mbgl::Resource::Kind , const std::string&& url_) -> std::string { + return callback(std::move(url_)); + } + ); + fileSourceObj->setResourceTransform(m_resourceTransform->self()); + } + // Setup and connect the renderer frontend frontend = std::make_unique<QMapboxGLRendererFrontend>( std::make_unique<mbgl::Renderer>(*this, pixelRatio, *fileSourceObj, *threadPool, @@ -1534,7 +1585,9 @@ mbgl::Size QMapboxGLPrivate::getFramebufferSize() const { void QMapboxGLPrivate::updateAssumedState() { assumeFramebufferBinding(fbObject); +#if QT_VERSION >= 0x050600 assumeViewport(0, 0, getFramebufferSize()); +#endif } void QMapboxGLPrivate::bind() { @@ -1642,7 +1695,7 @@ void QMapboxGLPrivate::onSourceChanged(mbgl::style::Source&) Initializes an OpenGL extension function such as Vertex Array Objects (VAOs), required by Mapbox GL Native engine. */ -mbgl::gl::ProcAddress QMapboxGLPrivate::initializeExtension(const char* name) { +mbgl::gl::ProcAddress QMapboxGLPrivate::getExtensionFunctionPointer(const char* name) { #if QT_VERSION >= 0x050000 QOpenGLContext* thisContext = QOpenGLContext::currentContext(); return thisContext->getProcAddress(name); diff --git a/platform/qt/src/qmapboxgl_p.hpp b/platform/qt/src/qmapboxgl_p.hpp index eb86870c10..f947c09f48 100644 --- a/platform/qt/src/qmapboxgl_p.hpp +++ b/platform/qt/src/qmapboxgl_p.hpp @@ -3,15 +3,19 @@ #include "qmapboxgl.hpp" #include "qmapboxgl_renderer_frontend_p.hpp" +#include <mbgl/actor/actor.hpp> #include <mbgl/map/map.hpp> #include <mbgl/renderer/renderer_backend.hpp> #include <mbgl/util/default_thread_pool.hpp> #include <mbgl/storage/default_file_source.hpp> #include <mbgl/util/geo.hpp> +#include <mbgl/storage/resource_transform.hpp> #include <QObject> #include <QSize> +#include <memory> + class QMapboxGLPrivate : public QObject, public mbgl::RendererBackend, public mbgl::MapObserver { Q_OBJECT @@ -57,7 +61,7 @@ public: bool dirty { false }; private: - mbgl::gl::ProcAddress initializeExtension(const char*) override; + mbgl::gl::ProcAddress getExtensionFunctionPointer(const char*) override; public slots: void connectionEstablished(); @@ -68,4 +72,7 @@ signals: void needsRendering(); void mapChanged(QMapboxGL::MapChange); void copyrightsChanged(const QString ©rightsHtml); + +private: + std::unique_ptr< mbgl::Actor<mbgl::ResourceTransform> > m_resourceTransform; }; diff --git a/platform/qt/src/qt_conversion.hpp b/platform/qt/src/qt_conversion.hpp index 40d7e5b928..19b0cb54fc 100644 --- a/platform/qt/src/qt_conversion.hpp +++ b/platform/qt/src/qt_conversion.hpp @@ -1,120 +1,145 @@ #pragma once #include <mbgl/style/conversion.hpp> -#include <mbgl/util/feature.hpp> +#include <mbgl/style/conversion/geojson.hpp> #include <mbgl/util/optional.hpp> -#include <QMapbox> - -#include <QColor> #include <QVariant> +#include <QColor> +#include <QMapbox> +#include "qt_geojson.hpp" namespace mbgl { namespace style { namespace conversion { -inline bool isUndefined(const QVariant& value) { - return value.isNull() || !value.isValid(); -} +template <> +class ConversionTraits<QVariant> { +public: + static bool isUndefined(const QVariant& value) { + return value.isNull() || !value.isValid(); + } -inline bool isArray(const QVariant& value) { - return value.canConvert(QVariant::List); -} + static bool isArray(const QVariant& value) { + return value.canConvert(QVariant::List); + } -inline std::size_t arrayLength(const QVariant& value) { - return value.toList().size(); -} + static std::size_t arrayLength(const QVariant& value) { + return value.toList().size(); + } -inline QVariant arrayMember(const QVariant& value, std::size_t i) { - return value.toList()[i]; -} + static QVariant arrayMember(const QVariant& value, std::size_t i) { + return value.toList()[i]; + } -inline bool isObject(const QVariant& value) { - return value.canConvert(QVariant::Map) - || value.type() == QVariant::ByteArray -#if QT_VERSION >= 0x050000 - || QString(value.typeName()) == QStringLiteral("QMapbox::Feature"); -#else - || QString(value.typeName()) == QString("QMapbox::Feature"); -#endif -} + static bool isObject(const QVariant& value) { + return value.canConvert(QVariant::Map) + || value.type() == QVariant::ByteArray + #if QT_VERSION >= 0x050000 + || QString(value.typeName()) == QStringLiteral("QMapbox::Feature"); + #else + || QString(value.typeName()) == QString("QMapbox::Feature"); + #endif + } -inline optional<QVariant> objectMember(const QVariant& value, const char* key) { - auto map = value.toMap(); - auto iter = map.constFind(key); + static optional<QVariant> objectMember(const QVariant& value, const char* key) { + auto map = value.toMap(); + auto iter = map.constFind(key); - if (iter != map.constEnd()) { - return iter.value(); - } else { - return {}; + if (iter != map.constEnd()) { + return iter.value(); + } else { + return {}; + } } -} -using EachMemberFn = std::function<optional<Error>(const std::string&, const QVariant&)>; + template <class Fn> + static optional<Error> eachMember(const QVariant& value, Fn&& fn) { + auto map = value.toMap(); + auto iter = map.constBegin(); -optional<Error> eachMember(const QVariant& value, EachMemberFn&& fn) { - auto map = value.toMap(); - auto iter = map.constBegin(); + while (iter != map.constEnd()) { + optional<Error> result = fn(iter.key().toStdString(), QVariant(iter.value())); + if (result) { + return result; + } - while (iter != map.constEnd()) { - optional<Error> result = fn(iter.key().toStdString(), iter.value()); - if (result) { - return result; + ++iter; } - ++iter; + return {}; } - return {}; -} + static optional<bool> toBool(const QVariant& value) { + if (value.type() == QVariant::Bool) { + return value.toBool(); + } else { + return {}; + } + } -inline optional<bool> toBool(const QVariant& value) { - if (value.type() == QVariant::Bool) { - return value.toBool(); - } else { - return {}; + static optional<float> toNumber(const QVariant& value) { + if (value.type() == QVariant::Int || value.type() == QVariant::Double) { + return value.toFloat(); + } else { + return {}; + } } -} -inline optional<float> toNumber(const QVariant& value) { - if (value.type() == QVariant::Int || value.type() == QVariant::Double) { - return value.toFloat(); - } else { - return {}; + static optional<double> toDouble(const QVariant& value) { + if (value.type() == QVariant::Int || value.type() == QVariant::Double) { + return value.toDouble(); + } else { + return {}; + } } -} -inline optional<double> toDouble(const QVariant& value) { - if (value.type() == QVariant::Int || value.type() == QVariant::Double) { - return value.toDouble(); - } else { - return {}; + + static optional<std::string> toString(const QVariant& value) { + if (value.type() == QVariant::String) { + return value.toString().toStdString(); + } else if (value.type() == QVariant::Color) { + return value.value<QColor>().name().toStdString(); + } else { + return {}; + } } -} -inline optional<std::string> toString(const QVariant& value) { - if (value.type() == QVariant::String) { - return value.toString().toStdString(); - } else if (value.type() == QVariant::Color) { - return value.value<QColor>().name().toStdString(); - } else { - return {}; + static optional<Value> toValue(const QVariant& value) { + if (value.type() == QVariant::Bool) { + return { value.toBool() }; + } else if (value.type() == QVariant::String) { + return { value.toString().toStdString() }; + } else if (value.type() == QVariant::Color) { + return { value.value<QColor>().name().toStdString() }; + } else if (value.type() == QVariant::Int) { + return { int64_t(value.toInt()) }; + } else if (value.canConvert(QVariant::Double)) { + return { value.toDouble() }; + } else { + return {}; + } } -} -inline optional<Value> toValue(const QVariant& value) { - if (value.type() == QVariant::Bool) { - return { value.toBool() }; - } else if (value.type() == QVariant::String) { - return { value.toString().toStdString() }; - } else if (value.type() == QVariant::Color) { - return { value.value<QColor>().name().toStdString() }; - } else if (value.type() == QVariant::Int) { - return { int64_t(value.toInt()) }; - } else if (value.canConvert(QVariant::Double)) { - return { value.toDouble() }; - } else { - return {}; + static optional<GeoJSON> toGeoJSON(const QVariant& value, Error& error) { + #if QT_VERSION >= 0x050000 + if (value.typeName() == QStringLiteral("QMapbox::Feature")) { + #else + if (value.typeName() == QString("QMapbox::Feature")) { + #endif + return GeoJSON { asMapboxGLFeature(value.value<QMapbox::Feature>()) }; + } else if (value.type() != QVariant::ByteArray) { + error = { "JSON data must be in QByteArray" }; + return {}; + } + + QByteArray data = value.toByteArray(); + return parseGeoJSON(std::string(data.constData(), data.size()), error); } +}; + +template <class T, class...Args> +optional<T> convert(const QVariant& value, Error& error, Args&&...args) { + return convert<T>(Convertible(value), error, std::forward<Args>(args)...); } } // namespace conversion diff --git a/platform/qt/src/qt_geojson.cpp b/platform/qt/src/qt_geojson.cpp new file mode 100644 index 0000000000..80377de64d --- /dev/null +++ b/platform/qt/src/qt_geojson.cpp @@ -0,0 +1,166 @@ +#include "qt_geojson.hpp" +#include <mapbox/geojson.hpp> +#include <mbgl/util/geometry.hpp> +#include <mbgl/util/feature.hpp> + +namespace QMapbox { + +mbgl::Point<double> asMapboxGLPoint(const QMapbox::Coordinate &coordinate) { + return mbgl::Point<double> { coordinate.second, coordinate.first }; +} + +mbgl::MultiPoint<double> asMapboxGLMultiPoint(const QMapbox::Coordinates &multiPoint) { + mbgl::MultiPoint<double> mbglMultiPoint; + mbglMultiPoint.reserve(multiPoint.size()); + for (const auto &point: multiPoint) { + mbglMultiPoint.emplace_back(asMapboxGLPoint(point)); + } + return mbglMultiPoint; +}; + +mbgl::LineString<double> asMapboxGLLineString(const QMapbox::Coordinates &lineString) { + mbgl::LineString<double> mbglLineString; + mbglLineString.reserve(lineString.size()); + for (const auto &coordinate : lineString) { + mbglLineString.emplace_back(asMapboxGLPoint(coordinate)); + } + return mbglLineString; +}; + +mbgl::MultiLineString<double> asMapboxGLMultiLineString(const QMapbox::CoordinatesCollection &multiLineString) { + mbgl::MultiLineString<double> mbglMultiLineString; + mbglMultiLineString.reserve(multiLineString.size()); + for (const auto &lineString : multiLineString) { + mbglMultiLineString.emplace_back(std::forward<mbgl::LineString<double>>(asMapboxGLLineString(lineString))); + } + return mbglMultiLineString; +}; + +mbgl::Polygon<double> asMapboxGLPolygon(const QMapbox::CoordinatesCollection &polygon) { + mbgl::Polygon<double> mbglPolygon; + mbglPolygon.reserve(polygon.size()); + for (const auto &linearRing : polygon) { + mbgl::LinearRing<double> mbglLinearRing; + mbglLinearRing.reserve(linearRing.size()); + for (const auto &coordinate: linearRing) { + mbglLinearRing.emplace_back(asMapboxGLPoint(coordinate)); + } + mbglPolygon.emplace_back(std::move(mbglLinearRing)); + } + return mbglPolygon; +}; + +mbgl::MultiPolygon<double> asMapboxGLMultiPolygon(const QMapbox::CoordinatesCollections &multiPolygon) { + mbgl::MultiPolygon<double> mbglMultiPolygon; + mbglMultiPolygon.reserve(multiPolygon.size()); + for (const auto &polygon : multiPolygon) { + mbglMultiPolygon.emplace_back(std::forward<mbgl::Polygon<double>>(asMapboxGLPolygon(polygon))); + } + return mbglMultiPolygon; +}; + +mbgl::Value asMapboxGLPropertyValue(const QVariant &value) { + auto valueList = [](const QVariantList &list) { + std::vector<mbgl::Value> mbglList; + mbglList.reserve(list.size()); + for (const auto& listValue : list) { + mbglList.emplace_back(asMapboxGLPropertyValue(listValue)); + } + return mbglList; + }; + + 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()) { + mbglMap.emplace(std::make_pair(it.key().toStdString(), asMapboxGLPropertyValue(it.value()))); + ++it; + } + return mbglMap; + }; + + switch (value.type()) { +#if QT_VERSION >= 0x050000 + case QMetaType::UnknownType: +#else + case QVariant::Invalid: +#endif + return mbgl::NullValue {}; + case QMetaType::Bool: + return { value.toBool() }; + case QMetaType::ULongLong: + return { uint64_t(value.toULongLong()) }; + case QMetaType::LongLong: + return { int64_t(value.toLongLong()) }; + case QMetaType::Double: + return { value.toDouble() }; + case QMetaType::QString: + return { value.toString().toStdString() }; + case QMetaType::QVariantList: + return valueList(value.toList()); + case QMetaType::QVariantMap: + return valueMap(value.toMap()); + default: + qWarning() << "Unsupported feature property value:" << value; + return {}; + } +} + +mbgl::FeatureIdentifier asMapboxGLFeatureIdentifier(const QVariant &id) { + switch (id.type()) { +#if QT_VERSION >= 0x050000 + case QMetaType::UnknownType: +#else + case QVariant::Invalid: +#endif + return {}; + case QMetaType::ULongLong: + return { uint64_t(id.toULongLong()) }; + case QMetaType::LongLong: + return { int64_t(id.toLongLong()) }; + case QMetaType::Double: + return { id.toDouble() }; + case QMetaType::QString: + return { id.toString().toStdString() }; + default: + qWarning() << "Unsupported feature identifier:" << id; + return {}; + } +} + +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()) { + properties.emplace(std::make_pair(it.key().toStdString(), asMapboxGLPropertyValue(it.value()))); + } + + mbgl::FeatureIdentifier id = asMapboxGLFeatureIdentifier(feature.id); + + if (feature.type == QMapbox::Feature::PointType) { + const QMapbox::Coordinates &points = feature.geometry.first().first(); + if (points.size() == 1) { + return { asMapboxGLPoint(points.first()), std::move(properties), std::move(id) }; + } else { + return { asMapboxGLMultiPoint(points), std::move(properties), std::move(id) }; + } + } else if (feature.type == QMapbox::Feature::LineStringType) { + const QMapbox::CoordinatesCollection &lineStrings = feature.geometry.first(); + if (lineStrings.size() == 1) { + return { asMapboxGLLineString(lineStrings.first()), std::move(properties), std::move(id) }; + } else { + return { asMapboxGLMultiLineString(lineStrings), std::move(properties), std::move(id) }; + } + } else { // PolygonType + const QMapbox::CoordinatesCollections &polygons = feature.geometry; + if (polygons.size() == 1) { + return { asMapboxGLPolygon(polygons.first()), std::move(properties), std::move(id) }; + } else { + return { asMapboxGLMultiPolygon(polygons), std::move(properties), std::move(id) }; + } + } +}; + +} // namespace QMapbox diff --git a/platform/qt/src/qt_geojson.hpp b/platform/qt/src/qt_geojson.hpp index a6958b7edc..a9c10272ab 100644 --- a/platform/qt/src/qt_geojson.hpp +++ b/platform/qt/src/qt_geojson.hpp @@ -1,7 +1,8 @@ #pragma once #include <mapbox/geojson.hpp> -#include <mbgl/style/conversion/geojson.hpp> +#include <mbgl/util/geometry.hpp> +#include <mbgl/util/feature.hpp> #include <QMapbox> @@ -13,187 +14,14 @@ namespace QMapbox { -mbgl::Point<double> asMapboxGLPoint(const QMapbox::Coordinate &coordinate) { - return mbgl::Point<double> { coordinate.second, coordinate.first }; -} - -mbgl::MultiPoint<double> asMapboxGLMultiPoint(const QMapbox::Coordinates &multiPoint) { - mbgl::MultiPoint<double> mbglMultiPoint; - mbglMultiPoint.reserve(multiPoint.size()); - for (const auto &point: multiPoint) { - mbglMultiPoint.emplace_back(asMapboxGLPoint(point)); - } - return mbglMultiPoint; -}; - -mbgl::LineString<double> asMapboxGLLineString(const QMapbox::Coordinates &lineString) { - mbgl::LineString<double> mbglLineString; - mbglLineString.reserve(lineString.size()); - for (const auto &coordinate : lineString) { - mbglLineString.emplace_back(asMapboxGLPoint(coordinate)); - } - return mbglLineString; -}; - -mbgl::MultiLineString<double> asMapboxGLMultiLineString(const QMapbox::CoordinatesCollection &multiLineString) { - mbgl::MultiLineString<double> mbglMultiLineString; - mbglMultiLineString.reserve(multiLineString.size()); - for (const auto &lineString : multiLineString) { - mbglMultiLineString.emplace_back(std::forward<mbgl::LineString<double>>(asMapboxGLLineString(lineString))); - } - return mbglMultiLineString; -}; - -mbgl::Polygon<double> asMapboxGLPolygon(const QMapbox::CoordinatesCollection &polygon) { - mbgl::Polygon<double> mbglPolygon; - mbglPolygon.reserve(polygon.size()); - for (const auto &linearRing : polygon) { - mbgl::LinearRing<double> mbglLinearRing; - mbglLinearRing.reserve(linearRing.size()); - for (const auto &coordinate: linearRing) { - mbglLinearRing.emplace_back(asMapboxGLPoint(coordinate)); - } - mbglPolygon.emplace_back(std::move(mbglLinearRing)); - } - return mbglPolygon; -}; - -mbgl::MultiPolygon<double> asMapboxGLMultiPolygon(const QMapbox::CoordinatesCollections &multiPolygon) { - mbgl::MultiPolygon<double> mbglMultiPolygon; - mbglMultiPolygon.reserve(multiPolygon.size()); - for (const auto &polygon : multiPolygon) { - mbglMultiPolygon.emplace_back(std::forward<mbgl::Polygon<double>>(asMapboxGLPolygon(polygon))); - } - return mbglMultiPolygon; -}; - -mbgl::Value asMapboxGLPropertyValue(const QVariant &value) { - auto valueList = [](const QVariantList &list) { - std::vector<mbgl::Value> mbglList; - mbglList.reserve(list.size()); - for (const auto& listValue : list) { - mbglList.emplace_back(asMapboxGLPropertyValue(listValue)); - } - return mbglList; - }; - - 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()) { - mbglMap.emplace(std::make_pair(it.key().toStdString(), asMapboxGLPropertyValue(it.value()))); - ++it; - } - return mbglMap; - }; - - switch (value.type()) { -#if QT_VERSION >= 0x050000 - case QMetaType::UnknownType: -#else - case QVariant::Invalid: -#endif - return mbgl::NullValue {}; - case QMetaType::Bool: - return { value.toBool() }; - case QMetaType::ULongLong: - return { uint64_t(value.toULongLong()) }; - case QMetaType::LongLong: - return { int64_t(value.toLongLong()) }; - case QMetaType::Double: - return { value.toDouble() }; - case QMetaType::QString: - return { value.toString().toStdString() }; - case QMetaType::QVariantList: - return valueList(value.toList()); - case QMetaType::QVariantMap: - return valueMap(value.toMap()); - default: - qWarning() << "Unsupported feature property value:" << value; - return {}; - } -} - -mbgl::FeatureIdentifier asMapboxGLFeatureIdentifier(const QVariant &id) { - switch (id.type()) { -#if QT_VERSION >= 0x050000 - case QMetaType::UnknownType: -#else - case QVariant::Invalid: -#endif - return {}; - case QMetaType::ULongLong: - return { uint64_t(id.toULongLong()) }; - case QMetaType::LongLong: - return { int64_t(id.toLongLong()) }; - case QMetaType::Double: - return { id.toDouble() }; - case QMetaType::QString: - return { id.toString().toStdString() }; - default: - qWarning() << "Unsupported feature identifier:" << id; - return {}; - } -} - -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()) { - properties.emplace(std::make_pair(it.key().toStdString(), asMapboxGLPropertyValue(it.value()))); - } - - mbgl::FeatureIdentifier id = asMapboxGLFeatureIdentifier(feature.id); - - if (feature.type == QMapbox::Feature::PointType) { - const QMapbox::Coordinates &points = feature.geometry.first().first(); - if (points.size() == 1) { - return { asMapboxGLPoint(points.first()), std::move(properties), std::move(id) }; - } else { - return { asMapboxGLMultiPoint(points), std::move(properties), std::move(id) }; - } - } else if (feature.type == QMapbox::Feature::LineStringType) { - const QMapbox::CoordinatesCollection &lineStrings = feature.geometry.first(); - if (lineStrings.size() == 1) { - return { asMapboxGLLineString(lineStrings.first()), std::move(properties), std::move(id) }; - } else { - return { asMapboxGLMultiLineString(lineStrings), std::move(properties), std::move(id) }; - } - } else { // PolygonType - const QMapbox::CoordinatesCollections &polygons = feature.geometry; - if (polygons.size() == 1) { - return { asMapboxGLPolygon(polygons.first()), std::move(properties), std::move(id) }; - } else { - return { asMapboxGLMultiPolygon(polygons), std::move(properties), std::move(id) }; - } - } -}; +mbgl::Point<double> asMapboxGLPoint(const QMapbox::Coordinate &coordinate); +mbgl::MultiPoint<double> asMapboxGLMultiPoint(const QMapbox::Coordinates &multiPoint); +mbgl::LineString<double> asMapboxGLLineString(const QMapbox::Coordinates &lineString); +mbgl::MultiLineString<double> asMapboxGLMultiLineString(const QMapbox::CoordinatesCollection &multiLineString); +mbgl::Polygon<double> asMapboxGLPolygon(const QMapbox::CoordinatesCollection &polygon); +mbgl::MultiPolygon<double> asMapboxGLMultiPolygon(const QMapbox::CoordinatesCollections &multiPolygon); +mbgl::Value asMapboxGLPropertyValue(const QVariant &value); +mbgl::FeatureIdentifier asMapboxGLFeatureIdentifier(const QVariant &id); +mbgl::Feature asMapboxGLFeature(const QMapbox::Feature &feature); } // namespace QMapbox - -namespace mbgl { -namespace style { -namespace conversion { - -template <> -optional<GeoJSON> Converter<GeoJSON>::operator()(const QVariant& value, Error& error) const { -#if QT_VERSION >= 0x050000 - if (value.typeName() == QStringLiteral("QMapbox::Feature")) { -#else - if (value.typeName() == QString("QMapbox::Feature")) { -#endif - return GeoJSON { asMapboxGLFeature(value.value<QMapbox::Feature>()) }; - } else if (value.type() != QVariant::ByteArray) { - error = { "JSON data must be in QByteArray" }; - return {}; - } - - QByteArray data = value.toByteArray(); - return convert<GeoJSON>(std::string(data.constData(), data.size()), error); -} - -} // namespace conversion -} // namespace style -} // namespace mbgl diff --git a/platform/qt/src/qt_image.cpp b/platform/qt/src/qt_image.cpp index 403ca9cbd3..a5c92514c1 100644 --- a/platform/qt/src/qt_image.cpp +++ b/platform/qt/src/qt_image.cpp @@ -54,8 +54,13 @@ PremultipliedImage decodeImage(const std::string& string) { throw std::runtime_error("Unsupported image type"); } +#if QT_VERSION >= 0x051000 + auto img = std::make_unique<uint8_t[]>(image.sizeInBytes()); + memcpy(img.get(), image.constBits(), image.sizeInBytes()); +#else auto img = std::make_unique<uint8_t[]>(image.byteCount()); memcpy(img.get(), image.constBits(), image.byteCount()); +#endif return { { static_cast<uint32_t>(image.width()), static_cast<uint32_t>(image.height()) }, std::move(img) }; diff --git a/platform/qt/src/qt_logging.cpp b/platform/qt/src/qt_logging.cpp new file mode 100755 index 0000000000..acbe9562d0 --- /dev/null +++ b/platform/qt/src/qt_logging.cpp @@ -0,0 +1,12 @@ +#include <mbgl/util/logging.hpp> +#include <mbgl/util/enum.hpp> + +#include <QDebug> + +namespace mbgl { + +void Log::platformRecord(EventSeverity severity, const std::string &msg) { + qWarning() << "[" << Enum<EventSeverity>::toString(severity) << "] " << QString::fromStdString(msg); +} + +} // namespace mbgl diff --git a/platform/qt/src/sqlite3.cpp b/platform/qt/src/sqlite3.cpp index 7d47ae552b..2f3db12f33 100644 --- a/platform/qt/src/sqlite3.cpp +++ b/platform/qt/src/sqlite3.cpp @@ -6,6 +6,7 @@ #include <QStringList> #include <QThread> #include <QVariant> +#include <QAtomicInt> #include <cassert> #include <cstring> @@ -60,20 +61,26 @@ void checkDatabaseOpenError(const QSqlDatabase &db) { } } +namespace { + QString incrementCounter() { + static QAtomicInt count = 0; + return QString::number(count.fetchAndAddAcquire(1)); + } +} + class DatabaseImpl { public: - DatabaseImpl(const char* filename, int flags) { - static uint64_t count = 0; - const QString connectionName = QString::number(uint64_t(QThread::currentThread())) + QString::number(count++); - + DatabaseImpl(const char* filename, int flags) + : connectionName(QString::number(uint64_t(QThread::currentThread())) + incrementCounter()) + { if (!QSqlDatabase::drivers().contains("QSQLITE")) { throw Exception { Exception::Code::CANTOPEN, "SQLite driver not found." }; } assert(!QSqlDatabase::contains(connectionName)); - db.reset(new QSqlDatabase(QSqlDatabase::addDatabase("QSQLITE", connectionName))); + auto db = QSqlDatabase::addDatabase("QSQLITE", connectionName); - QString connectOptions = db->connectOptions(); + QString connectOptions = db.connectOptions(); if (flags & OpenFlag::ReadOnly) { if (!connectOptions.isEmpty()) connectOptions.append(';'); connectOptions.append("QSQLITE_OPEN_READONLY"); @@ -83,26 +90,26 @@ public: connectOptions.append("QSQLITE_ENABLE_SHARED_CACHE"); } - db->setConnectOptions(connectOptions); - db->setDatabaseName(QString(filename)); + db.setConnectOptions(connectOptions); + db.setDatabaseName(QString(filename)); - if (!db->open()) { - checkDatabaseOpenError(*db); + if (!db.open()) { + checkDatabaseOpenError(db); } } ~DatabaseImpl() { - db->close(); - checkDatabaseError(*db); + auto db = QSqlDatabase::database(connectionName); + db.close(); + checkDatabaseError(db); } - QScopedPointer<QSqlDatabase> db; + QString connectionName; }; class StatementImpl { public: StatementImpl(const QString& sql, const QSqlDatabase& db) : query(db) { - query.setForwardOnly(true); if (!query.prepare(sql)) { checkQueryError(query); } @@ -147,17 +154,18 @@ void Database::setBusyTimeout(std::chrono::milliseconds timeout) { // internally to int, so we need to make sure the limits apply. std::string timeoutStr = mbgl::util::toString(timeout.count() & INT_MAX); - QString connectOptions = impl->db->connectOptions(); + auto db = QSqlDatabase::database(impl->connectionName); + QString connectOptions = db.connectOptions(); if (connectOptions.isEmpty()) { if (!connectOptions.isEmpty()) connectOptions.append(';'); connectOptions.append("QSQLITE_BUSY_TIMEOUT=").append(QString::fromStdString(timeoutStr)); } - if (impl->db->isOpen()) { - impl->db->close(); + if (db.isOpen()) { + db.close(); } - impl->db->setConnectOptions(connectOptions); - if (!impl->db->open()) { - checkDatabaseOpenError(*impl->db); + db.setConnectOptions(connectOptions); + if (!db.open()) { + checkDatabaseOpenError(db); } } @@ -169,9 +177,9 @@ void Database::exec(const std::string &sql) { if (!statement.endsWith(';')) { statement.append(';'); } - QSqlQuery query(*impl->db); - query.setForwardOnly(true); + QSqlQuery query(QSqlDatabase::database(impl->connectionName)); query.prepare(statement); + if (!query.exec()) { checkQueryError(query); } @@ -183,7 +191,7 @@ Statement Database::prepare(const char *query) { } Statement::Statement(Database *db, const char *sql) - : impl(std::make_unique<StatementImpl>(QString(sql), *db->impl->db)) { + : impl(std::make_unique<StatementImpl>(QString(sql), QSqlDatabase::database(db->impl->connectionName))) { assert(impl); } @@ -269,9 +277,13 @@ void Statement::bind(int offset, const char* value, std::size_t length, bool ret throw std::range_error("value too long"); } + // Qt SQLite driver treats QByteArray as blob: we need to explicitly + // declare the variant type as string. + QVariant text(QVariant::Type::String); + text.setValue(retain ? QByteArray(value, length) : QByteArray::fromRawData(value, length)); + // Field numbering starts at 0. - impl->query.bindValue(offset - 1, retain ? QByteArray(value, length) : - QByteArray::fromRawData(value, length), QSql::In); + impl->query.bindValue(offset - 1, std::move(text), QSql::In); checkQueryError(impl->query); } @@ -281,7 +293,12 @@ void Statement::bind(int offset, const std::string& value, bool retain) { } void Statement::bindBlob(int offset, const void* value_, std::size_t length, bool retain) { + assert(impl); const char* value = reinterpret_cast<const char*>(value_); + if (length > std::numeric_limits<int>::max()) { + // Kept for consistence with the default implementation. + throw std::range_error("value too long"); + } // Field numbering starts at 0. impl->query.bindValue(offset - 1, retain ? QByteArray(value, length) : @@ -296,20 +313,20 @@ void Statement::bindBlob(int offset, const std::vector<uint8_t>& value, bool ret bool Statement::run() { assert(impl); - if (impl->query.isValid()) { - return impl->query.next(); - } - assert(!impl->query.isActive()); - impl->query.setForwardOnly(true); - if (!impl->query.exec()) { - checkQueryError(impl->query); + if (!impl->query.isValid()) { + if (impl->query.exec()) { + impl->lastInsertRowId = impl->query.lastInsertId().value<int64_t>(); + impl->changes = impl->query.numRowsAffected(); + } else { + checkQueryError(impl->query); + } } - impl->lastInsertRowId = impl->query.lastInsertId().value<int64_t>(); - impl->changes = impl->query.numRowsAffected(); + const bool hasNext = impl->query.next(); + if (!hasNext) impl->query.finish(); - return impl->query.next(); + return hasNext; } template bool Statement::get(int); |