diff options
Diffstat (limited to 'src/plugins')
79 files changed, 6912 insertions, 158 deletions
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro b/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro index 27b3a5b513..f3f8a21ff8 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro +++ b/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro @@ -2,10 +2,8 @@ TARGET = qmldbg_debugger QT = qml-private core-private packetprotocol-private SOURCES += \ - $$PWD/qdebugmessageservice.cpp \ $$PWD/qqmldebuggerservicefactory.cpp \ $$PWD/qqmlenginedebugservice.cpp \ - $$PWD/qqmlnativedebugservice.cpp \ $$PWD/qqmlwatcher.cpp \ $$PWD/qv4debugservice.cpp \ $$PWD/qv4debugger.cpp \ @@ -16,10 +14,8 @@ SOURCES += \ HEADERS += \ $$PWD/../shared/qqmlconfigurabledebugservice.h \ $$PWD/../shared/qqmldebugpacket.h \ - $$PWD/qdebugmessageservice.h \ $$PWD/qqmldebuggerservicefactory.h \ $$PWD/qqmlenginedebugservice.h \ - $$PWD/qqmlnativedebugservice.h \ $$PWD/qqmlwatcher.h \ $$PWD/qv4debugservice.h \ $$PWD/qv4debugger.h \ diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservice.json b/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservice.json index 967a725903..442d7781a1 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservice.json +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservice.json @@ -1,3 +1,3 @@ { - "Keys": [ "DebugMessages", "QmlDebugger", "V8Debugger", "NativeQmlDebugger" ] + "Keys": [ "QmlDebugger", "V8Debugger" ] } diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp index ca3f07323d..9315adf4ce 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp @@ -39,27 +39,19 @@ #include "qqmldebuggerservicefactory.h" #include "qqmlenginedebugservice.h" -#include "qdebugmessageservice.h" #include "qv4debugservice.h" -#include "qqmlnativedebugservice.h" #include <private/qqmldebugserviceinterfaces_p.h> QT_BEGIN_NAMESPACE QQmlDebugService *QQmlDebuggerServiceFactory::create(const QString &key) { - if (key == QDebugMessageServiceImpl::s_key) - return new QDebugMessageServiceImpl(this); - if (key == QQmlEngineDebugServiceImpl::s_key) return new QQmlEngineDebugServiceImpl(this); if (key == QV4DebugServiceImpl::s_key) return new QV4DebugServiceImpl(this); - if (key == QQmlNativeDebugServiceImpl::s_key) - return new QQmlNativeDebugServiceImpl(this); - return 0; } diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.h b/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.h index 99d6679833..50eed2369c 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.h @@ -49,7 +49,7 @@ class QQmlDebuggerServiceFactory : public QQmlDebugServiceFactory Q_OBJECT Q_PLUGIN_METADATA(IID QQmlDebugServiceFactory_iid FILE "qqmldebuggerservice.json") public: - QQmlDebugService *create(const QString &key); + QQmlDebugService *create(const QString &key) override; }; QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp index f72b8a51f9..fe88d686fc 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp @@ -289,10 +289,12 @@ void QQmlEngineDebugServiceImpl::buildObjectDump(QDataStream &message, prop.value = expr->expression(); QObject *scope = expr->scopeObject(); if (scope) { - QString methodName = QString::fromLatin1(QMetaObjectPrivate::signal(scope->metaObject(), signalHandler->signalIndex()).name()); - if (!methodName.isEmpty()) { - prop.name = QLatin1String("on") + methodName[0].toUpper() - + methodName.mid(1); + const QByteArray methodName = QMetaObjectPrivate::signal(scope->metaObject(), + signalHandler->signalIndex()).name(); + const QLatin1String methodNameStr(methodName); + if (methodNameStr.size() != 0) { + prop.name = QLatin1String("on") + QChar(methodNameStr.at(0)).toUpper() + + methodNameStr.mid(1); } } } @@ -520,12 +522,12 @@ void QQmlEngineDebugServiceImpl::processMessage(const QByteArray &message) ds >> file >> lineNumber >> columnNumber >> recurse >> dumpProperties; - QList<QObject*> objects = objectForLocationInfo(file, lineNumber, columnNumber); + const QList<QObject*> objects = objectForLocationInfo(file, lineNumber, columnNumber); rs << QByteArray("FETCH_OBJECTS_FOR_LOCATION_R") << queryId << objects.count(); - foreach (QObject *object, objects) { + for (QObject *object : objects) { if (recurse) prepareDeferredObjects(object); buildObjectDump(rs, object, recurse, dumpProperties); diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp index 756b6b28be..773bc937f5 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp @@ -52,7 +52,7 @@ QV4DebuggerAgent::QV4DebuggerAgent(QV4DebugServiceImpl *debugService) QV4Debugger *QV4DebuggerAgent::pausedDebugger() const { - foreach (QV4Debugger *debugger, m_debuggers) { + for (QV4Debugger *debugger : m_debuggers) { if (debugger->state() == QV4Debugger::Paused) return debugger; } @@ -147,13 +147,13 @@ void QV4DebuggerAgent::pause(QV4Debugger *debugger) const void QV4DebuggerAgent::pauseAll() const { - foreach (QV4Debugger *debugger, m_debuggers) + for (QV4Debugger *debugger : m_debuggers) pause(debugger); } void QV4DebuggerAgent::resumeAll() const { - foreach (QV4Debugger *debugger, m_debuggers) + for (QV4Debugger *debugger : m_debuggers) if (debugger->state() == QV4Debugger::Paused) debugger->resume(QV4Debugger::FullThrottle); } @@ -161,7 +161,7 @@ void QV4DebuggerAgent::resumeAll() const int QV4DebuggerAgent::addBreakPoint(const QString &fileName, int lineNumber, bool enabled, const QString &condition) { if (enabled) - foreach (QV4Debugger *debugger, m_debuggers) + for (QV4Debugger *debugger : qAsConst(m_debuggers)) debugger->addBreakPoint(fileName, lineNumber, condition); int id = m_breakPoints.size(); @@ -178,7 +178,7 @@ void QV4DebuggerAgent::removeBreakPoint(int id) m_breakPoints.remove(id); if (breakPoint.enabled) - foreach (QV4Debugger *debugger, m_debuggers) + for (QV4Debugger *debugger : qAsConst(m_debuggers)) debugger->removeBreakPoint(breakPoint.fileName, breakPoint.lineNr); } @@ -195,7 +195,7 @@ void QV4DebuggerAgent::enableBreakPoint(int id, bool onoff) return; breakPoint.enabled = onoff; - foreach (QV4Debugger *debugger, m_debuggers) { + for (QV4Debugger *debugger : qAsConst(m_debuggers)) { if (onoff) debugger->addBreakPoint(breakPoint.fileName, breakPoint.lineNr, breakPoint.condition); else @@ -218,14 +218,14 @@ void QV4DebuggerAgent::setBreakOnThrow(bool onoff) { if (onoff != m_breakOnThrow) { m_breakOnThrow = onoff; - foreach (QV4Debugger *debugger, m_debuggers) + for (QV4Debugger *debugger : qAsConst(m_debuggers)) debugger->setBreakOnThrow(onoff); } } void QV4DebuggerAgent::clearAllPauseRequests() { - foreach (QV4Debugger *debugger, m_debuggers) + for (QV4Debugger *debugger : qAsConst(m_debuggers)) debugger->clearPauseRequest(); } diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp index a2d2fff72b..6c1e353b4d 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp @@ -42,6 +42,7 @@ #include <private/qv4script_p.h> #include <private/qqmlcontext_p.h> #include <private/qv4qobjectwrapper_p.h> +#include <private/qqmldebugservice_p.h> #include <QtQml/qqmlengine.h> @@ -51,9 +52,10 @@ QV4DebugJob::~QV4DebugJob() { } -JavaScriptJob::JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr, - const QString &script) : - engine(engine), frameNr(frameNr), script(script), resultIsException(false) +JavaScriptJob::JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr, int context, + const QString &script) : + engine(engine), frameNr(frameNr), context(context), script(script), + resultIsException(false) {} void JavaScriptJob::run() @@ -64,7 +66,23 @@ void JavaScriptJob::run() QV4::ExecutionContext *ctx = engine->currentContext; QObject scopeObject; - if (frameNr < 0) { // Use QML context if available + + if (frameNr > 0) { + for (int i = 0; i < frameNr; ++i) { + ctx = engine->parentContext(ctx); + } + engine->pushContext(ctx); + ctx = engine->currentContext; + } + + if (context >= 0) { + QQmlContext *extraContext = qmlContext(QQmlDebugService::objectForId(context)); + if (extraContext) { + engine->pushContext(ctx->newQmlContext(QQmlContextData::get(extraContext), + &scopeObject)); + ctx = engine->currentContext; + } + } else if (frameNr < 0) { // Use QML context if available QQmlEngine *qmlEngine = engine->qmlEngine(); if (qmlEngine) { QQmlContext *qmlRootContext = qmlEngine->rootContext(); @@ -88,13 +106,6 @@ void JavaScriptJob::run() engine->pushContext(ctx->newWithContext(withContext->toObject(engine))); ctx = engine->currentContext; } - } else { - if (frameNr > 0) { - for (int i = 0; i < frameNr; ++i) { - ctx = engine->parentContext(ctx); - } - engine->pushContext(ctx); - } } QV4::Script script(ctx, this->script); @@ -205,7 +216,7 @@ void ValueLookupJob::run() QQmlContextData::get(engine->qmlEngine()->rootContext()), scopeObject.data())); } - foreach (const QJsonValue &handle, handles) { + for (const QJsonValue &handle : handles) { QV4DataCollector::Ref ref = handle.toInt(); if (!collector->isValidRef(ref)) { exception = QString::fromLatin1("Invalid Ref: %1").arg(ref); @@ -224,8 +235,9 @@ const QString &ValueLookupJob::exceptionMessage() const } ExpressionEvalJob::ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, - const QString &expression, QV4DataCollector *collector) : - JavaScriptJob(engine, frameNr, expression), collector(collector) + int context, const QString &expression, + QV4DataCollector *collector) : + JavaScriptJob(engine, frameNr, context, expression), collector(collector) { } @@ -258,7 +270,7 @@ GatherSourcesJob::GatherSourcesJob(QV4::ExecutionEngine *engine) void GatherSourcesJob::run() { - foreach (QV4::CompiledData::CompilationUnit *unit, engine->compilationUnits) { + for (QV4::CompiledData::CompilationUnit *unit : qAsConst(engine->compilationUnits)) { QString fileName = unit->fileName(); if (!fileName.isEmpty()) sources.append(fileName); @@ -271,7 +283,7 @@ const QStringList &GatherSourcesJob::result() const } EvalJob::EvalJob(QV4::ExecutionEngine *engine, const QString &script) : - JavaScriptJob(engine, /*frameNr*/-1, script), result(false) + JavaScriptJob(engine, /*frameNr*/-1, /*context*/ -1, script), result(false) {} void EvalJob::handleResult(QV4::ScopedValue &result) diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h index 721f42b7c2..00d3e6206a 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h @@ -60,12 +60,13 @@ class JavaScriptJob : public QV4DebugJob { QV4::ExecutionEngine *engine; int frameNr; + int context; const QString &script; bool resultIsException; public: - JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr, const QString &script); - void run(); + JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr, int context, const QString &script); + void run() override; bool hasExeption() const; protected: @@ -90,7 +91,7 @@ class BacktraceJob: public CollectJob int toFrame; public: BacktraceJob(QV4DataCollector *collector, int fromFrame, int toFrame); - void run(); + void run() override; }; class FrameJob: public CollectJob @@ -100,7 +101,7 @@ class FrameJob: public CollectJob public: FrameJob(QV4DataCollector *collector, int frameNr); - void run(); + void run() override; bool wasSuccessful() const; }; @@ -112,7 +113,7 @@ class ScopeJob: public CollectJob public: ScopeJob(QV4DataCollector *collector, int frameNr, int scopeNr); - void run(); + void run() override; bool wasSuccessful() const; }; @@ -123,7 +124,7 @@ class ValueLookupJob: public CollectJob public: ValueLookupJob(const QJsonArray &handles, QV4DataCollector *collector); - void run(); + void run() override; const QString &exceptionMessage() const; }; @@ -135,9 +136,9 @@ class ExpressionEvalJob: public JavaScriptJob QJsonArray collectedRefs; public: - ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, const QString &expression, - QV4DataCollector *collector); - virtual void handleResult(QV4::ScopedValue &value); + ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, int context, + const QString &expression, QV4DataCollector *collector); + void handleResult(QV4::ScopedValue &value) override; const QString &exceptionMessage() const; const QJsonObject &returnValue() const; const QJsonArray &refs() const; @@ -150,7 +151,7 @@ class GatherSourcesJob: public QV4DebugJob public: GatherSourcesJob(QV4::ExecutionEngine *engine); - void run(); + void run() override; const QStringList &result() const; }; @@ -161,7 +162,7 @@ class EvalJob: public JavaScriptJob public: EvalJob(QV4::ExecutionEngine *engine, const QString &script); - virtual void handleResult(QV4::ScopedValue &result); + void handleResult(QV4::ScopedValue &result) override; bool resultAsBoolean() const; }; diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp index 00c5c1ad77..1d2cc092dc 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp @@ -152,7 +152,7 @@ class UnknownV8CommandHandler: public V8CommandHandler public: UnknownV8CommandHandler(): V8CommandHandler(QString()) {} - virtual void handleRequest() + void handleRequest() override { QString msg = QLatin1String("unimplemented command \"") + req.value(QLatin1String("command")).toString() @@ -167,7 +167,7 @@ class V8VersionRequest: public V8CommandHandler public: V8VersionRequest(): V8CommandHandler(QStringLiteral("version")) {} - virtual void handleRequest() + void handleRequest() override { addCommand(); addRequestSequence(); @@ -177,6 +177,7 @@ public: body.insert(QStringLiteral("V8Version"), QLatin1String("this is not V8, this is V4 in Qt " QT_VERSION_STR)); body.insert(QStringLiteral("UnpausedEvaluate"), true); + body.insert(QStringLiteral("ContextEvaluate"), true); addBody(body); } }; @@ -186,7 +187,7 @@ class V8SetBreakPointRequest: public V8CommandHandler public: V8SetBreakPointRequest(): V8CommandHandler(QStringLiteral("setbreakpoint")) {} - virtual void handleRequest() + void handleRequest() override { // decypher the payload: QJsonObject args = req.value(QLatin1String("arguments")).toObject(); @@ -237,7 +238,7 @@ class V8ClearBreakPointRequest: public V8CommandHandler public: V8ClearBreakPointRequest(): V8CommandHandler(QStringLiteral("clearbreakpoint")) {} - virtual void handleRequest() + void handleRequest() override { // decypher the payload: QJsonObject args = req.value(QLatin1String("arguments")).toObject(); @@ -270,7 +271,7 @@ class V8BacktraceRequest: public V8CommandHandler public: V8BacktraceRequest(): V8CommandHandler(QStringLiteral("backtrace")) {} - virtual void handleRequest() + void handleRequest() override { // decypher the payload: @@ -303,7 +304,7 @@ class V8FrameRequest: public V8CommandHandler public: V8FrameRequest(): V8CommandHandler(QStringLiteral("frame")) {} - virtual void handleRequest() + void handleRequest() override { // decypher the payload: QJsonObject arguments = req.value(QLatin1String("arguments")).toObject(); @@ -345,7 +346,7 @@ class V8ScopeRequest: public V8CommandHandler public: V8ScopeRequest(): V8CommandHandler(QStringLiteral("scope")) {} - virtual void handleRequest() + void handleRequest() override { // decypher the payload: QJsonObject arguments = req.value(QLatin1String("arguments")).toObject(); @@ -390,7 +391,7 @@ class V8LookupRequest: public V8CommandHandler public: V8LookupRequest(): V8CommandHandler(QStringLiteral("lookup")) {} - virtual void handleRequest() + void handleRequest() override { // decypher the payload: QJsonObject arguments = req.value(QLatin1String("arguments")).toObject(); @@ -430,7 +431,7 @@ class V8ContinueRequest: public V8CommandHandler public: V8ContinueRequest(): V8CommandHandler(QStringLiteral("continue")) {} - virtual void handleRequest() + void handleRequest() override { // decypher the payload: QJsonObject arguments = req.value(QLatin1String("arguments")).toObject(); @@ -476,7 +477,7 @@ class V8DisconnectRequest: public V8CommandHandler public: V8DisconnectRequest(): V8CommandHandler(QStringLiteral("disconnect")) {} - virtual void handleRequest() + void handleRequest() override { debugService->debuggerAgent.removeAllBreakPoints(); debugService->debuggerAgent.resumeAll(); @@ -494,7 +495,7 @@ class V8SetExceptionBreakRequest: public V8CommandHandler public: V8SetExceptionBreakRequest(): V8CommandHandler(QStringLiteral("setexceptionbreak")) {} - virtual void handleRequest() + void handleRequest() override { bool wasEnabled = debugService->debuggerAgent.breakOnThrow(); @@ -534,7 +535,7 @@ class V8ScriptsRequest: public V8CommandHandler public: V8ScriptsRequest(): V8CommandHandler(QStringLiteral("scripts")) {} - virtual void handleRequest() + void handleRequest() override { //decypher the payload: QJsonObject arguments = req.value(QLatin1String("arguments")).toObject(); @@ -558,7 +559,7 @@ public: debugger->runInEngine(&job); QJsonArray body; - foreach (const QString &source, job.result()) { + for (const QString &source : job.result()) { QJsonObject src; src[QLatin1String("name")] = source; src[QLatin1String("scriptType")] = 4; @@ -606,10 +607,11 @@ class V8EvaluateRequest: public V8CommandHandler public: V8EvaluateRequest(): V8CommandHandler(QStringLiteral("evaluate")) {} - virtual void handleRequest() + void handleRequest() override { QJsonObject arguments = req.value(QLatin1String("arguments")).toObject(); QString expression = arguments.value(QLatin1String("expression")).toString(); + int context = arguments.value(QLatin1String("context")).toInt(-1); int frame = -1; QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger(); @@ -627,7 +629,8 @@ public: frame = arguments.value(QLatin1String("frame")).toInt(0); } - ExpressionEvalJob job(debugger->engine(), frame, expression, debugger->collector()); + ExpressionEvalJob job(debugger->engine(), frame, context, expression, + debugger->collector()); debugger->runInEngine(&job); if (job.hasExeption()) { createErrorResponse(job.exceptionMessage()); @@ -718,7 +721,8 @@ void QV4DebugServiceImpl::stateAboutToBeChanged(State state) { QMutexLocker lock(&m_configMutex); if (state == Enabled) { - foreach (QV4Debugger *debugger, debuggerAgent.debuggers()) { + const auto debuggers = debuggerAgent.debuggers(); + for (QV4Debugger *debugger : debuggers) { QV4::ExecutionEngine *ee = debugger->engine(); if (!ee->debugger()) ee->setDebugger(debugger); @@ -737,7 +741,7 @@ void QV4DebugServiceImpl::signalEmitted(const QString &signal) //Normalize to Lower case. QString signalName = signal.left(signal.indexOf(QLatin1Char('('))).toLower(); - foreach (const QString &signal, breakOnSignals) { + for (const QString &signal : qAsConst(breakOnSignals)) { if (signal == signalName) { // TODO: pause debugger break; diff --git a/src/plugins/qmltooling/qmldbg_inspector/globalinspector.cpp b/src/plugins/qmltooling/qmldbg_inspector/globalinspector.cpp index 107d54c626..eb254ca1e0 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/globalinspector.cpp +++ b/src/plugins/qmltooling/qmldbg_inspector/globalinspector.cpp @@ -92,7 +92,7 @@ void GlobalInspector::setSelectedItems(const QList<QQuickItem *> &items) QList<QObject*> objectList; objectList.reserve(items.count()); - foreach (QQuickItem *item, items) + for (QQuickItem *item : items) objectList << item; sendCurrentObjects(objectList); @@ -113,7 +113,7 @@ void GlobalInspector::sendCurrentObjects(const QList<QObject*> &objects) QList<int> debugIds; debugIds.reserve(objects.count()); - foreach (QObject *object, objects) + for (QObject *object : objects) debugIds << QQmlDebugService::idForObject(object); ds << debugIds; @@ -194,7 +194,7 @@ bool GlobalInspector::createQmlObject(int requestId, const QString &qml, QObject return false; QString imports; - foreach (const QString &s, importList) + for (const QString &s : importList) imports += s + QLatin1Char('\n'); ObjectCreator *objectCreator = new ObjectCreator(requestId, parentContext->engine(), parent); @@ -223,7 +223,7 @@ void GlobalInspector::removeWindow(QQuickWindow *window) void GlobalInspector::setParentWindow(QQuickWindow *window, QWindow *parentWindow) { - foreach (QmlJSDebugger::QQuickWindowInspector *inspector, m_windowInspectors) { + for (QmlJSDebugger::QQuickWindowInspector *inspector : qAsConst(m_windowInspectors)) { if (inspector->quickWindow() == window) inspector->setParentWindow(parentWindow); } @@ -234,7 +234,8 @@ bool GlobalInspector::syncSelectedItems(const QList<QQuickItem *> &items) bool selectionChanged = false; // Disconnect and remove items that are no longer selected - foreach (const QPointer<QQuickItem> &item, m_selectedItems) { + const auto selectedItemsCopy = m_selectedItems; + for (const QPointer<QQuickItem> &item : selectedItemsCopy) { if (!item) // Don't see how this can happen due to handling of destroyed() continue; if (items.contains(item)) @@ -247,14 +248,14 @@ bool GlobalInspector::syncSelectedItems(const QList<QQuickItem *> &items) } // Connect and add newly selected items - foreach (QQuickItem *item, items) { + for (QQuickItem *item : items) { if (m_selectedItems.contains(item)) continue; selectionChanged = true; connect(item, &QObject::destroyed, this, &GlobalInspector::removeFromSelectedItems); m_selectedItems.append(item); - foreach (QQuickWindowInspector *inspector, m_windowInspectors) { + for (QQuickWindowInspector *inspector : qAsConst(m_windowInspectors)) { if (inspector->isEnabled() && inspector->quickWindow() == item->window()) { m_highlightItems.insert(item, new SelectionHighlight(titleForItem(item), item, inspector->overlay())); @@ -314,12 +315,12 @@ void GlobalInspector::processMessage(const QByteArray &message) ds >> requestId >> command; if (command == ENABLE) { - foreach (QQuickWindowInspector *inspector, m_windowInspectors) + for (QQuickWindowInspector *inspector : qAsConst(m_windowInspectors)) inspector->setEnabled(true); success = !m_windowInspectors.isEmpty(); } else if (command == DISABLE) { setSelectedItems(QList<QQuickItem*>()); - foreach (QQuickWindowInspector *inspector, m_windowInspectors) + for (QQuickWindowInspector *inspector : qAsConst(m_windowInspectors)) inspector->setEnabled(false); success = !m_windowInspectors.isEmpty(); } else if (command == SELECT) { @@ -327,7 +328,7 @@ void GlobalInspector::processMessage(const QByteArray &message) ds >> debugIds; QList<QQuickItem *> selectedObjects; - foreach (int debugId, debugIds) { + for (int debugId : qAsConst(debugIds)) { if (QQuickItem *obj = qobject_cast<QQuickItem *>(QQmlDebugService::objectForId(debugId))) selectedObjects << obj; @@ -341,7 +342,7 @@ void GlobalInspector::processMessage(const QByteArray &message) } else if (command == SHOW_APP_ON_TOP) { bool showOnTop; ds >> showOnTop; - foreach (QmlJSDebugger::QQuickWindowInspector *inspector, m_windowInspectors) + for (QmlJSDebugger::QQuickWindowInspector *inspector : qAsConst(m_windowInspectors)) inspector->setShowAppOnTop(showOnTop); success = !m_windowInspectors.isEmpty(); } else if (command == CREATE_OBJECT) { diff --git a/src/plugins/qmltooling/qmldbg_inspector/highlight.h b/src/plugins/qmltooling/qmldbg_inspector/highlight.h index 2bf4fc1ad5..3f910e833b 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/highlight.h +++ b/src/plugins/qmltooling/qmldbg_inspector/highlight.h @@ -81,7 +81,7 @@ class SelectionHighlight : public Highlight public: SelectionHighlight(const QString &name, QQuickItem *item, QQuickItem *parent); - void paint(QPainter *painter); + void paint(QPainter *painter) override; void showName(const QPointF &displayPoint); private: @@ -104,7 +104,7 @@ public: setZ(1); // hover highlight on top of selection highlight } - void paint(QPainter *painter); + void paint(QPainter *painter) override; }; } // namespace QmlJSDebugger diff --git a/src/plugins/qmltooling/qmldbg_inspector/qqmlinspectorservicefactory.h b/src/plugins/qmltooling/qmldbg_inspector/qqmlinspectorservicefactory.h index 09e6a01f96..3214532c8d 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qqmlinspectorservicefactory.h +++ b/src/plugins/qmltooling/qmldbg_inspector/qqmlinspectorservicefactory.h @@ -64,7 +64,7 @@ class QQmlInspectorServiceFactory : public QQmlDebugServiceFactory Q_OBJECT Q_PLUGIN_METADATA(IID QQmlDebugServiceFactory_iid FILE "qqmlinspectorservice.json") public: - QQmlDebugService *create(const QString &key); + QQmlDebugService *create(const QString &key) override; }; QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_inspector/qquickwindowinspector.h b/src/plugins/qmltooling/qmldbg_inspector/qquickwindowinspector.h index b37a9face1..fc18f33ad3 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qquickwindowinspector.h +++ b/src/plugins/qmltooling/qmldbg_inspector/qquickwindowinspector.h @@ -78,7 +78,7 @@ public: void setEnabled(bool enabled); protected: - bool eventFilter(QObject *, QEvent *); + bool eventFilter(QObject *, QEvent *) override; private: QQuickItem *m_overlay; diff --git a/src/plugins/qmltooling/qmldbg_local/qlocalclientconnection.cpp b/src/plugins/qmltooling/qmldbg_local/qlocalclientconnection.cpp index 64b26bdd0d..6152853917 100644 --- a/src/plugins/qmltooling/qmldbg_local/qlocalclientconnection.cpp +++ b/src/plugins/qmltooling/qmldbg_local/qlocalclientconnection.cpp @@ -43,6 +43,8 @@ #include <QtCore/qplugin.h> #include <QtNetwork/qlocalsocket.h> +Q_DECLARE_METATYPE(QLocalSocket::LocalSocketError) + QT_BEGIN_NAMESPACE @@ -133,8 +135,14 @@ bool QLocalClientConnection::connectToServer() { m_socket = new QLocalSocket; m_socket->setParent(this); - QObject::connect(m_socket, &QLocalSocket::connected, - this, &QLocalClientConnection::connectionEstablished); + connect(m_socket, &QLocalSocket::connected, + this, &QLocalClientConnection::connectionEstablished); + connect(m_socket, static_cast<void(QLocalSocket::*)(QLocalSocket::LocalSocketError)>( + &QLocalSocket::error), m_socket, [this](QLocalSocket::LocalSocketError) { + m_socket->disconnectFromServer(); + m_socket->connectToServer(m_filename); + }, Qt::QueuedConnection); + m_socket->connectToServer(m_filename); qDebug("QML Debugger: Connecting to socket %s...", m_filename.toLatin1().constData()); return true; diff --git a/src/plugins/qmltooling/qmldbg_local/qlocalclientconnectionfactory.h b/src/plugins/qmltooling/qmldbg_local/qlocalclientconnectionfactory.h index b884a1ec23..b64a1fff95 100644 --- a/src/plugins/qmltooling/qmldbg_local/qlocalclientconnectionfactory.h +++ b/src/plugins/qmltooling/qmldbg_local/qlocalclientconnectionfactory.h @@ -50,7 +50,7 @@ class QLocalClientConnectionFactory : public QQmlDebugServerConnectionFactory Q_PLUGIN_METADATA(IID QQmlDebugServerConnectionFactory_iid FILE "qlocalclientconnection.json") Q_INTERFACES(QQmlDebugServerConnectionFactory) public: - QQmlDebugServerConnection *create(const QString &key); + QQmlDebugServerConnection *create(const QString &key) override; }; QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_debugger/qdebugmessageservice.cpp b/src/plugins/qmltooling/qmldbg_messages/qdebugmessageservice.cpp index b0f59717ac..b0f59717ac 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qdebugmessageservice.cpp +++ b/src/plugins/qmltooling/qmldbg_messages/qdebugmessageservice.cpp diff --git a/src/plugins/qmltooling/qmldbg_debugger/qdebugmessageservice.h b/src/plugins/qmltooling/qmldbg_messages/qdebugmessageservice.h index c25e756c2d..24fd27514b 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qdebugmessageservice.h +++ b/src/plugins/qmltooling/qmldbg_messages/qdebugmessageservice.h @@ -68,10 +68,10 @@ public: QDebugMessageServiceImpl(QObject *parent = 0); void sendDebugMessage(QtMsgType type, const QMessageLogContext &ctxt, const QString &buf); - void synchronizeTime(const QElapsedTimer &otherTimer); + void synchronizeTime(const QElapsedTimer &otherTimer) override; protected: - void stateChanged(State); + void stateChanged(State) override; private: friend class QQmlDebuggerServiceFactory; diff --git a/src/plugins/qmltooling/qmldbg_messages/qdebugmessageservice.json b/src/plugins/qmltooling/qmldbg_messages/qdebugmessageservice.json new file mode 100644 index 0000000000..2e8dc65cf5 --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_messages/qdebugmessageservice.json @@ -0,0 +1,3 @@ +{ + "Keys": [ "DebugMessages" ] +} diff --git a/src/plugins/qmltooling/qmldbg_messages/qdebugmessageservicefactory.cpp b/src/plugins/qmltooling/qmldbg_messages/qdebugmessageservicefactory.cpp new file mode 100644 index 0000000000..a066237e77 --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_messages/qdebugmessageservicefactory.cpp @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdebugmessageservicefactory.h" +#include "qdebugmessageservice.h" +#include <private/qqmldebugserviceinterfaces_p.h> + +QT_BEGIN_NAMESPACE + +QQmlDebugService *QDebugMessageServiceFactory::create(const QString &key) +{ + if (key == QDebugMessageServiceImpl::s_key) + return new QDebugMessageServiceImpl(this); + + return 0; +} + +QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_messages/qdebugmessageservicefactory.h b/src/plugins/qmltooling/qmldbg_messages/qdebugmessageservicefactory.h new file mode 100644 index 0000000000..0c5f0f5d0a --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_messages/qdebugmessageservicefactory.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDEBUGMESSAGESERVICEFACTORY_H +#define QDEBUGMESSAGESERVICEFACTORY_H + +#include <private/qqmldebugservicefactory_p.h> + +QT_BEGIN_NAMESPACE + +class QDebugMessageServiceFactory : public QQmlDebugServiceFactory +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QQmlDebugServiceFactory_iid FILE "qdebugmessageservice.json") +public: + QQmlDebugService *create(const QString &key) override; +}; + +QT_END_NAMESPACE + +#endif // QDEBUGMESSAGESERVICEFACTORY_H diff --git a/src/plugins/qmltooling/qmldbg_messages/qmldbg_messages.pro b/src/plugins/qmltooling/qmldbg_messages/qmldbg_messages.pro new file mode 100644 index 0000000000..5ddf7c615d --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_messages/qmldbg_messages.pro @@ -0,0 +1,21 @@ +TARGET = qmldbg_messages +QT = qml-private core packetprotocol-private + +SOURCES += \ + $$PWD/qdebugmessageservice.cpp \ + $$PWD/qdebugmessageservicefactory.cpp + +HEADERS += \ + $$PWD/../shared/qqmldebugpacket.h \ + $$PWD/qdebugmessageservice.h \ + $$PWD/qdebugmessageservicefactory.h + +INCLUDEPATH += $$PWD \ + $$PWD/../shared + +OTHER_FILES += \ + $$PWD/qdebugmessageservice.json + +PLUGIN_TYPE = qmltooling +PLUGIN_CLASS_NAME = QDebugMessageServiceFactory +load(qt_plugin) diff --git a/src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.cpp b/src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.cpp index 3145601612..1a318b3ca2 100644 --- a/src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.cpp +++ b/src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.cpp @@ -183,7 +183,7 @@ QQmlNativeDebugConnector::QQmlNativeDebugConnector() : m_blockingMode(false) { const QString args = commandLineArguments(); - const auto lstjsDebugArguments = args.splitRef(QLatin1Char(',')); + const auto lstjsDebugArguments = args.splitRef(QLatin1Char(','), QString::SkipEmptyParts); QStringList services; for (const QStringRef &strArgument : lstjsDebugArguments) { if (strArgument == QLatin1String("block")) { @@ -195,7 +195,7 @@ QQmlNativeDebugConnector::QQmlNativeDebugConnector() services.append(strArgument.mid(9).toString()); } else if (!services.isEmpty()) { services.append(strArgument.toString()); - } else { + } else if (!strArgument.startsWith(QLatin1String("connector:"))) { qWarning("QML Debugger: Invalid argument \"%s\" detected. Ignoring the same.", strArgument.toUtf8().constData()); } @@ -205,7 +205,7 @@ QQmlNativeDebugConnector::QQmlNativeDebugConnector() QQmlNativeDebugConnector::~QQmlNativeDebugConnector() { - foreach (QQmlDebugService *service, m_services) { + for (QQmlDebugService *service : qAsConst(m_services)) { service->stateAboutToBeChanged(QQmlDebugService::NotConnected); service->setState(QQmlDebugService::NotConnected); service->stateChanged(QQmlDebugService::NotConnected); @@ -232,12 +232,12 @@ void QQmlNativeDebugConnector::addEngine(QJSEngine *engine) Q_ASSERT(!m_engines.contains(engine)); TRACE_PROTOCOL("Add engine to connector:" << engine); - foreach (QQmlDebugService *service, m_services) + for (QQmlDebugService *service : qAsConst(m_services)) service->engineAboutToBeAdded(engine); announceObjectAvailability(QLatin1String("qmlengine"), engine, true); - foreach (QQmlDebugService *service, m_services) + for (QQmlDebugService *service : qAsConst(m_services)) service->engineAdded(engine); m_engines.append(engine); @@ -248,12 +248,12 @@ void QQmlNativeDebugConnector::removeEngine(QJSEngine *engine) Q_ASSERT(m_engines.contains(engine)); TRACE_PROTOCOL("Remove engine from connector:" << engine); - foreach (QQmlDebugService *service, m_services) + for (QQmlDebugService *service : qAsConst(m_services)) service->engineAboutToBeRemoved(engine); announceObjectAvailability(QLatin1String("qmlengine"), engine, false); - foreach (QQmlDebugService *service, m_services) + for (QQmlDebugService *service : qAsConst(m_services)) service->engineRemoved(engine); m_engines.removeOne(engine); diff --git a/src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.h b/src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.h index 1184925e53..f8b7e1d527 100644 --- a/src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.h +++ b/src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.h @@ -78,7 +78,7 @@ class QQmlNativeDebugConnectorFactory : public QQmlDebugConnectorFactory Q_OBJECT Q_PLUGIN_METADATA(IID QQmlDebugConnectorFactory_iid FILE "qqmlnativedebugconnector.json") public: - QQmlDebugConnector *create(const QString &key); + QQmlDebugConnector *create(const QString &key) override; }; QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_nativedebugger/qmldbg_nativedebugger.pro b/src/plugins/qmltooling/qmldbg_nativedebugger/qmldbg_nativedebugger.pro new file mode 100644 index 0000000000..1873a6a77c --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_nativedebugger/qmldbg_nativedebugger.pro @@ -0,0 +1,21 @@ +TARGET = qmldbg_nativedebugger +QT = qml-private core packetprotocol-private + +SOURCES += \ + $$PWD/qqmlnativedebugservicefactory.cpp \ + $$PWD/qqmlnativedebugservice.cpp + +HEADERS += \ + $$PWD/../shared/qqmldebugpacket.h \ + $$PWD/qqmlnativedebugservicefactory.h \ + $$PWD/qqmlnativedebugservice.h \ + +INCLUDEPATH += $$PWD \ + $$PWD/../shared + +OTHER_FILES += \ + $$PWD/qqmlnativedebugservice.json + +PLUGIN_TYPE = qmltooling +PLUGIN_CLASS_NAME = QQmlNativeDebugServiceFactory +load(qt_plugin) diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp index 5b96163b48..9c198a8afc 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp @@ -287,7 +287,7 @@ void NativeDebugger::signalEmitted(const QString &signal) //Normalize to Lower case. QString signalName = signal.left(signal.indexOf(QLatin1Char('('))).toLower(); - foreach (const QString &signal, breakOnSignals) { + for (const QString &signal : qAsConst(breakOnSignals)) { if (signal == signalName) { // TODO: pause debugger break; @@ -340,16 +340,16 @@ void NativeDebugger::handleBacktrace(QJsonObject *response, const QJsonObject &a if (heapFunctionObject) { QJsonObject frame; - frame[QStringLiteral("language")] = QStringLiteral("js"); - frame[QStringLiteral("context")] = encodeContext(executionContext); + frame.insert(QStringLiteral("language"), QStringLiteral("js")); + frame.insert(QStringLiteral("context"), encodeContext(executionContext)); if (QV4::Function *function = heapFunctionObject->function) { if (QV4::Heap::String *functionName = function->name()) - frame[QStringLiteral("function")] = functionName->toQString(); - frame[QStringLiteral("file")] = function->sourceFile(); + frame.insert(QStringLiteral("function"), functionName->toQString()); + frame.insert(QStringLiteral("file"), function->sourceFile()); } int line = executionContext->d()->lineNumber; - frame[QStringLiteral("line")] = (line < 0 ? -line : line); + frame.insert(QStringLiteral("line"), (line < 0 ? -line : line)); frameArray.push_back(frame); } @@ -475,8 +475,8 @@ void NativeDebugger::handleVariables(QJsonObject *response, const QJsonObject &a TRACE_PROTOCOL("Engine: " << engine); Collector collector(engine); - QJsonArray expanded = arguments.value(QLatin1String("expanded")).toArray(); - foreach (const QJsonValue &ex, expanded) + const QJsonArray expanded = arguments.value(QLatin1String("expanded")).toArray(); + for (const QJsonValue &ex : expanded) collector.m_expanded.append(ex.toString()); TRACE_PROTOCOL("Expanded: " << collector.m_expanded); @@ -527,16 +527,16 @@ void NativeDebugger::handleExpressions(QJsonObject *response, const QJsonObject TRACE_PROTOCOL("Engines: " << engine << m_engine); Collector collector(engine); - QJsonArray expanded = arguments.value(QLatin1String("expanded")).toArray(); - foreach (const QJsonValue &ex, expanded) + const QJsonArray expanded = arguments.value(QLatin1String("expanded")).toArray(); + for (const QJsonValue &ex : expanded) collector.m_expanded.append(ex.toString()); TRACE_PROTOCOL("Expanded: " << collector.m_expanded); QJsonArray output; QV4::Scope scope(engine); - QJsonArray expressions = arguments.value(QLatin1String("expressions")).toArray(); - foreach (const QJsonValue &expr, expressions) { + const QJsonArray expressions = arguments.value(QLatin1String("expressions")).toArray(); + for (const QJsonValue &expr : expressions) { QString expression = expr.toObject().value(QLatin1String("expression")).toString(); QString name = expr.toObject().value(QLatin1String("name")).toString(); TRACE_PROTOCOL("Evaluate expression: " << expression); @@ -548,15 +548,15 @@ void NativeDebugger::handleExpressions(QJsonObject *response, const QJsonObject m_runningJob = false; if (result->isUndefined()) { QJsonObject dict; - dict[QStringLiteral("name")] = name; - dict[QStringLiteral("valueencoded")] = QStringLiteral("undefined"); + dict.insert(QStringLiteral("name"), name); + dict.insert(QStringLiteral("valueencoded"), QStringLiteral("undefined")); output.append(dict); } else if (result.ptr && result.ptr->rawValue()) { collector.collect(&output, QString(), name, *result); } else { QJsonObject dict; - dict[QStringLiteral("name")] = name; - dict[QStringLiteral("valueencoded")] = QStringLiteral("notaccessible"); + dict.insert(QStringLiteral("name"), name); + dict.insert(QStringLiteral("valueencoded"), QStringLiteral("notaccessible")); output.append(dict); } TRACE_PROTOCOL("EXCEPTION: " << engine->hasException); @@ -748,7 +748,8 @@ void QQmlNativeDebugServiceImpl::engineAboutToBeRemoved(QJSEngine *engine) TRACE_PROTOCOL("Removing engine" << engine); if (engine) { QV4::ExecutionEngine *executionEngine = QV8Engine::getV4(engine->handle()); - foreach (NativeDebugger *debugger, m_debuggers) { + const auto debuggersCopy = m_debuggers; + for (NativeDebugger *debugger : debuggersCopy) { if (debugger->engine() == executionEngine) m_debuggers.removeAll(debugger); } @@ -759,7 +760,7 @@ void QQmlNativeDebugServiceImpl::engineAboutToBeRemoved(QJSEngine *engine) void QQmlNativeDebugServiceImpl::stateAboutToBeChanged(QQmlDebugService::State state) { if (state == Enabled) { - foreach (NativeDebugger *debugger, m_debuggers) { + for (NativeDebugger *debugger : qAsConst(m_debuggers)) { QV4::ExecutionEngine *engine = debugger->engine(); if (!engine->debugger()) engine->setDebugger(debugger); @@ -783,7 +784,7 @@ void QQmlNativeDebugServiceImpl::messageReceived(const QByteArray &message) } else if (cmd == QLatin1String("echo")) { response.insert(QStringLiteral("result"), arguments); } else { - foreach (NativeDebugger *debugger, m_debuggers) + for (NativeDebugger *debugger : qAsConst(m_debuggers)) if (debugger) debugger->handleCommand(&response, cmd, arguments); } diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.h b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.h index 8015513f9e..58bf1bc94a 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.h +++ b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.h @@ -67,7 +67,6 @@ QT_BEGIN_NAMESPACE class NativeDebugger; class BreakPointHandler; -class QQmlDebuggerServiceFactory; class QQmlNativeDebugServiceImpl : public QQmlNativeDebugService { @@ -86,7 +85,6 @@ public: void emitAsynchronousMessageToClient(const QJsonObject &message); private: - friend class QQmlDebuggerServiceFactory; friend class NativeDebugger; QList<QPointer<NativeDebugger> > m_debuggers; diff --git a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.json b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.json new file mode 100644 index 0000000000..2951166298 --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.json @@ -0,0 +1,3 @@ +{ + "Keys": [ "NativeQmlDebugger" ] +} diff --git a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservicefactory.cpp b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservicefactory.cpp new file mode 100644 index 0000000000..1841c82d5d --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservicefactory.cpp @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmlnativedebugservice.h" +#include "qqmlnativedebugservicefactory.h" +#include <private/qqmldebugserviceinterfaces_p.h> + +QT_BEGIN_NAMESPACE + +QQmlDebugService *QQmlNativeDebugServiceFactory::create(const QString &key) +{ + if (key == QQmlNativeDebugServiceImpl::s_key) + return new QQmlNativeDebugServiceImpl(this); + + return 0; +} + +QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservicefactory.h b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservicefactory.h new file mode 100644 index 0000000000..f2b2e4792e --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservicefactory.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLNATIVEDEBUGSERVICEFACTORY_H +#define QQMLNATIVEDEBUGSERVICEFACTORY_H + +#include <private/qqmldebugservicefactory_p.h> + +QT_BEGIN_NAMESPACE + +class QQmlNativeDebugServiceFactory : public QQmlDebugServiceFactory +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QQmlDebugServiceFactory_iid FILE "qqmlnativedebugservice.json") +public: + QQmlDebugService *create(const QString &key) override; +}; + +QT_END_NAMESPACE + +#endif // QQMLNATIVEDEBUGSERVICEFACTORY_H diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlenginecontrolservice.cpp b/src/plugins/qmltooling/qmldbg_profiler/qqmlenginecontrolservice.cpp index 6b653d5a54..9918a95116 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qqmlenginecontrolservice.cpp +++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlenginecontrolservice.cpp @@ -46,6 +46,7 @@ QT_BEGIN_NAMESPACE QQmlEngineControlServiceImpl::QQmlEngineControlServiceImpl(QObject *parent) : QQmlEngineControlService(1, parent) { + blockingMode = QQmlDebugConnector::instance()->blockingMode(); } void QQmlEngineControlServiceImpl::messageReceived(const QByteArray &message) @@ -68,7 +69,7 @@ void QQmlEngineControlServiceImpl::messageReceived(const QByteArray &message) void QQmlEngineControlServiceImpl::engineAboutToBeAdded(QJSEngine *engine) { QMutexLocker lock(&dataMutex); - if (state() == Enabled) { + if (blockingMode && state() == Enabled) { Q_ASSERT(!stoppingEngines.contains(engine)); Q_ASSERT(!startingEngines.contains(engine)); startingEngines.append(engine); @@ -81,7 +82,7 @@ void QQmlEngineControlServiceImpl::engineAboutToBeAdded(QJSEngine *engine) void QQmlEngineControlServiceImpl::engineAboutToBeRemoved(QJSEngine *engine) { QMutexLocker lock(&dataMutex); - if (state() == Enabled) { + if (blockingMode && state() == Enabled) { Q_ASSERT(!stoppingEngines.contains(engine)); Q_ASSERT(!startingEngines.contains(engine)); stoppingEngines.append(engine); @@ -122,10 +123,10 @@ void QQmlEngineControlServiceImpl::stateChanged(State) { // We flush everything for any kind of state change, to avoid complicated timing issues. QMutexLocker lock(&dataMutex); - foreach (QJSEngine *engine, startingEngines) + for (QJSEngine *engine : qAsConst(startingEngines)) emit attachedToEngine(engine); startingEngines.clear(); - foreach (QJSEngine *engine, stoppingEngines) + for (QJSEngine *engine : qAsConst(stoppingEngines)) emit detachedFromEngine(engine); stoppingEngines.clear(); } diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlenginecontrolservice.h b/src/plugins/qmltooling/qmldbg_profiler/qqmlenginecontrolservice.h index 1138310820..6392944519 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qqmlenginecontrolservice.h +++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlenginecontrolservice.h @@ -79,6 +79,7 @@ protected: QMutex dataMutex; QList<QJSEngine *> startingEngines; QList<QJSEngine *> stoppingEngines; + bool blockingMode; void messageReceived(const QByteArray &) Q_DECL_OVERRIDE; void engineAboutToBeAdded(QJSEngine *) Q_DECL_OVERRIDE; diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp index dba2fd3cc3..c1f6f93ef1 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp +++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp @@ -51,6 +51,8 @@ #include <QtCore/qthread.h> #include <QtCore/qcoreapplication.h> +#include <algorithm> + QT_BEGIN_NAMESPACE Q_QML_DEBUG_PLUGIN_LOADER(QQmlAbstractProfilerAdapter) @@ -92,16 +94,18 @@ void QQmlProfilerServiceImpl::dataReady(QQmlAbstractProfilerAdapter *profiler) m_startTimes.insert(0, profiler); if (dataComplete) { QList<QJSEngine *> enginesToRelease; - foreach (QJSEngine *engine, m_stoppingEngines) { - foreach (QQmlAbstractProfilerAdapter *engineProfiler, m_engineProfilers.values(engine)) { - if (m_startTimes.values().contains(engineProfiler)) { + for (QJSEngine *engine : qAsConst(m_stoppingEngines)) { + const auto range = qAsConst(m_engineProfilers).equal_range(engine); + const auto startTimesEnd = m_startTimes.cend(); + for (auto it = range.first; it != range.second; ++it) { + if (std::find(m_startTimes.cbegin(), startTimesEnd, *it) != startTimesEnd) { enginesToRelease.append(engine); break; } } } sendMessages(); - foreach (QJSEngine *engine, enginesToRelease) { + for (QJSEngine *engine : qAsConst(enginesToRelease)) { m_stoppingEngines.removeOne(engine); emit detachedFromEngine(engine); } @@ -130,8 +134,9 @@ void QQmlProfilerServiceImpl::engineAdded(QJSEngine *engine) "QML profilers have to be added from the engine thread"); QMutexLocker lock(&m_configMutex); - foreach (QQmlAbstractProfilerAdapter *profiler, m_engineProfilers.values(engine)) - profiler->stopWaiting(); + const auto range = qAsConst(m_engineProfilers).equal_range(engine); + for (auto it = range.first; it != range.second; ++it) + (*it)->stopWaiting(); } void QQmlProfilerServiceImpl::engineAboutToBeRemoved(QJSEngine *engine) @@ -141,7 +146,9 @@ void QQmlProfilerServiceImpl::engineAboutToBeRemoved(QJSEngine *engine) QMutexLocker lock(&m_configMutex); bool isRunning = false; - foreach (QQmlAbstractProfilerAdapter *profiler, m_engineProfilers.values(engine)) { + const auto range = qAsConst(m_engineProfilers).equal_range(engine); + for (auto it = range.first; it != range.second; ++it) { + QQmlAbstractProfilerAdapter *profiler = *it; if (profiler->isRunning()) isRunning = true; profiler->startWaiting(); @@ -160,7 +167,9 @@ void QQmlProfilerServiceImpl::engineRemoved(QJSEngine *engine) "QML profilers have to be removed from the engine thread"); QMutexLocker lock(&m_configMutex); - foreach (QQmlAbstractProfilerAdapter *profiler, m_engineProfilers.values(engine)) { + const auto range = qAsConst(m_engineProfilers).equal_range(engine); + for (auto it = range.first; it != range.second; ++it) { + QQmlAbstractProfilerAdapter *profiler = *it; removeProfilerFromStartTimes(profiler); delete profiler; } @@ -183,7 +192,7 @@ void QQmlProfilerServiceImpl::addGlobalProfiler(QQmlAbstractProfilerAdapter *pro // Global profilers are started whenever any engine profiler is started and stopped when // all engine profilers are stopped. quint64 features = 0; - foreach (QQmlAbstractProfilerAdapter *engineProfiler, m_engineProfilers) + for (QQmlAbstractProfilerAdapter *engineProfiler : qAsConst(m_engineProfilers)) features |= engineProfiler->features(); if (features != 0) @@ -231,7 +240,9 @@ void QQmlProfilerServiceImpl::startProfiling(QJSEngine *engine, quint64 features d << m_timer.nsecsElapsed() << (int)Event << (int)StartTrace; bool startedAny = false; if (engine != 0) { - foreach (QQmlAbstractProfilerAdapter *profiler, m_engineProfilers.values(engine)) { + const auto range = qAsConst(m_engineProfilers).equal_range(engine); + for (auto it = range.first; it != range.second; ++it) { + QQmlAbstractProfilerAdapter *profiler = *it; if (!profiler->isRunning()) { profiler->startProfiling(features); startedAny = true; @@ -249,12 +260,12 @@ void QQmlProfilerServiceImpl::startProfiling(QJSEngine *engine, quint64 features startedAny = true; } } - foreach (QJSEngine *profiledEngine, engines) + for (QJSEngine *profiledEngine : qAsConst(engines)) d << idForObject(profiledEngine); } if (startedAny) { - foreach (QQmlAbstractProfilerAdapter *profiler, m_globalProfilers) { + for (QQmlAbstractProfilerAdapter *profiler : qAsConst(m_globalProfilers)) { if (!profiler->isRunning()) profiler->startProfiling(features); } @@ -294,7 +305,7 @@ void QQmlProfilerServiceImpl::stopProfiling(QJSEngine *engine) if (stopping.isEmpty()) return; - foreach (QQmlAbstractProfilerAdapter *profiler, m_globalProfilers) { + for (QQmlAbstractProfilerAdapter *profiler : qAsConst(m_globalProfilers)) { if (!profiler->isRunning()) continue; m_startTimes.insert(-1, profiler); @@ -308,10 +319,10 @@ void QQmlProfilerServiceImpl::stopProfiling(QJSEngine *engine) emit stopFlushTimer(); m_waitingForStop = true; - foreach (QQmlAbstractProfilerAdapter *profiler, reporting) + for (QQmlAbstractProfilerAdapter *profiler : qAsConst(reporting)) profiler->reportData(m_useMessageTypes); - foreach (QQmlAbstractProfilerAdapter *profiler, stopping) + for (QQmlAbstractProfilerAdapter *profiler : qAsConst(stopping)) profiler->stopProfiling(); } @@ -327,7 +338,7 @@ void QQmlProfilerServiceImpl::sendMessages() traceEnd << m_timer.nsecsElapsed() << (int)Event << (int)EndTrace; QSet<QJSEngine *> seen; - foreach (QQmlAbstractProfilerAdapter *profiler, m_startTimes) { + for (QQmlAbstractProfilerAdapter *profiler : qAsConst(m_startTimes)) { for (QMultiHash<QJSEngine *, QQmlAbstractProfilerAdapter *>::iterator i(m_engineProfilers.begin()); i != m_engineProfilers.end(); ++i) { if (i.value() == profiler && !seen.contains(i.key())) { @@ -367,7 +378,7 @@ void QQmlProfilerServiceImpl::sendMessages() emit messagesToClient(name(), messages); // Restart flushing if any profilers are still running - foreach (const QQmlAbstractProfilerAdapter *profiler, m_engineProfilers) { + for (const QQmlAbstractProfilerAdapter *profiler : qAsConst(m_engineProfilers)) { if (profiler->isRunning()) { emit startFlushTimer(); break; @@ -438,21 +449,21 @@ void QQmlProfilerServiceImpl::flush() QMutexLocker lock(&m_configMutex); QList<QQmlAbstractProfilerAdapter *> reporting; - foreach (QQmlAbstractProfilerAdapter *profiler, m_engineProfilers) { + for (QQmlAbstractProfilerAdapter *profiler : qAsConst(m_engineProfilers)) { if (profiler->isRunning()) { m_startTimes.insert(-1, profiler); reporting.append(profiler); } } - foreach (QQmlAbstractProfilerAdapter *profiler, m_globalProfilers) { + for (QQmlAbstractProfilerAdapter *profiler : qAsConst(m_globalProfilers)) { if (profiler->isRunning()) { m_startTimes.insert(-1, profiler); reporting.append(profiler); } } - foreach (QQmlAbstractProfilerAdapter *profiler, reporting) + for (QQmlAbstractProfilerAdapter *profiler : qAsConst(reporting)) profiler->reportData(m_useMessageTypes); } diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservicefactory.h b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservicefactory.h index 772e53bde7..cdce4cd240 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservicefactory.h +++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservicefactory.h @@ -60,7 +60,7 @@ class QQmlProfilerServiceFactory : public QQmlDebugServiceFactory Q_OBJECT Q_PLUGIN_METADATA(IID QQmlDebugServiceFactory_iid FILE "qqmlprofilerservice.json") public: - QQmlDebugService *create(const QString &key); + QQmlDebugService *create(const QString &key) override; }; QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapterfactory.h b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapterfactory.h index 489545b504..41b9875c03 100644 --- a/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapterfactory.h +++ b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapterfactory.h @@ -61,7 +61,7 @@ class QQuickProfilerAdapterFactory : public QQmlAbstractProfilerAdapterFactory Q_OBJECT Q_PLUGIN_METADATA(IID QQmlAbstractProfilerAdapterFactory_iid FILE "qquickprofileradapter.json") public: - QQmlAbstractProfilerAdapter *create(const QString &key); + QQmlAbstractProfilerAdapter *create(const QString &key) override; }; QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp b/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp index 96b3455790..f6f48e43a4 100644 --- a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp +++ b/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp @@ -346,7 +346,7 @@ void QQmlDebugServerImpl::parseArguments() QString fileName; QStringList services; - const auto lstjsDebugArguments = args.splitRef(QLatin1Char(',')); + const auto lstjsDebugArguments = args.splitRef(QLatin1Char(','), QString::SkipEmptyParts); for (auto argsIt = lstjsDebugArguments.begin(), argsItEnd = lstjsDebugArguments.end(); argsIt != argsItEnd; ++argsIt) { const QStringRef &strArgument = *argsIt; if (strArgument.startsWith(QLatin1String("port:"))) { @@ -377,7 +377,7 @@ void QQmlDebugServerImpl::parseArguments() services.append(strArgument.mid(9).toString()); } else if (!services.isEmpty()) { services.append(strArgument.toString()); - } else { + } else if (!strArgument.startsWith(QLatin1String("connector:"))) { const QString message = tr("QML Debugger: Invalid argument \"%1\" detected." " Ignoring the same.").arg(strArgument.toString()); qWarning("%s", qPrintable(message)); @@ -589,12 +589,12 @@ void QQmlDebugServerImpl::addEngine(QJSEngine *engine) QMutexLocker locker(&m_helloMutex); Q_ASSERT(!m_engineConditions.contains(engine)); - foreach (QQmlDebugService *service, m_plugins) + for (QQmlDebugService *service : qAsConst(m_plugins)) service->engineAboutToBeAdded(engine); m_engineConditions[engine].waitForServices(&m_helloMutex, m_plugins.count()); - foreach (QQmlDebugService *service, m_plugins) + for (QQmlDebugService *service : qAsConst(m_plugins)) service->engineAdded(engine); } @@ -606,12 +606,12 @@ void QQmlDebugServerImpl::removeEngine(QJSEngine *engine) QMutexLocker locker(&m_helloMutex); Q_ASSERT(m_engineConditions.contains(engine)); - foreach (QQmlDebugService *service, m_plugins) + for (QQmlDebugService *service : qAsConst(m_plugins)) service->engineAboutToBeRemoved(engine); m_engineConditions[engine].waitForServices(&m_helloMutex, m_plugins.count()); - foreach (QQmlDebugService *service, m_plugins) + for (QQmlDebugService *service : qAsConst(m_plugins)) service->engineRemoved(engine); m_engineConditions.remove(engine); @@ -703,11 +703,11 @@ void QQmlDebugServerImpl::sendMessages(const QString &name, const QList<QByteArr if (m_clientSupportsMultiPackets) { QQmlDebugPacket out; out << name; - foreach (const QByteArray &message, messages) + for (const QByteArray &message : messages) out << message; m_protocol->send(out.data()); } else { - foreach (const QByteArray &message, messages) + for (const QByteArray &message : messages) doSendMessage(name, message); } m_connection->flush(); diff --git a/src/plugins/qmltooling/qmldbg_server/qqmldebugserverfactory.h b/src/plugins/qmltooling/qmldbg_server/qqmldebugserverfactory.h index fd71b03019..2debabaeb2 100644 --- a/src/plugins/qmltooling/qmldbg_server/qqmldebugserverfactory.h +++ b/src/plugins/qmltooling/qmldbg_server/qqmldebugserverfactory.h @@ -63,7 +63,7 @@ class QQmlDebugServerFactory : public QQmlDebugConnectorFactory // QQmlDebugServer is for connection plugins. Q_PLUGIN_METADATA(IID QQmlDebugConnectorFactory_iid FILE "qqmldebugserver.json") public: - QQmlDebugConnector *create(const QString &key); + QQmlDebugConnector *create(const QString &key) override; }; QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnectionfactory.h b/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnectionfactory.h index 52d9f4b709..d3b0e00584 100644 --- a/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnectionfactory.h +++ b/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnectionfactory.h @@ -50,7 +50,7 @@ class QTcpServerConnectionFactory : public QQmlDebugServerConnectionFactory Q_PLUGIN_METADATA(IID QQmlDebugServerConnectionFactory_iid FILE "qtcpserverconnection.json") Q_INTERFACES(QQmlDebugServerConnectionFactory) public: - QQmlDebugServerConnection *create(const QString &key); + QQmlDebugServerConnection *create(const QString &key) override; }; QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmltooling.pro b/src/plugins/qmltooling/qmltooling.pro index 907fbe9273..8123e2999e 100644 --- a/src/plugins/qmltooling/qmltooling.pro +++ b/src/plugins/qmltooling/qmltooling.pro @@ -19,12 +19,16 @@ qtConfig(qml-network) { # Services SUBDIRS += \ qmldbg_debugger \ - qmldbg_profiler + qmldbg_profiler \ + qmldbg_messages \ + qmldbg_nativedebugger qmldbg_server.depends = packetprotocol qmldbg_native.depends = packetprotocol qmldbg_debugger.depends = packetprotocol qmldbg_profiler.depends = packetprotocol +qmldbg_messages.depends = packetprotocol +qmldbg_nativedebugger.depends = packetprotocol qtHaveModule(quick) { SUBDIRS += \ diff --git a/src/plugins/scenegraph/openvg/openvg.json b/src/plugins/scenegraph/openvg/openvg.json new file mode 100644 index 0000000000..224afbf784 --- /dev/null +++ b/src/plugins/scenegraph/openvg/openvg.json @@ -0,0 +1,3 @@ +{ + "Keys": ["openvg"] +} diff --git a/src/plugins/scenegraph/openvg/openvg.pro b/src/plugins/scenegraph/openvg/openvg.pro new file mode 100644 index 0000000000..8a58796a05 --- /dev/null +++ b/src/plugins/scenegraph/openvg/openvg.pro @@ -0,0 +1,56 @@ +TARGET = qsgopenvgbackend + +QT += gui-private core-private qml-private quick-private + +PLUGIN_TYPE = scenegraph +PLUGIN_CLASS_NAME = QSGOpenVGAdaptation +load(qt_plugin) + +QMAKE_TARGET_PRODUCT = "Qt Quick OpenVG Renderer (Qt $$QT_VERSION)" +QMAKE_TARGET_DESCRIPTION = "Quick OpenVG Renderer for Qt." + +QMAKE_USE += openvg + +OTHER_FILES += $$PWD/openvg.json + +HEADERS += \ + qsgopenvgadaptation_p.h \ + qsgopenvgcontext_p.h \ + qsgopenvgrenderloop_p.h \ + qsgopenvgglyphnode_p.h \ + qopenvgcontext_p.h \ + qsgopenvgrenderer_p.h \ + qsgopenvginternalrectanglenode.h \ + qsgopenvgnodevisitor.h \ + qopenvgmatrix.h \ + qsgopenvgpublicnodes.h \ + qsgopenvginternalimagenode.h \ + qsgopenvgtexture.h \ + qsgopenvglayer.h \ + qsgopenvghelpers.h \ + qsgopenvgfontglyphcache.h \ + qsgopenvgpainternode.h \ + qsgopenvgspritenode.h \ + qsgopenvgrenderable.h \ + qopenvgoffscreensurface.h + +SOURCES += \ + qsgopenvgadaptation.cpp \ + qsgopenvgcontext.cpp \ + qsgopenvgrenderloop.cpp \ + qsgopenvgglyphnode.cpp \ + qopenvgcontext.cpp \ + qsgopenvgrenderer.cpp \ + qsgopenvginternalrectanglenode.cpp \ + qsgopenvgnodevisitor.cpp \ + qopenvgmatrix.cpp \ + qsgopenvgpublicnodes.cpp \ + qsgopenvginternalimagenode.cpp \ + qsgopenvgtexture.cpp \ + qsgopenvglayer.cpp \ + qsgopenvghelpers.cpp \ + qsgopenvgfontglyphcache.cpp \ + qsgopenvgpainternode.cpp \ + qsgopenvgspritenode.cpp \ + qsgopenvgrenderable.cpp \ + qopenvgoffscreensurface.cpp diff --git a/src/plugins/scenegraph/openvg/qopenvgcontext.cpp b/src/plugins/scenegraph/openvg/qopenvgcontext.cpp new file mode 100644 index 0000000000..ea2c24afdb --- /dev/null +++ b/src/plugins/scenegraph/openvg/qopenvgcontext.cpp @@ -0,0 +1,218 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qpa/qplatformnativeinterface.h> +#include <QtGui/QGuiApplication> +#include <QtCore/QVector> +#include <QtCore/QDebug> + +#include "qopenvgcontext_p.h" + +QT_BEGIN_NAMESPACE + +QOpenVGContext::QOpenVGContext(QWindow *window) + : m_window(window) +{ + QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface(); + m_display = reinterpret_cast<EGLDisplay>(nativeInterface->nativeResourceForWindow("EglDisplay", window)); + m_surface = reinterpret_cast<EGLSurface>(nativeInterface->nativeResourceForWindow("EglSurface", window)); + + if (m_display == 0) + qFatal("QOpenVGContext: failed to get EGLDisplay"); + if (m_surface == 0) + qFatal("QOpenVGContext: failed to get EGLSurface"); + + EGLint configID = 0; + if (eglQuerySurface(m_display, m_surface, EGL_CONFIG_ID, &configID)) { + EGLint numConfigs; + const EGLint configAttribs[] = { + EGL_CONFIG_ID, configID, + EGL_NONE + }; + eglChooseConfig(m_display, configAttribs, &m_config, 1, &numConfigs); + } else { + qFatal("QOpenVGContext: failed to get surface config"); + } + + // Create an EGL Context + eglBindAPI(EGL_OPENVG_API); + m_context = eglCreateContext(m_display, m_config, EGL_NO_CONTEXT, 0); + if (!m_context) + qFatal("QOpenVGContext: eglCreateContext failed"); +} + +QOpenVGContext::~QOpenVGContext() +{ + doneCurrent(); + eglDestroyContext(m_display, m_context); +} + +void QOpenVGContext::makeCurrent() +{ + makeCurrent(m_surface); +} + +void QOpenVGContext::makeCurrent(EGLSurface surface) +{ + eglMakeCurrent(m_display, surface, surface, m_context); +} + +void QOpenVGContext::doneCurrent() +{ + eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); +} + +void QOpenVGContext::swapBuffers() +{ + swapBuffers(m_surface); +} + +void QOpenVGContext::swapBuffers(EGLSurface surface) +{ + eglSwapBuffers(m_display, surface); +} + +QWindow *QOpenVGContext::window() const +{ + return m_window; +} + +QImage QOpenVGContext::readFramebuffer(const QSize &size) +{ + QImage framebufferImage(size, QImage::Format_RGB32); + vgReadPixels(framebufferImage.bits(), framebufferImage.bytesPerLine(), VG_sXRGB_8888, 0, 0, size.width(), size.height()); + return framebufferImage.mirrored(false, true); +} + +void QOpenVGContext::getConfigs() +{ + EGLint configsAvailable = 0; + eglGetConfigs(m_display, 0, 0, &configsAvailable); + + QVector<EGLConfig> configs(configsAvailable); + eglGetConfigs(m_display, configs.data(), configs.size(), &configsAvailable); + + for (EGLConfig config : configs) { + EGLint value; + eglGetConfigAttrib(m_display, config, EGL_CONFIG_ID, &value); + qDebug() << "#################\n" << "EGL_CONFIG_ID:" << value; + eglGetConfigAttrib(m_display, config, EGL_BUFFER_SIZE, &value); + qDebug() << "EGL_BUFFER_SIZE:" << value; + eglGetConfigAttrib(m_display, config, EGL_ALPHA_SIZE, &value); + qDebug() << "EGL_ALPHA_SIZE:" << value; + eglGetConfigAttrib(m_display, config, EGL_RED_SIZE, &value); + qDebug() << "EGL_RED_SIZE:" << value; + eglGetConfigAttrib(m_display, config, EGL_GREEN_SIZE, &value); + qDebug() << "EGL_GREEN_SIZE:" << value; + eglGetConfigAttrib(m_display, config, EGL_BLUE_SIZE, &value); + qDebug() << "EGL_BLUE_SIZE:" << value; + eglGetConfigAttrib(m_display, config, EGL_DEPTH_SIZE, &value); + qDebug() << "EGL_DEPTH_SIZE:" << value; + eglGetConfigAttrib(m_display, config, EGL_STENCIL_SIZE, &value); + qDebug() << "EGL_STENCIL_SIZE:" << value; + + eglGetConfigAttrib(m_display, config, EGL_ALPHA_MASK_SIZE, &value); + qDebug() << "EGL_ALPHA_MASK_SIZE:" << value; + eglGetConfigAttrib(m_display, config, EGL_BIND_TO_TEXTURE_RGB, &value); + qDebug() << "EGL_BIND_TO_TEXTURE_RGB:" << value; + eglGetConfigAttrib(m_display, config, EGL_BIND_TO_TEXTURE_RGBA, &value); + qDebug() << "EGL_BIND_TO_TEXTURE_RGBA:" << value; + + + eglGetConfigAttrib(m_display, config, EGL_COLOR_BUFFER_TYPE, &value); + qDebug() << "EGL_COLOR_BUFFER_TYPE:" << value; + eglGetConfigAttrib(m_display, config, EGL_CONFIG_CAVEAT, &value); + qDebug() << "EGL_CONFIG_CAVEAT:" << value; + eglGetConfigAttrib(m_display, config, EGL_CONFORMANT, &value); + qDebug() << "EGL_CONFORMANT:" << value; + + + eglGetConfigAttrib(m_display, config, EGL_LEVEL, &value); + qDebug() << "EGL_LEVEL:" << value; + eglGetConfigAttrib(m_display, config, EGL_LUMINANCE_SIZE, &value); + qDebug() << "EGL_LUMINANCE_SIZE:" << value; + eglGetConfigAttrib(m_display, config, EGL_MAX_PBUFFER_WIDTH, &value); + qDebug() << "EGL_MAX_PBUFFER_WIDTH:" << value; + eglGetConfigAttrib(m_display, config, EGL_MAX_PBUFFER_HEIGHT, &value); + qDebug() << "EGL_MAX_PBUFFER_HEIGHT:" << value; + eglGetConfigAttrib(m_display, config, EGL_MAX_PBUFFER_PIXELS, &value); + qDebug() << "EGL_MAX_PBUFFER_PIXELS:" << value; + eglGetConfigAttrib(m_display, config, EGL_MAX_SWAP_INTERVAL, &value); + qDebug() << "EGL_MAX_SWAP_INTERVAL:" << value; + eglGetConfigAttrib(m_display, config, EGL_MIN_SWAP_INTERVAL, &value); + qDebug() << "EGL_MIN_SWAP_INTERVAL:" << value; + eglGetConfigAttrib(m_display, config, EGL_NATIVE_RENDERABLE, &value); + qDebug() << "EGL_NATIVE_RENDERABLE:" << value; + eglGetConfigAttrib(m_display, config, EGL_NATIVE_VISUAL_ID, &value); + qDebug() << "EGL_NATIVE_VISUAL_ID:" << value; + eglGetConfigAttrib(m_display, config, EGL_NATIVE_VISUAL_TYPE, &value); + qDebug() << "EGL_NATIVE_VISUAL_TYPE:" << value; + eglGetConfigAttrib(m_display, config, EGL_RENDERABLE_TYPE, &value); + qDebug() << "EGL_RENDERABLE_TYPE:" << value; + eglGetConfigAttrib(m_display, config, EGL_SAMPLE_BUFFERS, &value); + qDebug() << "EGL_SAMPLE_BUFFERS:" << value; + eglGetConfigAttrib(m_display, config, EGL_SAMPLES, &value); + qDebug() << "EGL_SAMPLES:" << value; + + eglGetConfigAttrib(m_display, config, EGL_SURFACE_TYPE, &value); + qDebug() << "EGL_SURFACE_TYPE:" << value; + eglGetConfigAttrib(m_display, config, EGL_TRANSPARENT_TYPE, &value); + qDebug() << "EGL_TRANSPARENT_TYPE:" << value; + eglGetConfigAttrib(m_display, config, EGL_TRANSPARENT_RED_VALUE, &value); + qDebug() << "EGL_TRANSPARENT_RED_VALUE:" << value; + eglGetConfigAttrib(m_display, config, EGL_TRANSPARENT_GREEN_VALUE, &value); + qDebug() << "EGL_TRANSPARENT_GREEN_VALUE:" << value; + eglGetConfigAttrib(m_display, config, EGL_TRANSPARENT_BLUE_VALUE, &value); + qDebug() << "EGL_TRANSPARENT_BLUE_VALUE:" << value; + } +} + +void QOpenVGContext::checkErrors() +{ + VGErrorCode error; + EGLint eglError; + do { + error = vgGetError(); + eglError = eglGetError(); + qDebug() << "error: " << QString::number(error, 16); + qDebug() << "eglError: " << QString::number(eglError, 16); + } while (error != VG_NO_ERROR && eglError != EGL_SUCCESS); +} + +QT_END_NAMESPACE diff --git a/src/plugins/scenegraph/openvg/qopenvgcontext_p.h b/src/plugins/scenegraph/openvg/qopenvgcontext_p.h new file mode 100644 index 0000000000..a1ba73957f --- /dev/null +++ b/src/plugins/scenegraph/openvg/qopenvgcontext_p.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOPENVGCONTEXT_H +#define QOPENVGCONTEXT_H + +#include <QtGui/QWindow> +#include <QtGui/QImage> + +#include <EGL/egl.h> +#include <VG/openvg.h> + +QT_BEGIN_NAMESPACE + +class QOpenVGContext +{ +public: + QOpenVGContext(QWindow *window); + ~QOpenVGContext(); + + void makeCurrent(); + void makeCurrent(EGLSurface surface); + void doneCurrent(); + void swapBuffers(); + void swapBuffers(EGLSurface surface); + + + QWindow *window() const; + + EGLDisplay eglDisplay() { return m_display; } + EGLConfig eglConfig() { return m_config; } + EGLContext eglContext() { return m_context; } + + QImage readFramebuffer(const QSize &size); + + void getConfigs(); + + static void checkErrors(); + +private: + EGLSurface m_surface; + EGLDisplay m_display; + EGLConfig m_config; + EGLContext m_context; + + QWindow *m_window; + +}; + +QT_END_NAMESPACE + +#endif // QOPENVGCONTEXT_H diff --git a/src/plugins/scenegraph/openvg/qopenvgmatrix.cpp b/src/plugins/scenegraph/openvg/qopenvgmatrix.cpp new file mode 100644 index 0000000000..83ce96578e --- /dev/null +++ b/src/plugins/scenegraph/openvg/qopenvgmatrix.cpp @@ -0,0 +1,378 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qopenvgmatrix.h" + +QT_BEGIN_NAMESPACE + +// QOpenVGMatrix: Because Qt will never have enough matrix classes +// Internally the data is stored as column-major format +// So this is a 3x3 version of QMatrix4x4 for optimal +// OpenVG usage. + +QOpenVGMatrix::QOpenVGMatrix() +{ + setToIdentity(); +} + +QOpenVGMatrix::QOpenVGMatrix(const float *values) +{ + for (int col = 0; col < 3; ++col) + for (int row = 0; row < 3; ++row) + m[col][row] = values[col * 3 + row]; +} + +const float &QOpenVGMatrix::operator()(int row, int column) const +{ + Q_ASSERT(row >= 0 && row < 4 && column >= 0 && column < 4); + return m[column][row]; +} + +float &QOpenVGMatrix::operator()(int row, int column) +{ + Q_ASSERT(row >= 0 && row < 4 && column >= 0 && column < 4); + return m[column][row]; +} + +bool QOpenVGMatrix::isIdentity() const +{ + if (m[0][0] != 1.0f || m[0][1] != 0.0f || m[0][2] != 0.0f) + return false; + if ( m[1][0] != 0.0f || m[1][1] != 1.0f) + return false; + if (m[1][2] != 0.0f || m[2][0] != 0.0f) + return false; + if (m[2][1] != 0.0f || m[2][2] != 1.0f) + return false; + + return true; +} + +void QOpenVGMatrix::setToIdentity() +{ + m[0][0] = 1.0f; + m[0][1] = 0.0f; + m[0][2] = 0.0f; + m[1][0] = 0.0f; + m[1][1] = 1.0f; + m[1][2] = 0.0f; + m[2][0] = 0.0f; + m[2][1] = 0.0f; + m[2][2] = 1.0f; +} + +bool QOpenVGMatrix::isAffine() const +{ + if (m[0][2] == 0.0f && m[1][2] == 0.0f && m[2][2] == 1.0f) + return true; + + return false; +} + +QPointF QOpenVGMatrix::map(const QPointF &point) const +{ + return *this * point; +} + +void QOpenVGMatrix::fill(float value) +{ + m[0][0] = value; + m[0][1] = value; + m[0][2] = value; + m[1][0] = value; + m[1][1] = value; + m[1][2] = value; + m[2][0] = value; + m[2][1] = value; + m[2][2] = value; +} + +QOpenVGMatrix QOpenVGMatrix::transposed() const +{ + QOpenVGMatrix result; + for (int row = 0; row < 3; ++row) { + for (int col = 0; col < 3; ++col) + result.m[col][row] = m[row][col]; + } + return result; +} + +QOpenVGMatrix &QOpenVGMatrix::operator+=(const QOpenVGMatrix &other) +{ + m[0][0] += other.m[0][0]; + m[0][1] += other.m[0][1]; + m[0][2] += other.m[0][2]; + m[1][0] += other.m[1][0]; + m[1][1] += other.m[1][1]; + m[1][2] += other.m[1][2]; + m[2][0] += other.m[2][0]; + m[2][1] += other.m[2][1]; + m[2][2] += other.m[2][2]; + return *this; +} + +QOpenVGMatrix &QOpenVGMatrix::operator-=(const QOpenVGMatrix &other) +{ + m[0][0] -= other.m[0][0]; + m[0][1] -= other.m[0][1]; + m[0][2] -= other.m[0][2]; + m[1][0] -= other.m[1][0]; + m[1][1] -= other.m[1][1]; + m[1][2] -= other.m[1][2]; + m[2][0] -= other.m[2][0]; + m[2][1] -= other.m[2][1]; + m[2][2] -= other.m[2][2]; + return *this; +} + +QOpenVGMatrix &QOpenVGMatrix::operator*=(const QOpenVGMatrix &other) +{ + float m0, m1; + m0 = m[0][0] * other.m[0][0] + + m[1][0] * other.m[0][1] + + m[2][0] * other.m[0][2]; + m1 = m[0][0] * other.m[1][0] + + m[1][0] * other.m[1][1] + + m[2][0] * other.m[1][2]; + m[2][0] = m[0][0] * other.m[2][0] + + m[1][0] * other.m[2][1] + + m[2][0] * other.m[2][2]; + m[0][0] = m0; + m[1][0] = m1; + + m0 = m[0][1] * other.m[0][0] + + m[1][1] * other.m[0][1] + + m[2][1] * other.m[0][2]; + m1 = m[0][1] * other.m[1][0] + + m[1][1] * other.m[1][1] + + m[2][1] * other.m[1][2]; + m[2][1] = m[0][1] * other.m[2][0] + + m[1][1] * other.m[2][1] + + m[2][1] * other.m[2][2]; + m[0][1] = m0; + m[1][1] = m1; + + m0 = m[0][2] * other.m[0][0] + + m[1][2] * other.m[0][1] + + m[2][2] * other.m[0][2]; + m1 = m[0][2] * other.m[1][0] + + m[1][2] * other.m[1][1] + + m[2][2] * other.m[1][2]; + m[2][2] = m[0][2] * other.m[2][0] + + m[1][2] * other.m[2][1] + + m[2][2] * other.m[2][2]; + m[0][2] = m0; + m[1][2] = m1; + return *this; +} + +QOpenVGMatrix &QOpenVGMatrix::operator*=(float factor) +{ + m[0][0] *= factor; + m[0][1] *= factor; + m[0][2] *= factor; + m[1][0] *= factor; + m[1][1] *= factor; + m[1][2] *= factor; + m[2][0] *= factor; + m[2][1] *= factor; + m[2][2] *= factor; + return *this; +} + +QOpenVGMatrix &QOpenVGMatrix::operator/=(float divisor) +{ + m[0][0] /= divisor; + m[0][1] /= divisor; + m[0][2] /= divisor; + m[1][0] /= divisor; + m[1][1] /= divisor; + m[1][2] /= divisor; + m[2][0] /= divisor; + m[2][1] /= divisor; + m[2][2] /= divisor; + return *this; +} + +bool QOpenVGMatrix::operator==(const QOpenVGMatrix &other) const +{ + return m[0][0] == other.m[0][0] && + m[0][1] == other.m[0][1] && + m[0][2] == other.m[0][2] && + m[1][0] == other.m[1][0] && + m[1][1] == other.m[1][1] && + m[1][2] == other.m[1][2] && + m[2][0] == other.m[2][0] && + m[2][1] == other.m[2][1] && + m[2][2] == other.m[2][2]; +} + +bool QOpenVGMatrix::operator!=(const QOpenVGMatrix &other) const +{ + return m[0][0] != other.m[0][0] || + m[0][1] != other.m[0][1] || + m[0][2] != other.m[0][2] || + m[1][0] != other.m[1][0] || + m[1][1] != other.m[1][1] || + m[1][2] != other.m[1][2] || + m[2][0] != other.m[2][0] || + m[2][1] != other.m[2][1] || + m[2][2] != other.m[2][2]; +} + +void QOpenVGMatrix::copyDataTo(float *values) const +{ + // Row-Major? + for (int row = 0; row < 3; ++row) { + for (int col = 0; col < 3; ++col) + values[row * 3 + col] = float(m[col][row]); + } +} + +QOpenVGMatrix operator*(const QOpenVGMatrix &m1, const QOpenVGMatrix &m2) +{ + QOpenVGMatrix matrix; + matrix.m[0][0] = m1.m[0][0] * m2.m[0][0] + + m1.m[1][0] * m2.m[0][1] + + m1.m[2][0] * m2.m[0][2]; + matrix.m[0][1] = m1.m[0][1] * m2.m[0][0] + + m1.m[1][1] * m2.m[0][1] + + m1.m[2][1] * m2.m[0][2]; + matrix.m[0][2] = m1.m[0][2] * m2.m[0][0] + + m1.m[1][2] * m2.m[0][1] + + m1.m[2][2] * m2.m[0][2]; + + matrix.m[1][0] = m1.m[0][0] * m2.m[1][0] + + m1.m[1][0] * m2.m[1][1] + + m1.m[2][0] * m2.m[1][2]; + matrix.m[1][1] = m1.m[0][1] * m2.m[1][0] + + m1.m[1][1] * m2.m[1][1] + + m1.m[2][1] * m2.m[1][2]; + matrix.m[1][2] = m1.m[0][2] * m2.m[1][0] + + m1.m[1][2] * m2.m[1][1] + + m1.m[2][2] * m2.m[1][2]; + + matrix.m[2][0] = m1.m[0][0] * m2.m[2][0] + + m1.m[1][0] * m2.m[2][1] + + m1.m[2][0] * m2.m[2][2]; + matrix.m[2][1] = m1.m[0][1] * m2.m[2][0] + + m1.m[1][1] * m2.m[2][1] + + m1.m[2][1] * m2.m[2][2]; + matrix.m[2][2] = m1.m[0][2] * m2.m[2][0] + + m1.m[1][2] * m2.m[2][1] + + m1.m[2][2] * m2.m[2][2]; + return matrix; +} + +QPointF operator*(const QPointF& point, const QOpenVGMatrix& matrix) +{ + float xin = point.x(); + float yin = point.y(); + float x = xin * matrix.m[0][0] + + yin * matrix.m[0][1] + + matrix.m[0][2]; + float y = xin * matrix.m[1][0] + + yin * matrix.m[1][1] + + matrix.m[1][2]; + float w = xin * matrix.m[2][0] + + yin * matrix.m[2][1] + + matrix.m[2][2]; + if (w == 1.0f) { + return QPointF(float(x), float(y)); + } else { + return QPointF(float(x / w), float(y / w)); + } +} + +QPointF operator*(const QOpenVGMatrix& matrix, const QPointF& point) +{ + float xin = point.x(); + float yin = point.y(); + float x = xin * matrix.m[0][0] + + yin * matrix.m[1][0] + + matrix.m[2][0]; + float y = xin * matrix.m[0][1] + + yin * matrix.m[1][1] + + matrix.m[2][1]; + float w = xin * matrix.m[0][2] + + yin * matrix.m[1][2] + + matrix.m[2][2]; + if (w == 1.0f) { + return QPointF(float(x), float(y)); + } else { + return QPointF(float(x / w), float(y / w)); + } +} + +QDebug operator<<(QDebug dbg, const QOpenVGMatrix &m) +{ + QDebugStateSaver saver(dbg); + // Output in row-major order because it is more human-readable. + dbg.nospace() << "QOpenVGMatrix:(" << endl + << qSetFieldWidth(10) + << m(0, 0) << m(0, 1) << m(0, 2) << endl + << m(1, 0) << m(1, 1) << m(1, 2) << endl + << m(2, 0) << m(2, 1) << m(2, 2) << endl + << qSetFieldWidth(0) << ')'; + return dbg; +} + +QDataStream &operator<<(QDataStream &stream, const QOpenVGMatrix &matrix) +{ + for (int row = 0; row < 3; ++row) + for (int col = 0; col < 3; ++col) + stream << matrix(row, col); + return stream; +} + + +QDataStream &operator>>(QDataStream &stream, QOpenVGMatrix &matrix) +{ + float x; + for (int row = 0; row < 4; ++row) { + for (int col = 0; col < 4; ++col) { + stream >> x; + matrix(row, col) = x; + } + } + return stream; +} + + +QT_END_NAMESPACE diff --git a/src/plugins/scenegraph/openvg/qopenvgmatrix.h b/src/plugins/scenegraph/openvg/qopenvgmatrix.h new file mode 100644 index 0000000000..f51bf8147d --- /dev/null +++ b/src/plugins/scenegraph/openvg/qopenvgmatrix.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOPENVGMATRIX_H +#define QOPENVGMATRIX_H + +#include <QtCore/qdebug.h> +#include <QtCore/QDataStream> +#include <QtCore/QPointF> + +QT_BEGIN_NAMESPACE + +class QOpenVGMatrix +{ +public: + QOpenVGMatrix(); + explicit QOpenVGMatrix(const float *values); + + const float& operator()(int row, int column) const; + float& operator()(int row, int column); + + bool isIdentity() const; + void setToIdentity(); + + bool isAffine() const; + + QPointF map(const QPointF& point) const; + + void fill(float value); + + QOpenVGMatrix transposed() const; + + QOpenVGMatrix& operator+=(const QOpenVGMatrix& other); + QOpenVGMatrix& operator-=(const QOpenVGMatrix& other); + QOpenVGMatrix& operator*=(const QOpenVGMatrix& other); + QOpenVGMatrix& operator*=(float factor); + QOpenVGMatrix& operator/=(float divisor); + friend QOpenVGMatrix operator*(const QOpenVGMatrix& m1, const QOpenVGMatrix& m2); + friend QPointF operator*(const QPointF& point, const QOpenVGMatrix& matrix); + friend QPointF operator*(const QOpenVGMatrix& matrix, const QPointF& point); +#ifndef QT_NO_DEBUG_STREAM + friend QDebug operator<<(QDebug dbg, const QOpenVGMatrix &m); +#endif + bool operator==(const QOpenVGMatrix& other) const; + bool operator!=(const QOpenVGMatrix& other) const; + + void copyDataTo(float *values) const; + + float *data() { return *m; } + const float *data() const { return *m; } + const float *constData() const { return *m; } + +private: + float m[3][3]; +}; + +QOpenVGMatrix operator*(const QOpenVGMatrix& m1, const QOpenVGMatrix& m2); +QPointF operator*(const QPointF& point, const QOpenVGMatrix& matrix); +QPointF operator*(const QOpenVGMatrix& matrix, const QPointF& point); + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug dbg, const QOpenVGMatrix &m); +#endif + +#ifndef QT_NO_DATASTREAM +QDataStream &operator<<(QDataStream &, const QOpenVGMatrix &); +QDataStream &operator>>(QDataStream &, QOpenVGMatrix &); +#endif + +QT_END_NAMESPACE + +#endif // QOPENVGMATRIX_H diff --git a/src/plugins/scenegraph/openvg/qopenvgoffscreensurface.cpp b/src/plugins/scenegraph/openvg/qopenvgoffscreensurface.cpp new file mode 100644 index 0000000000..80af227fb4 --- /dev/null +++ b/src/plugins/scenegraph/openvg/qopenvgoffscreensurface.cpp @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qopenvgoffscreensurface.h" + +#include <QtGui/QImage> +#include <QDebug> + +QT_BEGIN_NAMESPACE + +QOpenVGOffscreenSurface::QOpenVGOffscreenSurface(const QSize &size) + : m_size(size) +{ + m_display = eglGetCurrentDisplay(); + m_image = vgCreateImage(VG_sARGB_8888_PRE, m_size.width(), m_size.height(), VG_IMAGE_QUALITY_BETTER); + + const EGLint configAttribs[] = { + EGL_CONFORMANT, EGL_OPENVG_BIT, + EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_ALPHA_MASK_SIZE, 8, + EGL_NONE + }; + + EGLConfig pbufferConfig; + EGLint numConfig; + eglChooseConfig(m_display, configAttribs, &pbufferConfig, 1, &numConfig); + + m_context = eglCreateContext(m_display, pbufferConfig, eglGetCurrentContext(), 0); + if (m_context == EGL_NO_CONTEXT) + qWarning("QOpenVGOffscreenSurface: failed to create EGLContext"); + + m_renderTarget = eglCreatePbufferFromClientBuffer(m_display, + EGL_OPENVG_IMAGE, + (EGLClientBuffer)m_image, + pbufferConfig, + 0); + if (m_renderTarget == EGL_NO_SURFACE) + qWarning("QOpenVGOffscreenSurface: failed to create EGLSurface from VGImage"); +} + +QOpenVGOffscreenSurface::~QOpenVGOffscreenSurface() +{ + vgDestroyImage(m_image); + eglDestroySurface(m_display, m_renderTarget); + eglDestroyContext(m_display, m_context); +} + +void QOpenVGOffscreenSurface::makeCurrent() +{ + EGLContext currentContext = eglGetCurrentContext(); + if (m_context != currentContext) { + m_previousContext = eglGetCurrentContext(); + m_previousReadSurface = eglGetCurrentSurface(EGL_READ); + m_previousDrawSurface = eglGetCurrentSurface(EGL_DRAW); + + eglMakeCurrent(m_display, m_renderTarget, m_renderTarget, m_context); + } +} + +void QOpenVGOffscreenSurface::doneCurrent() +{ + EGLContext currentContext = eglGetCurrentContext(); + if (m_context == currentContext) { + eglMakeCurrent(m_display, m_previousDrawSurface, m_previousReadSurface, m_previousContext); + m_previousContext = EGL_NO_CONTEXT; + m_previousReadSurface = EGL_NO_SURFACE; + m_previousDrawSurface = EGL_NO_SURFACE; + } +} + +void QOpenVGOffscreenSurface::swapBuffers() +{ + eglSwapBuffers(m_display, m_renderTarget); +} + +QImage QOpenVGOffscreenSurface::readbackQImage() +{ + QImage readbackImage(m_size, QImage::Format_ARGB32_Premultiplied); + vgGetImageSubData(m_image, readbackImage.bits(), readbackImage.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0, m_size.width(), m_size.height()); + return readbackImage; +} + +QT_END_NAMESPACE diff --git a/src/plugins/scenegraph/openvg/qopenvgoffscreensurface.h b/src/plugins/scenegraph/openvg/qopenvgoffscreensurface.h new file mode 100644 index 0000000000..746e4de1cd --- /dev/null +++ b/src/plugins/scenegraph/openvg/qopenvgoffscreensurface.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOPENVGOFFSCREENSURFACE_H +#define QOPENVGOFFSCREENSURFACE_H + +#include "qopenvgcontext_p.h" + +QT_BEGIN_NAMESPACE + +class QOpenVGOffscreenSurface +{ +public: + QOpenVGOffscreenSurface(const QSize &size); + ~QOpenVGOffscreenSurface(); + + void makeCurrent(); + void doneCurrent(); + void swapBuffers(); + + VGImage image() { return m_image; } + QSize size() const { return m_size; } + + QImage readbackQImage(); + +private: + VGImage m_image; + QSize m_size; + EGLContext m_context; + EGLSurface m_renderTarget; + EGLContext m_previousContext = EGL_NO_CONTEXT; + EGLSurface m_previousReadSurface = EGL_NO_SURFACE; + EGLSurface m_previousDrawSurface = EGL_NO_SURFACE; + EGLDisplay m_display; +}; + +QT_END_NAMESPACE + +#endif // QOPENVGOFFSCREENSURFACE_H diff --git a/src/plugins/scenegraph/openvg/qsgopenvgadaptation.cpp b/src/plugins/scenegraph/openvg/qsgopenvgadaptation.cpp new file mode 100644 index 0000000000..1a26522459 --- /dev/null +++ b/src/plugins/scenegraph/openvg/qsgopenvgadaptation.cpp @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgopenvgadaptation_p.h" + +#include "qsgopenvgcontext_p.h" +#include "qsgopenvgrenderloop_p.h" + +QT_BEGIN_NAMESPACE + +QSGOpenVGAdaptation::QSGOpenVGAdaptation(QObject *parent) + : QSGContextPlugin(parent) +{ +} + +QStringList QSGOpenVGAdaptation::keys() const +{ + return QStringList() << QLatin1String("openvg"); +} + +QSGContext *QSGOpenVGAdaptation::create(const QString &key) const +{ + Q_UNUSED(key) + if (!instance) + instance = new QSGOpenVGContext(); + return instance; +} + +QSGRenderLoop *QSGOpenVGAdaptation::createWindowManager() +{ + return new QSGOpenVGRenderLoop(); +} + +QSGContextFactoryInterface::Flags QSGOpenVGAdaptation::flags(const QString &key) const +{ + Q_UNUSED(key) + return 0; +} + +QSGOpenVGContext *QSGOpenVGAdaptation::instance = nullptr; + +QT_END_NAMESPACE diff --git a/src/plugins/scenegraph/openvg/qsgopenvgadaptation_p.h b/src/plugins/scenegraph/openvg/qsgopenvgadaptation_p.h new file mode 100644 index 0000000000..77f79af9ac --- /dev/null +++ b/src/plugins/scenegraph/openvg/qsgopenvgadaptation_p.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGOPENVGADAPTATION_H +#define QSGOPENVGADAPTATION_H + +#include <private/qsgcontextplugin_p.h> + +QT_BEGIN_NAMESPACE + +class QSGContext; +class QSGRenderLoop; +class QSGOpenVGContext; + +class QSGOpenVGAdaptation : public QSGContextPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QSGContextFactoryInterface" FILE "openvg.json") +public: + QSGOpenVGAdaptation(QObject *parent = nullptr); + + QStringList keys() const override; + QSGContext *create(const QString &key) const override; + QSGRenderLoop *createWindowManager() override; + Flags flags(const QString &key) const override; +private: + static QSGOpenVGContext *instance; +}; + +QT_END_NAMESPACE + +#endif // QSGOPENVGADAPTATION_H diff --git a/src/plugins/scenegraph/openvg/qsgopenvgcontext.cpp b/src/plugins/scenegraph/openvg/qsgopenvgcontext.cpp new file mode 100644 index 0000000000..22a80c62e8 --- /dev/null +++ b/src/plugins/scenegraph/openvg/qsgopenvgcontext.cpp @@ -0,0 +1,219 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgopenvgcontext_p.h" +#include "qsgopenvgrenderer_p.h" +#include "qsgopenvginternalrectanglenode.h" +#include "qsgopenvginternalimagenode.h" +#include "qsgopenvgpublicnodes.h" +#include "qsgopenvgtexture.h" +#include "qsgopenvglayer.h" +#include "qsgopenvgglyphnode_p.h" +#include "qsgopenvgfontglyphcache.h" +#include "qsgopenvgpainternode.h" +#include "qsgopenvgspritenode.h" + +#include "qopenvgcontext_p.h" + +#include <private/qsgrenderer_p.h> + +// polish, animations, sync, render and swap in the render loop +Q_LOGGING_CATEGORY(QSG_OPENVG_LOG_TIME_RENDERLOOP, "qt.scenegraph.time.renderloop") + +QT_BEGIN_NAMESPACE + +QSGOpenVGRenderContext::QSGOpenVGRenderContext(QSGContext *context) + : QSGRenderContext(context) + , m_vgContext(nullptr) + , m_glyphCacheManager(nullptr) +{ + +} + +void QSGOpenVGRenderContext::initialize(void *context) +{ + m_vgContext = static_cast<QOpenVGContext*>(context); + QSGRenderContext::initialize(context); +} + +void QSGOpenVGRenderContext::invalidate() +{ + m_vgContext = nullptr; + delete m_glyphCacheManager; + m_glyphCacheManager = nullptr; + QSGRenderContext::invalidate(); +} + +void QSGOpenVGRenderContext::renderNextFrame(QSGRenderer *renderer, uint fboId) +{ + renderer->renderScene(fboId); +} + +QSGTexture *QSGOpenVGRenderContext::createTexture(const QImage &image, uint flags) const +{ + QImage tmp = image; + + // Make sure image is not larger than maxTextureSize + int maxSize = maxTextureSize(); + if (tmp.width() > maxSize || tmp.height() > maxSize) { + tmp = tmp.scaled(qMin(maxSize, tmp.width()), qMin(maxSize, tmp.height()), Qt::IgnoreAspectRatio, Qt::FastTransformation); + } + + return new QSGOpenVGTexture(tmp, flags); +} + +QSGRenderer *QSGOpenVGRenderContext::createRenderer() +{ + return new QSGOpenVGRenderer(this); +} + +QSGOpenVGContext::QSGOpenVGContext(QObject *parent) +{ + Q_UNUSED(parent) +} + +QSGRenderContext *QSGOpenVGContext::createRenderContext() +{ + return new QSGOpenVGRenderContext(this); +} + +QSGRectangleNode *QSGOpenVGContext::createRectangleNode() +{ + return new QSGOpenVGRectangleNode; +} + +QSGImageNode *QSGOpenVGContext::createImageNode() +{ + return new QSGOpenVGImageNode; +} + +QSGPainterNode *QSGOpenVGContext::createPainterNode(QQuickPaintedItem *item) +{ + Q_UNUSED(item) + return new QSGOpenVGPainterNode(item); +} + +QSGGlyphNode *QSGOpenVGContext::createGlyphNode(QSGRenderContext *rc, bool preferNativeGlyphNode) +{ + Q_UNUSED(preferNativeGlyphNode) + return new QSGOpenVGGlyphNode(rc); +} + +QSGNinePatchNode *QSGOpenVGContext::createNinePatchNode() +{ + return new QSGOpenVGNinePatchNode; +} + +QSGLayer *QSGOpenVGContext::createLayer(QSGRenderContext *renderContext) +{ + return new QSGOpenVGLayer(renderContext); +} + +QSurfaceFormat QSGOpenVGContext::defaultSurfaceFormat() const +{ + QSurfaceFormat format = QSurfaceFormat::defaultFormat(); + format.setRenderableType(QSurfaceFormat::OpenVG); + format.setMajorVersion(1); + return format; +} + +QSGInternalRectangleNode *QSGOpenVGContext::createInternalRectangleNode() +{ + return new QSGOpenVGInternalRectangleNode(); +} + +QSGInternalImageNode *QSGOpenVGContext::createInternalImageNode() +{ + return new QSGOpenVGInternalImageNode(); +} + +int QSGOpenVGRenderContext::maxTextureSize() const +{ + VGint width = vgGeti(VG_MAX_IMAGE_WIDTH); + VGint height = vgGeti(VG_MAX_IMAGE_HEIGHT); + + return qMin(width, height); +} + + +QSGSpriteNode *QSGOpenVGContext::createSpriteNode() +{ + return new QSGOpenVGSpriteNode(); +} + +QSGRendererInterface *QSGOpenVGContext::rendererInterface(QSGRenderContext *renderContext) +{ + return static_cast<QSGOpenVGRenderContext *>(renderContext); +} + +QSGRendererInterface::GraphicsApi QSGOpenVGRenderContext::graphicsApi() const +{ + return OpenVG; +} + +QSGRendererInterface::ShaderType QSGOpenVGRenderContext::shaderType() const +{ + return UnknownShadingLanguage; +} + +QSGRendererInterface::ShaderCompilationTypes QSGOpenVGRenderContext::shaderCompilationType() const +{ + return 0; +} + +QSGRendererInterface::ShaderSourceTypes QSGOpenVGRenderContext::shaderSourceType() const +{ + return 0; +} + +QSGOpenVGFontGlyphCache *QSGOpenVGRenderContext::glyphCache(const QRawFont &rawFont) +{ + if (!m_glyphCacheManager) + m_glyphCacheManager = new QSGOpenVGFontGlyphCacheManager; + + QSGOpenVGFontGlyphCache *cache = m_glyphCacheManager->cache(rawFont); + if (!cache) { + cache = new QSGOpenVGFontGlyphCache(m_glyphCacheManager, rawFont); + m_glyphCacheManager->insertCache(rawFont, cache); + } + + return cache; +} + +QT_END_NAMESPACE diff --git a/src/plugins/scenegraph/openvg/qsgopenvgcontext_p.h b/src/plugins/scenegraph/openvg/qsgopenvgcontext_p.h new file mode 100644 index 0000000000..fa9939a253 --- /dev/null +++ b/src/plugins/scenegraph/openvg/qsgopenvgcontext_p.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGOPENVGCONTEXT_H +#define QSGOPENVGCONTEXT_H + +#include <private/qsgcontext_p.h> +#include <qsgrendererinterface.h> + +Q_DECLARE_LOGGING_CATEGORY(QSG_OPENVG_LOG_TIME_RENDERLOOP) + +QT_BEGIN_NAMESPACE + +class QOpenVGContext; +class QSGOpenVGFontGlyphCache; +class QSGOpenVGFontGlyphCacheManager; + +class QSGOpenVGRenderContext : public QSGRenderContext, public QSGRendererInterface +{ + Q_OBJECT +public: + QSGOpenVGRenderContext(QSGContext *context); + + void initialize(void *context) override; + void invalidate() override; + void renderNextFrame(QSGRenderer *renderer, uint fboId) override; + QSGTexture *createTexture(const QImage &image, uint flags) const override; + QSGRenderer *createRenderer() override; + int maxTextureSize() const override; + + // QSGRendererInterface interface + GraphicsApi graphicsApi() const override; + ShaderType shaderType() const override; + ShaderCompilationTypes shaderCompilationType() const override; + ShaderSourceTypes shaderSourceType() const override; + + QOpenVGContext* vgContext() { return m_vgContext; } + QSGOpenVGFontGlyphCache* glyphCache(const QRawFont &rawFont); + +private: + QOpenVGContext *m_vgContext; + QSGOpenVGFontGlyphCacheManager *m_glyphCacheManager; + +}; + +class QSGOpenVGContext : public QSGContext +{ + Q_OBJECT +public: + QSGOpenVGContext(QObject *parent = nullptr); + + QSGRenderContext *createRenderContext() override; + QSGRectangleNode *createRectangleNode() override; + QSGImageNode *createImageNode() override; + QSGPainterNode *createPainterNode(QQuickPaintedItem *item) override; + QSGGlyphNode *createGlyphNode(QSGRenderContext *rc, bool preferNativeGlyphNode) override; + QSGNinePatchNode *createNinePatchNode() override; + QSGLayer *createLayer(QSGRenderContext *renderContext) override; + QSurfaceFormat defaultSurfaceFormat() const override; + QSGInternalRectangleNode *createInternalRectangleNode() override; + QSGInternalImageNode *createInternalImageNode() override; + QSGSpriteNode *createSpriteNode() override; + QSGRendererInterface *rendererInterface(QSGRenderContext *renderContext) override; +}; + +#endif // QSGOPENVGCONTEXT_H + +QT_END_NAMESPACE diff --git a/src/plugins/scenegraph/openvg/qsgopenvgfontglyphcache.cpp b/src/plugins/scenegraph/openvg/qsgopenvgfontglyphcache.cpp new file mode 100644 index 0000000000..dd630c776f --- /dev/null +++ b/src/plugins/scenegraph/openvg/qsgopenvgfontglyphcache.cpp @@ -0,0 +1,162 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgopenvgfontglyphcache.h" +#include "qsgopenvghelpers.h" +#include <private/qfontengine_p.h> +#include <private/qrawfont_p.h> + +QT_BEGIN_NAMESPACE + +QSGOpenVGFontGlyphCacheManager::QSGOpenVGFontGlyphCacheManager() +{ + +} + +QSGOpenVGFontGlyphCacheManager::~QSGOpenVGFontGlyphCacheManager() +{ + qDeleteAll(m_caches); +} + +QSGOpenVGFontGlyphCache *QSGOpenVGFontGlyphCacheManager::cache(const QRawFont &font) +{ + return m_caches.value(font, nullptr); +} + +void QSGOpenVGFontGlyphCacheManager::insertCache(const QRawFont &font, QSGOpenVGFontGlyphCache *cache) +{ + m_caches.insert(font, cache); +} + +QSGOpenVGFontGlyphCache::QSGOpenVGFontGlyphCache(QSGOpenVGFontGlyphCacheManager *manager, const QRawFont &font) + : m_manager(manager) +{ + m_referenceFont = font; + QRawFontPrivate *fontD = QRawFontPrivate::get(font); + m_glyphCount = fontD->fontEngine->glyphCount(); + m_font = vgCreateFont(0); +} + +QSGOpenVGFontGlyphCache::~QSGOpenVGFontGlyphCache() +{ + if (m_font != VG_INVALID_HANDLE) + vgDestroyFont(m_font); +} + +void QSGOpenVGFontGlyphCache::populate(const QVector<quint32> &glyphs) +{ + QSet<quint32> referencedGlyphs; + QSet<quint32> newGlyphs; + int count = glyphs.count(); + for (int i = 0; i < count; ++i) { + quint32 glyphIndex = glyphs.at(i); + if ((int) glyphIndex >= glyphCount()) { + qWarning("Warning: glyph is not available with index %d", glyphIndex); + continue; + } + + referencedGlyphs.insert(glyphIndex); + + + if (!m_cachedGlyphs.contains(glyphIndex)) { + newGlyphs.insert(glyphIndex); + } + } + + referenceGlyphs(referencedGlyphs); + if (!newGlyphs.isEmpty()) + requestGlyphs(newGlyphs); +} + +void QSGOpenVGFontGlyphCache::release(const QVector<quint32> &glyphs) +{ + QSet<quint32> unusedGlyphs; + int count = glyphs.count(); + for (int i = 0; i < count; ++i) { + quint32 glyphIndex = glyphs.at(i); + unusedGlyphs.insert(glyphIndex); + } + releaseGlyphs(unusedGlyphs); +} + +void QSGOpenVGFontGlyphCache::requestGlyphs(const QSet<quint32> &glyphs) +{ + VGfloat origin[2]; + VGfloat escapement[2]; + QRectF metrics; + QRawFont rawFont = m_referenceFont; + + // Before adding any new glyphs, remove any unused glyphs + for (auto glyph : qAsConst(m_unusedGlyphs)) { + vgClearGlyph(m_font, glyph); + } + + for (auto glyph : glyphs) { + m_cachedGlyphs.insert(glyph); + + // Calculate the path for the glyph and cache it. + QPainterPath path = rawFont.pathForGlyph(glyph); + VGPath vgPath; + if (!path.isEmpty()) { + vgPath = QSGOpenVGHelpers::qPainterPathToVGPath(path); + } else { + // Probably a "space" character with no visible outline. + vgPath = VG_INVALID_HANDLE; + } + origin[0] = 0; + origin[1] = 0; + escapement[0] = 0; + escapement[1] = 0; + vgSetGlyphToPath(m_font, glyph, vgPath, VG_FALSE, origin, escapement); + vgDestroyPath(vgPath); // Reduce reference count. + } + +} + +void QSGOpenVGFontGlyphCache::referenceGlyphs(const QSet<quint32> &glyphs) +{ + m_unusedGlyphs -= glyphs; +} + +void QSGOpenVGFontGlyphCache::releaseGlyphs(const QSet<quint32> &glyphs) +{ + m_unusedGlyphs += glyphs; +} + +QT_END_NAMESPACE diff --git a/src/plugins/scenegraph/openvg/qsgopenvgfontglyphcache.h b/src/plugins/scenegraph/openvg/qsgopenvgfontglyphcache.h new file mode 100644 index 0000000000..a88d28b0fe --- /dev/null +++ b/src/plugins/scenegraph/openvg/qsgopenvgfontglyphcache.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGOPENVGFONTGLYPHCACHE_H +#define QSGOPENVGFONTGLYPHCACHE_H + +#include <QtGui/QGlyphRun> +#include <QtCore/QSet> +#include <QtCore/QLinkedList> +#include <VG/openvg.h> + +QT_BEGIN_NAMESPACE + +class QSGOpenVGFontGlyphCache; + +class QSGOpenVGFontGlyphCacheManager +{ +public: + QSGOpenVGFontGlyphCacheManager(); + ~QSGOpenVGFontGlyphCacheManager(); + + QSGOpenVGFontGlyphCache *cache(const QRawFont &font); + void insertCache(const QRawFont &font, QSGOpenVGFontGlyphCache *cache); + +private: + QHash<QRawFont, QSGOpenVGFontGlyphCache *> m_caches; +}; + +class QSGOpenVGFontGlyphCache +{ +public: + QSGOpenVGFontGlyphCache(QSGOpenVGFontGlyphCacheManager *manager, const QRawFont &font); + ~QSGOpenVGFontGlyphCache(); + + const QSGOpenVGFontGlyphCacheManager *manager() const { return m_manager; } + const QRawFont &referenceFont() const { return m_referenceFont; } + int glyphCount() const { return m_glyphCount; } + + void populate(const QVector<quint32> &glyphs); + void release(const QVector<quint32> &glyphs); + + VGFont font() { return m_font; } + +private: + void requestGlyphs(const QSet<quint32> &glyphs); + void referenceGlyphs(const QSet<quint32> &glyphs); + void releaseGlyphs(const QSet<quint32> &glyphs); + + QSGOpenVGFontGlyphCacheManager *m_manager; + QRawFont m_referenceFont; + int m_glyphCount; + + VGFont m_font; + QSet<quint32> m_cachedGlyphs; + QSet<quint32> m_unusedGlyphs; +}; + + +QT_END_NAMESPACE + +#endif // QSGOPENVGFONTGLYPHCACHE_H diff --git a/src/plugins/scenegraph/openvg/qsgopenvgglyphnode.cpp b/src/plugins/scenegraph/openvg/qsgopenvgglyphnode.cpp new file mode 100644 index 0000000000..8be2a97034 --- /dev/null +++ b/src/plugins/scenegraph/openvg/qsgopenvgglyphnode.cpp @@ -0,0 +1,214 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgopenvgglyphnode_p.h" +#include "qopenvgcontext_p.h" +#include "qsgopenvgcontext_p.h" +#include "qsgopenvghelpers.h" +#include "qsgopenvgfontglyphcache.h" +#include "qopenvgoffscreensurface.h" + +QT_BEGIN_NAMESPACE + +QSGOpenVGGlyphNode::QSGOpenVGGlyphNode(QSGRenderContext *rc) + : m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 0) + , m_style(QQuickText::Normal) + , m_glyphCache(nullptr) +{ + // Set Dummy material to avoid asserts + setMaterial((QSGMaterial*)1); + setGeometry(&m_geometry); + m_fontColorPaint = vgCreatePaint(); + m_styleColorPaint = vgCreatePaint(); + + // Get handle to Glyph Cache + m_renderContext = static_cast<QSGOpenVGRenderContext*>(rc); +} + +QSGOpenVGGlyphNode::~QSGOpenVGGlyphNode() +{ + if (m_glyphCache) + m_glyphCache->release(m_glyphRun.glyphIndexes()); + + vgDestroyPaint(m_fontColorPaint); + vgDestroyPaint(m_styleColorPaint); +} + +void QSGOpenVGGlyphNode::setGlyphs(const QPointF &position, const QGlyphRun &glyphs) +{ + // Obtain glyph cache for font + auto oldGlyphCache = m_glyphCache; + m_glyphCache = m_renderContext->glyphCache(glyphs.rawFont()); + if (m_glyphCache != oldGlyphCache) { + if (oldGlyphCache) + oldGlyphCache->release(m_glyphRun.glyphIndexes()); + } + m_glyphCache->populate(glyphs.glyphIndexes()); + + m_position = position; + m_glyphRun = glyphs; + m_bounding_rect = glyphs.boundingRect().translated(m_position - QPointF(0.0, glyphs.rawFont().ascent())); + + // Recreate ajustments + m_xAdjustments.clear(); + m_yAdjustments.clear(); + + for (int i = 1; i < glyphs.positions().count(); ++i) { + m_xAdjustments.append(glyphs.positions().at(i).x() - glyphs.positions().at(i-1).x()); + m_yAdjustments.append(glyphs.positions().at(i).y() - glyphs.positions().at(i-1).y()); + } +} + +void QSGOpenVGGlyphNode::setColor(const QColor &color) +{ + m_color = color; + vgSetParameteri(m_fontColorPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); + vgSetParameterfv(m_fontColorPaint, VG_PAINT_COLOR, 4, QSGOpenVGHelpers::qColorToVGColor(m_color, opacity()).constData()); +} + +void QSGOpenVGGlyphNode::setStyle(QQuickText::TextStyle style) +{ + m_style = style; +} + +void QSGOpenVGGlyphNode::setStyleColor(const QColor &color) +{ + m_styleColor = color; + vgSetParameteri(m_styleColorPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); + vgSetParameterfv(m_styleColorPaint, VG_PAINT_COLOR, 4, QSGOpenVGHelpers::qColorToVGColor(m_styleColor, opacity()).constData()); +} + +QPointF QSGOpenVGGlyphNode::baseLine() const +{ + return QPointF(); +} + +void QSGOpenVGGlyphNode::setPreferredAntialiasingMode(QSGGlyphNode::AntialiasingMode) +{ +} + +void QSGOpenVGGlyphNode::update() +{ +} + +void QSGOpenVGGlyphNode::render() +{ + if (m_glyphRun.positions().count() == 0) + return; + + // Rendering Style + qreal offset = 1.0; + + QOpenVGOffscreenSurface *offscreenSurface = nullptr; + + // Set Transform + vgSeti(VG_MATRIX_MODE, VG_MATRIX_GLYPH_USER_TO_SURFACE); + if (transform().isAffine()) { + vgLoadMatrix(transform().constData()); + } else { + vgLoadIdentity(); + offscreenSurface = new QOpenVGOffscreenSurface(QSize(ceil(m_bounding_rect.width()), ceil(m_bounding_rect.height()))); + offscreenSurface->makeCurrent(); + } + + // Set Quality + vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_BETTER); + + + switch (m_style) { + case QQuickText::Normal: break; + case QQuickText::Outline: + // Set the correct fill state + vgSetPaint(m_styleColorPaint, VG_FILL_PATH); + drawGlyphsAtOffset(QPointF(0, offset)); + drawGlyphsAtOffset(QPointF(0, -offset)); + drawGlyphsAtOffset(QPointF(offset, 0)); + drawGlyphsAtOffset(QPointF(-offset, 0)); + break; + case QQuickText::Raised: + vgSetPaint(m_styleColorPaint, VG_FILL_PATH); + drawGlyphsAtOffset(QPointF(0, offset)); + break; + case QQuickText::Sunken: + vgSetPaint(m_styleColorPaint, VG_FILL_PATH); + drawGlyphsAtOffset(QPointF(0, -offset)); + break; + } + + // Set the correct fill state + vgSetPaint(m_fontColorPaint, VG_FILL_PATH); + drawGlyphsAtOffset(QPointF(0.0, 0.0)); + + if (!transform().isAffine()) { + vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE); + vgLoadMatrix(transform().constData()); + offscreenSurface->doneCurrent(); + vgDrawImage(offscreenSurface->image()); + delete offscreenSurface; + } +} + +void QSGOpenVGGlyphNode::setOpacity(float opacity) +{ + if (QSGOpenVGRenderable::opacity() != opacity) { + QSGOpenVGRenderable::setOpacity(opacity); + // Update Colors + setColor(m_color); + setStyleColor(m_styleColor); + } +} + +void QSGOpenVGGlyphNode::drawGlyphsAtOffset(const QPointF &offset) +{ + QPointF firstPosition = m_glyphRun.positions()[0] + (m_position - QPointF(0, m_glyphRun.rawFont().ascent())); + VGfloat origin[2]; + origin[0] = firstPosition.x() + offset.x(); + origin[1] = firstPosition.y() + offset.y(); + vgSetfv(VG_GLYPH_ORIGIN, 2, origin); + + vgDrawGlyphs(m_glyphCache->font(), + m_glyphRun.glyphIndexes().count(), + (VGuint*)m_glyphRun.glyphIndexes().constData(), + m_xAdjustments.constData(), + m_yAdjustments.constData(), + VG_FILL_PATH, + VG_TRUE); +} + +QT_END_NAMESPACE diff --git a/src/plugins/scenegraph/openvg/qsgopenvgglyphnode_p.h b/src/plugins/scenegraph/openvg/qsgopenvgglyphnode_p.h new file mode 100644 index 0000000000..205e3dcbc8 --- /dev/null +++ b/src/plugins/scenegraph/openvg/qsgopenvgglyphnode_p.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGOPENVGGLYPHNODE_H +#define QSGOPENVGGLYPHNODE_H + +#include <private/qsgadaptationlayer_p.h> +#include <QtCore/QVector> + +#include <VG/openvg.h> + +#include "qsgopenvgrenderable.h" +#include "qsgopenvgfontglyphcache.h" + +QT_BEGIN_NAMESPACE + +class QSGOpenVGFontGlyphCache; +class QSGOpenVGRenderContext; +class QSGRenderContext; + +class QSGOpenVGGlyphNode : public QSGGlyphNode, public QSGOpenVGRenderable +{ +public: + QSGOpenVGGlyphNode(QSGRenderContext *rc); + ~QSGOpenVGGlyphNode(); + + void setGlyphs(const QPointF &position, const QGlyphRun &glyphs) override; + void setColor(const QColor &color) override; + void setStyle(QQuickText::TextStyle style) override; + void setStyleColor(const QColor &color) override; + QPointF baseLine() const override; + void setPreferredAntialiasingMode(AntialiasingMode) override; + void update() override; + + void render() override; + void setOpacity(float opacity) override; + +private: + void drawGlyphsAtOffset(const QPointF &offset); + + QPointF m_position; + QGlyphRun m_glyphRun; + QColor m_color; + QSGGeometry m_geometry; + QQuickText::TextStyle m_style; + QColor m_styleColor; + + QSGOpenVGFontGlyphCache *m_glyphCache; + QVector<VGfloat> m_xAdjustments; + QVector<VGfloat> m_yAdjustments; + VGPaint m_fontColorPaint; + VGPaint m_styleColorPaint; + + QSGOpenVGRenderContext *m_renderContext; +}; + +QT_END_NAMESPACE + +#endif // QSGOPENVGGLYPHNODE_H diff --git a/src/plugins/scenegraph/openvg/qsgopenvghelpers.cpp b/src/plugins/scenegraph/openvg/qsgopenvghelpers.cpp new file mode 100644 index 0000000000..6bc99d32a1 --- /dev/null +++ b/src/plugins/scenegraph/openvg/qsgopenvghelpers.cpp @@ -0,0 +1,433 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgopenvghelpers.h" +#include <cmath> + +QT_BEGIN_NAMESPACE + +namespace QSGOpenVGHelpers { + +VGPath qPainterPathToVGPath(const QPainterPath &path) +{ + int count = path.elementCount(); + + VGPath vgpath = vgCreatePath(VG_PATH_FORMAT_STANDARD, + VG_PATH_DATATYPE_F, + 1.0f, // scale + 0.0f, // bias + count + 1, // segmentCapacityHint + count * 2, // coordCapacityHint + VG_PATH_CAPABILITY_ALL); + + if (count == 0) + return vgpath; + + QVector<VGfloat> coords; + QVector<VGubyte> segments; + + int curvePos = 0; + QPointF temp; + + // Keep track of the start and end of each sub-path. QPainterPath + // does not have an "implicit close" flag like QVectorPath does. + // We therefore have to detect closed paths by looking for a LineTo + // element that connects back to the initial MoveTo element. + qreal startx = 0.0; + qreal starty = 0.0; + qreal endx = 0.0; + qreal endy = 0.0; + bool haveStart = false; + bool haveEnd = false; + + for (int i = 0; i < count; ++i) { + const QPainterPath::Element element = path.elementAt(i); + switch (element.type) { + + case QPainterPath::MoveToElement: + { + if (haveStart && haveEnd && startx == endx && starty == endy) { + // Implicitly close the previous sub-path. + segments.append(VG_CLOSE_PATH); + } + temp = QPointF(element.x, element.y); + startx = temp.x(); + starty = temp.y(); + coords.append(startx); + coords.append(starty); + haveStart = true; + haveEnd = false; + segments.append(VG_MOVE_TO_ABS); + } + break; + + case QPainterPath::LineToElement: + { + temp = QPointF(element.x, element.y); + endx = temp.x(); + endy = temp.y(); + coords.append(endx); + coords.append(endy); + haveEnd = true; + segments.append(VG_LINE_TO_ABS); + } + break; + + case QPainterPath::CurveToElement: + { + temp = QPointF(element.x, element.y); + coords.append(temp.x()); + coords.append(temp.y()); + haveEnd = false; + curvePos = 2; + } + break; + + case QPainterPath::CurveToDataElement: + { + temp = QPointF(element.x, element.y); + coords.append(temp.x()); + coords.append(temp.y()); + haveEnd = false; + curvePos += 2; + if (curvePos == 6) { + curvePos = 0; + segments.append(VG_CUBIC_TO_ABS); + } + } + break; + + } + } + + if (haveStart && haveEnd && startx == endx && starty == endy) { + // Implicitly close the last sub-path. + segments.append(VG_CLOSE_PATH); + } + + vgAppendPathData(vgpath, segments.count(), + segments.constData(), coords.constData()); + + return vgpath; +} + + +void qDrawTiled(VGImage image, const QSize imageSize, const QRectF &targetRect, const QPointF offset, float scaleX, float scaleY) { + + //Check for valid image size and targetRect + if (imageSize.width() <= 0 || imageSize.height() <= 0) + return; + if (targetRect.width() <= 0 || targetRect.height() <= 0) + return; + + // This logic is mostly from the Qt Raster PaintEngine's qt_draw_tile + qreal drawH; + qreal drawW; + qreal xPos; + qreal xOff; + qreal yPos = targetRect.y(); + qreal yOff; + + if (offset.y() < 0) + yOff = imageSize.height() - qRound(-offset.y()) % imageSize.height(); + else + yOff = qRound(offset.y()) % imageSize.height(); + + + // Save the current image transform matrix + vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE); + QVector<float> originalMatrix(9); + vgGetMatrix(originalMatrix.data()); + + while (!qFuzzyCompare(yPos, targetRect.y() + targetRect.height()) && + yPos < targetRect.y() + targetRect.height()) { + drawH = imageSize.height() - yOff; // Cropping first row + if (yPos + drawH * scaleY > targetRect.y() + targetRect.height()) { // Cropping last row + // Check that values aren't equal + if (!qFuzzyCompare((float)(yPos + drawH * scaleY), (float)(targetRect.y() + targetRect.height()))) + drawH = targetRect.y() + targetRect.height() - yPos; + } + xPos = targetRect.x(); + if (offset.x() < 0) + xOff = imageSize.width() - qRound(-offset.x()) % imageSize.width(); + else + xOff = qRound(offset.x()) % imageSize.width(); + + while (!qFuzzyCompare(xPos, targetRect.x() + targetRect.width()) && + xPos < targetRect.x() + targetRect.width()) { + drawW = imageSize.width() - xOff; // Cropping first column + if (xPos + drawW * scaleX > targetRect.x() + targetRect.width()) { + // Check that values aren't equal + if (!qFuzzyCompare((float)(xPos + drawW * scaleX), (float)(targetRect.x() + targetRect.width()))) + drawW = targetRect.x() + targetRect.width() - xPos; + } + if (round(drawW) > 0 && round(drawH) > 0) { // Can't source image less than 1 width or height + //Draw here + VGImage childRectImage = vgChildImage(image, xOff, yOff, round(drawW), round(drawH)); + vgTranslate(xPos, yPos); + vgScale(scaleX, scaleY); + vgDrawImage(childRectImage); + vgDestroyImage(childRectImage); + vgLoadMatrix(originalMatrix.constData()); + } + if ( drawW > 0) + xPos += drawW * scaleX; + xOff = 0; + } + if ( drawH > 0) + yPos += drawH * scaleY; + yOff = 0; + + } +} + +void qDrawBorderImage(VGImage image, const QSizeF &textureSize, const QRectF &targetRect, const QRectF &innerTargetRect, const QRectF &subSourceRect) +{ + // Create normalized margins + QMarginsF margins(qMax(innerTargetRect.left() - targetRect.left(), 0.0), + qMax(innerTargetRect.top() - targetRect.top(), 0.0), + qMax(targetRect.right() - innerTargetRect.right(), 0.0), + qMax(targetRect.bottom() - innerTargetRect.bottom(), 0.0)); + + QRectF sourceRect(0, 0, textureSize.width(), textureSize.height()); + + // Create all the subRects + QRectF topLeftSourceRect(sourceRect.topLeft(), QSizeF(margins.left(), margins.top())); + QRectF topRightSourceRect(sourceRect.width() - margins.right(), sourceRect.top(), margins.right(), margins.top()); + QRectF bottomLeftSourceRect(sourceRect.left(), sourceRect.height() - margins.bottom(), margins.left(), margins.bottom()); + QRectF bottomRightSourceRect(sourceRect.width() - margins.right(), sourceRect.height() - margins.bottom(), margins.right(), margins.bottom()); + + QRectF topSourceRect(margins.left(), 0.0, sourceRect.width() - (margins.right() + margins.left()), margins.top()); + QRectF topTargetRect(margins.left(), 0.0, innerTargetRect.width(), margins.top()); + QRectF bottomSourceRect(margins.left(), sourceRect.height() - margins.bottom(), sourceRect.width() - (margins.right() + margins.left()), margins.bottom()); + QRectF bottomTargetRect(margins.left(), targetRect.height() - margins.bottom(), innerTargetRect.width(), margins.bottom()); + QRectF leftSourceRect(0.0, margins.top(), margins.left(), sourceRect.height() - (margins.bottom() + margins.top())); + QRectF leftTargetRect(0.0, margins.top(), margins.left(), innerTargetRect.height()); + QRectF rightSourceRect(sourceRect.width() - margins.right(), margins.top(), margins.right(), sourceRect.height() - (margins.bottom() + margins.top())); + QRectF rightTargetRect(targetRect.width() - margins.right(), margins.top(), margins.right(), innerTargetRect.height()); + + QRectF centerSourceRect(margins.left(), margins.top(), sourceRect.width() - (margins.right() + margins.left()), sourceRect.height() - (margins.top() + margins.bottom())); + + // Draw the 9 different sections + // (1) Top Left (unscaled) + qDrawSubImage(image, + topLeftSourceRect, + targetRect.topLeft()); + + // (3) Top Right (unscaled) + qDrawSubImage(image, + topRightSourceRect, + QPointF(targetRect.width() - margins.right(), 0.0)); + + // (7) Bottom Left (unscaled) + qDrawSubImage(image, + bottomLeftSourceRect, + QPointF(targetRect.left(), targetRect.height() - margins.bottom())); + + // (9) Bottom Right (unscaled) + qDrawSubImage(image, + bottomRightSourceRect, + QPointF(targetRect.width() - margins.right(), targetRect.height() - margins.bottom())); + + double scaledWidth = 1.0; + double scaledHeight = 1.0; + + // (2) Top (scaled via horizontalTileRule) + VGImage topImage = vgChildImage(image, topSourceRect.x(), topSourceRect.y(), topSourceRect.width(), topSourceRect.height()); + scaledWidth = (topTargetRect.width() / subSourceRect.width()) / topSourceRect.width(); + + QSGOpenVGHelpers::qDrawTiled(topImage, topSourceRect.size().toSize(), topTargetRect, QPoint(0.0, 0.0), scaledWidth, 1); + + vgDestroyImage(topImage); + + // (8) Bottom (scaled via horizontalTileRule) + VGImage bottomImage = vgChildImage(image, bottomSourceRect.x(), bottomSourceRect.y(), bottomSourceRect.width(), bottomSourceRect.height()); + scaledWidth = (bottomTargetRect.width() / subSourceRect.width()) / bottomSourceRect.width(); + + QSGOpenVGHelpers::qDrawTiled(bottomImage, bottomSourceRect.size().toSize(), bottomTargetRect, QPoint(0.0, 0.0), scaledWidth, 1); + + vgDestroyImage(bottomImage); + + // (4) Left (scaled via verticalTileRule) + VGImage leftImage = vgChildImage(image, leftSourceRect.x(), leftSourceRect.y(), leftSourceRect.width(), leftSourceRect.height()); + scaledHeight = (leftTargetRect.height() / subSourceRect.height()) / leftSourceRect.height(); + QSGOpenVGHelpers::qDrawTiled(leftImage, leftSourceRect.size().toSize(), leftTargetRect, QPointF(0.0, 0.0), 1, scaledHeight); + + vgDestroyImage(leftImage); + + // (6) Right (scaled via verticalTileRule) + VGImage rightImage = vgChildImage(image, rightSourceRect.x(), rightSourceRect.y(), rightSourceRect.width(), rightSourceRect.height()); + scaledHeight = (rightTargetRect.height() / subSourceRect.height()) / rightSourceRect.height(); + + QSGOpenVGHelpers::qDrawTiled(rightImage, rightSourceRect.size().toSize(), rightTargetRect, QPointF(0, 0), 1, scaledHeight); + + vgDestroyImage(rightImage); + + // (5) Center (saled via verticalTileRule and horizontalTileRule) + VGImage centerImage = vgChildImage(image, centerSourceRect.x(), centerSourceRect.y(), centerSourceRect.width(), centerSourceRect.height()); + + scaledWidth = (innerTargetRect.width() / subSourceRect.width()) / centerSourceRect.width(); + scaledHeight = (innerTargetRect.height() / subSourceRect.height()) / centerSourceRect.height(); + + QSGOpenVGHelpers::qDrawTiled(centerImage, centerSourceRect.size().toSize(), innerTargetRect, QPointF(0, 0), scaledWidth, scaledHeight); + + vgDestroyImage(centerImage); +} + +void qDrawSubImage(VGImage image, const QRectF &sourceRect, const QPointF &destOffset) +{ + // Check for valid source size + if (sourceRect.width() <= 0 || sourceRect.height() <= 0) + return; + + // Save the current image transform matrix + vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE); + QVector<float> originalMatrix(9); + vgGetMatrix(originalMatrix.data()); + + // Get the child Image + VGImage childRectImage = vgChildImage(image, sourceRect.x(), sourceRect.y(), sourceRect.width(), sourceRect.height()); + vgTranslate(destOffset.x(), destOffset.y()); + vgDrawImage(childRectImage); + vgDestroyImage(childRectImage); + + // Pop Matrix + vgLoadMatrix(originalMatrix.constData()); +} + +const QVector<VGfloat> qColorToVGColor(const QColor &color, float opacity) +{ + QVector<VGfloat> vgColor(4); + vgColor[0] = color.redF(); + vgColor[1] = color.greenF(); + vgColor[2] = color.blueF(); + vgColor[3] = color.alphaF() * opacity; + return vgColor; +} + +VGImageFormat qImageFormatToVGImageFormat(QImage::Format format) +{ + VGImageFormat vgFormat; + + switch (format) { + case QImage::Format_Mono: + case QImage::Format_MonoLSB: + vgFormat = VG_BW_1; + break; + case QImage::Format_RGB32: + vgFormat = VG_sXRGB_8888; + break; + case QImage::Format_ARGB32: + vgFormat = VG_sARGB_8888; + break; + case QImage::Format_ARGB32_Premultiplied: + vgFormat = VG_sARGB_8888_PRE; + break; + case QImage::Format_RGB16: + vgFormat = VG_sRGB_565; + break; + case QImage::Format_RGBX8888: + vgFormat = VG_sRGBX_8888; + break; + case QImage::Format_RGBA8888: + vgFormat = VG_sRGBA_8888; + break; + case QImage::Format_RGBA8888_Premultiplied: + vgFormat = VG_sRGBA_8888_PRE; + break; + case QImage::Format_Alpha8: + vgFormat = VG_A_8; + break; + case QImage::Format_Grayscale8: + vgFormat = VG_sL_8; + break; + default: + //Invalid + vgFormat = (VGImageFormat)-1; + break; + } + + return vgFormat; +} + +QImage::Format qVGImageFormatToQImageFormat(VGImageFormat format) +{ + QImage::Format qImageFormat; + + switch (format) { + case VG_BW_1: + qImageFormat = QImage::Format_Mono; + break; + case VG_sXRGB_8888: + qImageFormat = QImage::Format_RGB32; + break; + case VG_sARGB_8888: + qImageFormat = QImage::Format_ARGB32; + break; + case VG_sARGB_8888_PRE: + qImageFormat = QImage::Format_ARGB32_Premultiplied; + break; + case VG_sRGB_565: + qImageFormat = QImage::Format_RGB16; + break; + case VG_sRGBX_8888: + qImageFormat = QImage::Format_RGBX8888; + break; + case VG_sRGBA_8888: + qImageFormat = QImage::Format_RGBA8888; + break; + case VG_sRGBA_8888_PRE: + qImageFormat = QImage::Format_RGBA8888_Premultiplied; + break; + case VG_A_8: + qImageFormat = QImage::Format_Alpha8; + break; + case VG_sL_8: + qImageFormat = QImage::Format_Grayscale8; + default: + qImageFormat = QImage::Format_ARGB32; + break; + } + + return qImageFormat; +} + +} // end namespace QSGOpenVGHelpers + +QT_END_NAMESPACE diff --git a/src/plugins/scenegraph/openvg/qsgopenvghelpers.h b/src/plugins/scenegraph/openvg/qsgopenvghelpers.h new file mode 100644 index 0000000000..ee8ff73ca8 --- /dev/null +++ b/src/plugins/scenegraph/openvg/qsgopenvghelpers.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGOPENVGHELPERS_H +#define QSGOPENVGHELPERS_H + +#include <QtGui/QPainterPath> +#include <QtGui/QColor> +#include <QtGui/QImage> +#include <VG/openvg.h> + +QT_BEGIN_NAMESPACE + +namespace QSGOpenVGHelpers { + +VGPath qPainterPathToVGPath(const QPainterPath &path); +void qDrawTiled(VGImage image, const QSize imageSize, const QRectF &targetRect, const QPointF offset, float scaleX, float scaleY); +void qDrawBorderImage(VGImage image, const QSizeF &textureSize, const QRectF &targetRect, const QRectF &innerTargetRect, const QRectF &subSourceRect); +void qDrawSubImage(VGImage image, const QRectF &sourceRect, const QPointF &destOffset); +const QVector<VGfloat> qColorToVGColor(const QColor &color, float opacity = 1.0f); +VGImageFormat qImageFormatToVGImageFormat(QImage::Format format); +QImage::Format qVGImageFormatToQImageFormat(VGImageFormat format); + +}; + +QT_END_NAMESPACE + +#endif // QSGOPENVGHELPERS_H diff --git a/src/plugins/scenegraph/openvg/qsgopenvginternalimagenode.cpp b/src/plugins/scenegraph/openvg/qsgopenvginternalimagenode.cpp new file mode 100644 index 0000000000..3dd1f9133c --- /dev/null +++ b/src/plugins/scenegraph/openvg/qsgopenvginternalimagenode.cpp @@ -0,0 +1,239 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgopenvginternalimagenode.h" +#include "qsgopenvghelpers.h" + +#include <VG/openvg.h> + +QT_BEGIN_NAMESPACE + +QSGOpenVGInternalImageNode::QSGOpenVGInternalImageNode() +{ + // Set Dummy material and geometry to avoid asserts + setMaterial((QSGMaterial*)1); + setGeometry((QSGGeometry*)1); +} + +QSGOpenVGInternalImageNode::~QSGOpenVGInternalImageNode() +{ + if (m_subSourceRectImage != 0) + vgDestroyImage(m_subSourceRectImage); +} + +void QSGOpenVGInternalImageNode::render() +{ + if (!m_texture) { + return; + } + + // Set Draw Mode + if (opacity() < 1.0) { + //Transparent + vgSetPaint(opacityPaint(), VG_FILL_PATH); + vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_MULTIPLY); + } else { + vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL); + } + + // Set Transform + vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE); + vgLoadMatrix(transform().constData()); + + VGImage image = static_cast<VGImage>(m_texture->textureId()); + QSize textureSize = m_texture->textureSize(); + + if (image == VG_INVALID_HANDLE || !textureSize.isValid()) + return; + + + // If Mirrored + if (m_mirror) { + vgTranslate(m_targetRect.width(), 0.0f); + vgScale(-1.0, 1.0); + } + + if (m_smooth) + vgSeti(VG_IMAGE_QUALITY, VG_IMAGE_QUALITY_BETTER); + else + vgSeti(VG_IMAGE_QUALITY, VG_IMAGE_QUALITY_NONANTIALIASED); + + + if (m_innerTargetRect != m_targetRect) { + // border image + QSGOpenVGHelpers::qDrawBorderImage(image, textureSize, m_targetRect, m_innerTargetRect, m_subSourceRect); + } else if (m_tileHorizontal || m_tileVertical) { + // Tilled Image + + float sx = m_targetRect.width() / (m_subSourceRect.width() * textureSize.width()); + float sy = m_targetRect.height() / (m_subSourceRect.height() * textureSize.height()); + QPointF offset(m_subSourceRect.left() * textureSize.width(), m_subSourceRect.top() * textureSize.height()); + + QSGOpenVGHelpers::qDrawTiled(image, textureSize, m_targetRect, offset, sx, sy); + + } else { + // Regular BLIT + + QRectF sr(m_subSourceRect.left() * textureSize.width(), m_subSourceRect.top() * textureSize.height(), + m_subSourceRect.width() * textureSize.width(), m_subSourceRect.height() * textureSize.height()); + + if (m_subSourceRectImageDirty) { + if (m_subSourceRectImage != 0) + vgDestroyImage(m_subSourceRectImage); + m_subSourceRectImage = vgChildImage(image, sr.x(), sr.y(), sr.width(), sr.height()); + m_subSourceRectImageDirty = false; + } + + // If the the source rect is the same as the target rect + if (sr == m_targetRect) { + vgDrawImage(image); + } else { + // Scale + float scaleX = m_targetRect.width() / sr.width(); + float scaleY = m_targetRect.height() / sr.height(); + vgTranslate(m_targetRect.x(), m_targetRect.y()); + vgScale(scaleX, scaleY); + vgDrawImage(m_subSourceRectImage); + } + } +} + +void QSGOpenVGInternalImageNode::setTargetRect(const QRectF &rect) +{ + if (rect == m_targetRect) + return; + m_targetRect = rect; + markDirty(DirtyGeometry); +} + +void QSGOpenVGInternalImageNode::setInnerTargetRect(const QRectF &rect) +{ + if (rect == m_innerTargetRect) + return; + m_innerTargetRect = rect; + markDirty(DirtyGeometry); +} + +void QSGOpenVGInternalImageNode::setInnerSourceRect(const QRectF &rect) +{ + if (rect == m_innerSourceRect) + return; + m_innerSourceRect = rect; + markDirty(DirtyGeometry); +} + +void QSGOpenVGInternalImageNode::setSubSourceRect(const QRectF &rect) +{ + if (rect == m_subSourceRect) + return; + m_subSourceRect = rect; + m_subSourceRectImageDirty = true; + markDirty(DirtyGeometry); +} + +void QSGOpenVGInternalImageNode::setTexture(QSGTexture *texture) +{ + m_texture = texture; + m_subSourceRectImageDirty = true; + markDirty(DirtyMaterial); +} + +void QSGOpenVGInternalImageNode::setMirror(bool mirror) +{ + if (m_mirror != mirror) { + m_mirror = mirror; + markDirty(DirtyMaterial); + } +} + +void QSGOpenVGInternalImageNode::setMipmapFiltering(QSGTexture::Filtering) +{ +} + +void QSGOpenVGInternalImageNode::setFiltering(QSGTexture::Filtering filtering) +{ + bool smooth = (filtering == QSGTexture::Linear); + if (smooth == m_smooth) + return; + + m_smooth = smooth; + markDirty(DirtyMaterial); +} + +void QSGOpenVGInternalImageNode::setHorizontalWrapMode(QSGTexture::WrapMode wrapMode) +{ + bool tileHorizontal = (wrapMode == QSGTexture::Repeat); + if (tileHorizontal == m_tileHorizontal) + return; + + m_tileHorizontal = tileHorizontal; + markDirty(DirtyMaterial); +} + +void QSGOpenVGInternalImageNode::setVerticalWrapMode(QSGTexture::WrapMode wrapMode) +{ + bool tileVertical = (wrapMode == QSGTexture::Repeat); + if (tileVertical == m_tileVertical) + return; + + m_tileVertical = (wrapMode == QSGTexture::Repeat); + markDirty(DirtyMaterial); +} + +void QSGOpenVGInternalImageNode::update() +{ +} + +void QSGOpenVGInternalImageNode::preprocess() +{ + bool doDirty = false; + QSGLayer *t = qobject_cast<QSGLayer *>(m_texture); + if (t) { + doDirty = t->updateTexture(); + markDirty(DirtyGeometry); + } + if (doDirty) + markDirty(DirtyMaterial); +} + +QT_END_NAMESPACE + + + + diff --git a/src/plugins/scenegraph/openvg/qsgopenvginternalimagenode.h b/src/plugins/scenegraph/openvg/qsgopenvginternalimagenode.h new file mode 100644 index 0000000000..2361aa4892 --- /dev/null +++ b/src/plugins/scenegraph/openvg/qsgopenvginternalimagenode.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGOPENVGINTERNALIMAGENODE_H +#define QSGOPENVGINTERNALIMAGENODE_H + +#include <private/qsgadaptationlayer_p.h> +#include "qsgopenvgrenderable.h" + +#include <VG/openvg.h> + +QT_BEGIN_NAMESPACE + +class QSGOpenVGInternalImageNode : public QSGInternalImageNode, public QSGOpenVGRenderable +{ +public: + QSGOpenVGInternalImageNode(); + ~QSGOpenVGInternalImageNode(); + + void render() override; + + void setTargetRect(const QRectF &rect) override; + void setInnerTargetRect(const QRectF &rect) override; + void setInnerSourceRect(const QRectF &rect) override; + void setSubSourceRect(const QRectF &rect) override; + void setTexture(QSGTexture *texture) override; + void setMirror(bool mirror) override; + void setMipmapFiltering(QSGTexture::Filtering filtering) override; + void setFiltering(QSGTexture::Filtering filtering) override; + void setHorizontalWrapMode(QSGTexture::WrapMode wrapMode) override; + void setVerticalWrapMode(QSGTexture::WrapMode wrapMode) override; + void update() override; + + void preprocess() override; + +private: + + QRectF m_targetRect; + QRectF m_innerTargetRect; + QRectF m_innerSourceRect = QRectF(0, 0, 1, 1); + QRectF m_subSourceRect = QRectF(0, 0, 1, 1); + + bool m_mirror = false; + bool m_smooth = true; + bool m_tileHorizontal = false; + bool m_tileVertical = false; + + QSGTexture *m_texture = nullptr; + + VGImage m_subSourceRectImage = 0; + bool m_subSourceRectImageDirty = true; +}; + +QT_END_NAMESPACE + +#endif // QSGOPENVGINTERNALIMAGENODE_H diff --git a/src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.cpp b/src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.cpp new file mode 100644 index 0000000000..be437303bc --- /dev/null +++ b/src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.cpp @@ -0,0 +1,732 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgopenvginternalrectanglenode.h" +#include "qsgopenvghelpers.h" + +#include <VG/vgu.h> + +QSGOpenVGInternalRectangleNode::QSGOpenVGInternalRectangleNode() +{ + // Set Dummy material and geometry to avoid asserts + setMaterial((QSGMaterial*)1); + setGeometry((QSGGeometry*)1); + createVGResources(); +} + +QSGOpenVGInternalRectangleNode::~QSGOpenVGInternalRectangleNode() +{ + destroyVGResources(); +} + + +void QSGOpenVGInternalRectangleNode::setRect(const QRectF &rect) +{ + m_rect = rect; + m_pathDirty = true; +} + +void QSGOpenVGInternalRectangleNode::setColor(const QColor &color) +{ + m_fillColor = color; + m_fillDirty = true; +} + +void QSGOpenVGInternalRectangleNode::setPenColor(const QColor &color) +{ + m_strokeColor = color; + m_strokeDirty = true; +} + +void QSGOpenVGInternalRectangleNode::setPenWidth(qreal width) +{ + m_penWidth = width; + m_strokeDirty = true; + m_pathDirty = true; +} + +//Move first stop by pos relative to seconds +static QGradientStop interpolateStop(const QGradientStop &firstStop, const QGradientStop &secondStop, double newPos) +{ + double distance = secondStop.first - firstStop.first; + double distanceDelta = newPos - firstStop.first; + double modifierValue = distanceDelta / distance; + int redDelta = (secondStop.second.red() - firstStop.second.red()) * modifierValue; + int greenDelta = (secondStop.second.green() - firstStop.second.green()) * modifierValue; + int blueDelta = (secondStop.second.blue() - firstStop.second.blue()) * modifierValue; + int alphaDelta = (secondStop.second.alpha() - firstStop.second.alpha()) * modifierValue; + + QGradientStop newStop; + newStop.first = newPos; + newStop.second = QColor(firstStop.second.red() + redDelta, + firstStop.second.green() + greenDelta, + firstStop.second.blue() + blueDelta, + firstStop.second.alpha() + alphaDelta); + + return newStop; +} + +void QSGOpenVGInternalRectangleNode::setGradientStops(const QGradientStops &stops) +{ + + //normalize stops + bool needsNormalization = false; + for (const QGradientStop &stop : qAsConst(stops)) { + if (stop.first < 0.0 || stop.first > 1.0) { + needsNormalization = true; + continue; + } + } + + if (needsNormalization) { + QGradientStops normalizedStops; + if (stops.count() == 1) { + //If there is only one stop, then the position does not matter + //It is just treated as a color + QGradientStop stop = stops.at(0); + stop.first = 0.0; + normalizedStops.append(stop); + } else { + //Clip stops to only the first below 0.0 and above 1.0 + int below = -1; + int above = -1; + QVector<int> between; + for (int i = 0; i < stops.count(); ++i) { + if (stops.at(i).first < 0.0) { + below = i; + } else if (stops.at(i).first > 1.0) { + above = i; + break; + } else { + between.append(i); + } + } + + //Interpoloate new color values for above and below + if (below != -1 ) { + //If there are more than one stops left, interpolate + if (below + 1 < stops.count()) { + normalizedStops.append(interpolateStop(stops.at(below), stops.at(below + 1), 0.0)); + } else { + QGradientStop singleStop; + singleStop.first = 0.0; + singleStop.second = stops.at(below).second; + normalizedStops.append(singleStop); + } + } + + for (int i = 0; i < between.count(); ++i) + normalizedStops.append(stops.at(between.at(i))); + + if (above != -1) { + //If there stops before above, interpolate + if (above >= 1) { + normalizedStops.append(interpolateStop(stops.at(above), stops.at(above - 1), 1.0)); + } else { + QGradientStop singleStop; + singleStop.first = 1.0; + singleStop.second = stops.at(above).second; + normalizedStops.append(singleStop); + } + } + } + + m_gradientStops = normalizedStops; + + } else { + m_gradientStops = stops; + } + + m_fillDirty = true; +} + +void QSGOpenVGInternalRectangleNode::setRadius(qreal radius) +{ + m_radius = radius; + m_pathDirty = true; +} + +void QSGOpenVGInternalRectangleNode::setAligned(bool aligned) +{ + m_aligned = aligned; +} + +void QSGOpenVGInternalRectangleNode::update() +{ +} + +void QSGOpenVGInternalRectangleNode::render() +{ + // Set Transform + if (transform().isAffine()) { + // Use current transform matrix + vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE); + vgLoadMatrix(transform().constData()); + if (m_offscreenSurface) { + delete m_offscreenSurface; + m_offscreenSurface = nullptr; + } + } else { + vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE); + vgLoadIdentity(); + if (m_radius > 0) { + // Fallback to rendering to an image for rounded rects with perspective transforms + if (m_offscreenSurface == nullptr || m_offscreenSurface->size() != QSize(ceil(m_rect.width()), ceil(m_rect.height()))) { + delete m_offscreenSurface; + m_offscreenSurface = new QOpenVGOffscreenSurface(QSize(ceil(m_rect.width()), ceil(m_rect.height()))); + } + + m_offscreenSurface->makeCurrent(); + } else if (m_offscreenSurface) { + delete m_offscreenSurface; + m_offscreenSurface = nullptr; + } + } + + + // If path is dirty + if (m_pathDirty) { + vgClearPath(m_rectanglePath, VG_PATH_CAPABILITY_APPEND_TO); + vgClearPath(m_borderPath, VG_PATH_CAPABILITY_APPEND_TO); + + if (m_penWidth == 0) { + generateRectanglePath(m_rect, m_radius, m_rectanglePath); + } else { + generateRectangleAndBorderPaths(m_rect, m_penWidth, m_radius, m_rectanglePath, m_borderPath); + } + + m_pathDirty = false; + } + + //If fill is drity + if (m_fillDirty) { + if (m_gradientStops.isEmpty()) { + vgSetParameteri(m_rectanglePaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); + vgSetParameterfv(m_rectanglePaint, VG_PAINT_COLOR, 4, QSGOpenVGHelpers::qColorToVGColor(m_fillColor, opacity()).constData()); + } else { + // Linear Gradient + vgSetParameteri(m_rectanglePaint, VG_PAINT_TYPE, VG_PAINT_TYPE_LINEAR_GRADIENT); + const VGfloat verticalLinearGradient[] = { + 0.0f, + 0.0f, + 0.0f, + static_cast<VGfloat>(m_rect.height()) + }; + vgSetParameterfv(m_rectanglePaint, VG_PAINT_LINEAR_GRADIENT, 4, verticalLinearGradient); + vgSetParameteri(m_rectanglePaint, VG_PAINT_COLOR_RAMP_SPREAD_MODE, VG_COLOR_RAMP_SPREAD_PAD); + vgSetParameteri(m_rectanglePaint, VG_PAINT_COLOR_RAMP_PREMULTIPLIED, false); + + QVector<VGfloat> stops; + for (const QGradientStop &stop : qAsConst(m_gradientStops)) { + // offset + stops.append(stop.first); + // color + stops.append(QSGOpenVGHelpers::qColorToVGColor(stop.second, opacity())); + } + + vgSetParameterfv(m_rectanglePaint, VG_PAINT_COLOR_RAMP_STOPS, stops.length(), stops.constData()); + } + + m_fillDirty = false; + } + + //If stroke is dirty + if (m_strokeDirty) { + vgSetParameteri(m_borderPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); + vgSetParameterfv(m_borderPaint, VG_PAINT_COLOR, 4, QSGOpenVGHelpers::qColorToVGColor(m_strokeColor, opacity()).constData()); + + m_strokeDirty = false; + } + + //Draw + if (m_penWidth > 0) { + vgSetPaint(m_borderPaint, VG_FILL_PATH); + vgDrawPath(m_borderPath, VG_FILL_PATH); + vgSetPaint(m_rectanglePaint, VG_FILL_PATH); + vgDrawPath(m_rectanglePath, VG_FILL_PATH); + } else { + vgSetPaint(m_rectanglePaint, VG_FILL_PATH); + vgDrawPath(m_rectanglePath, VG_FILL_PATH); + } + + if (!transform().isAffine() && m_radius > 0) { + m_offscreenSurface->doneCurrent(); + // Render offscreen surface + vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE); + vgLoadMatrix(transform().constData()); + vgDrawImage(m_offscreenSurface->image()); + } +} + +void QSGOpenVGInternalRectangleNode::setOpacity(float opacity) +{ + if (opacity != QSGOpenVGRenderable::opacity()) { + QSGOpenVGRenderable::setOpacity(opacity); + m_strokeDirty = true; + m_fillDirty = true; + } +} + +void QSGOpenVGInternalRectangleNode::setTransform(const QOpenVGMatrix &transform) +{ + // if there transform matrix is not affine, regenerate the path + if (transform.isAffine()) + m_pathDirty = true; + + QSGOpenVGRenderable::setTransform(transform); +} + +void QSGOpenVGInternalRectangleNode::createVGResources() +{ + m_rectanglePaint = vgCreatePaint(); + m_borderPaint = vgCreatePaint(); + m_rectanglePath = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1, 0, 0, 0, + VG_PATH_CAPABILITY_APPEND_TO); + m_borderPath = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1, 0, 0, 0, + VG_PATH_CAPABILITY_APPEND_TO); +} + +void QSGOpenVGInternalRectangleNode::destroyVGResources() +{ + if (m_offscreenSurface) + delete m_offscreenSurface; + + vgDestroyPaint(m_rectanglePaint); + vgDestroyPaint(m_borderPaint); + vgDestroyPath(m_rectanglePath); + vgDestroyPath(m_borderPath); +} + +void QSGOpenVGInternalRectangleNode::generateRectanglePath(const QRectF &rect, float radius, VGPath path) const +{ + if (radius == 0) { + // Generate a rectangle + if (transform().isAffine()) { + // Create command list + static const VGubyte rectCommands[] = { + VG_MOVE_TO_ABS, + VG_HLINE_TO_REL, + VG_VLINE_TO_REL, + VG_HLINE_TO_REL, + VG_CLOSE_PATH + }; + + // Create command data + QVector<VGfloat> coordinates(5); + coordinates[0] = rect.x(); + coordinates[1] = rect.y(); + coordinates[2] = rect.width(); + coordinates[3] = rect.height(); + coordinates[4] = -rect.width(); + vgAppendPathData(path, 5, rectCommands, coordinates.constData()); + } else { + // Pre-transform path + static const VGubyte rectCommands[] = { + VG_MOVE_TO_ABS, + VG_LINE_TO_ABS, + VG_LINE_TO_ABS, + VG_LINE_TO_ABS, + VG_CLOSE_PATH + }; + + QVector<VGfloat> coordinates(8); + const QPointF topLeft = transform().map(rect.topLeft()); + const QPointF topRight = transform().map(rect.topRight()); + const QPointF bottomLeft = transform().map(rect.bottomLeft()); + const QPointF bottomRight = transform().map(rect.bottomRight()); + coordinates[0] = bottomLeft.x(); + coordinates[1] = bottomLeft.y(); + coordinates[2] = bottomRight.x(); + coordinates[3] = bottomRight.y(); + coordinates[4] = topRight.x(); + coordinates[5] = topRight.y(); + coordinates[6] = topLeft.x(); + coordinates[7] = topLeft.y(); + + vgAppendPathData(path, 5, rectCommands, coordinates.constData()); + } + } else { + // Generate a rounded rectangle + //Radius should never exceeds half of the width or half of the height + float adjustedRadius = qMin((float)qMin(rect.width(), rect.height()) * 0.5f, radius); + + // OpenVG expectes radius to be 2x what we expect + adjustedRadius *= 2; + + // Create command list + static const VGubyte roundedRectCommands[] = { + VG_MOVE_TO_ABS, + VG_HLINE_TO_REL, + VG_SCCWARC_TO_REL, + VG_VLINE_TO_REL, + VG_SCCWARC_TO_REL, + VG_HLINE_TO_REL, + VG_SCCWARC_TO_REL, + VG_VLINE_TO_REL, + VG_SCCWARC_TO_REL, + VG_CLOSE_PATH + }; + + // Create command data + QVector<VGfloat> coordinates(26); + + coordinates[0] = rect.x() + adjustedRadius / 2; + coordinates[1] = rect.y(); + + coordinates[2] = rect.width() - adjustedRadius; + + coordinates[3] = adjustedRadius / 2; + coordinates[4] = adjustedRadius / 2; + coordinates[5] = 0; + coordinates[6] = adjustedRadius / 2; + coordinates[7] = adjustedRadius / 2; + + coordinates[8] = rect.height() - adjustedRadius; + + coordinates[9] = adjustedRadius / 2; + coordinates[10] = adjustedRadius / 2; + coordinates[11] = 0; + coordinates[12] = -adjustedRadius / 2; + coordinates[13] = adjustedRadius / 2; + + coordinates[14] = -(rect.width() - adjustedRadius); + + coordinates[15] = adjustedRadius / 2; + coordinates[16] = adjustedRadius / 2; + coordinates[17] = 0; + coordinates[18] = -adjustedRadius / 2; + coordinates[19] = -adjustedRadius / 2; + + coordinates[20] = -(rect.height() - adjustedRadius); + + coordinates[21] = adjustedRadius / 2; + coordinates[22] = adjustedRadius / 2; + coordinates[23] = 0; + coordinates[24] = adjustedRadius / 2; + coordinates[25] = -adjustedRadius / 2; + + vgAppendPathData(path, 10, roundedRectCommands, coordinates.constData()); + } +} + +void QSGOpenVGInternalRectangleNode::generateBorderPath(const QRectF &rect, float borderWidth, float borderHeight, float radius, VGPath path) const +{ + if (radius == 0) { + // squared frame + if (transform().isAffine()) { + // Create command list + static const VGubyte squaredBorderCommands[] = { + VG_MOVE_TO_ABS, + VG_HLINE_TO_REL, + VG_VLINE_TO_REL, + VG_HLINE_TO_REL, + VG_MOVE_TO_ABS, + VG_VLINE_TO_REL, + VG_HLINE_TO_REL, + VG_VLINE_TO_REL, + VG_CLOSE_PATH + }; + + // Create command data + QVector<VGfloat> coordinates(10); + // Outside Square + coordinates[0] = rect.x(); + coordinates[1] = rect.y(); + coordinates[2] = rect.width(); + coordinates[3] = rect.height(); + coordinates[4] = -rect.width(); + // Inside Square (opposite direction) + coordinates[5] = rect.x() + borderWidth; + coordinates[6] = rect.y() + borderHeight; + coordinates[7] = rect.height() - (borderHeight * 2); + coordinates[8] = rect.width() - (borderWidth * 2); + coordinates[9] = -(rect.height() - (borderHeight * 2)); + + vgAppendPathData(path, 9, squaredBorderCommands, coordinates.constData()); + } else { + // persepective transform + static const VGubyte squaredBorderCommands[] = { + VG_MOVE_TO_ABS, + VG_LINE_TO_ABS, + VG_LINE_TO_ABS, + VG_LINE_TO_ABS, + VG_MOVE_TO_ABS, + VG_LINE_TO_ABS, + VG_LINE_TO_ABS, + VG_LINE_TO_ABS, + VG_CLOSE_PATH + }; + + QVector<VGfloat> coordinates(16); + QRectF insideRect = rect.marginsRemoved(QMarginsF(borderWidth, borderHeight, borderWidth, borderHeight)); + QPointF outsideBottomLeft = transform().map(rect.bottomLeft()); + QPointF outsideBottomRight = transform().map(rect.bottomRight()); + QPointF outsideTopRight = transform().map(rect.topRight()); + QPointF outsideTopLeft = transform().map(rect.topLeft()); + QPointF insideBottomLeft = transform().map(insideRect.bottomLeft()); + QPointF insideTopLeft = transform().map(insideRect.topLeft()); + QPointF insideTopRight = transform().map(insideRect.topRight()); + QPointF insideBottomRight = transform().map(insideRect.bottomRight()); + + // Outside + coordinates[0] = outsideBottomLeft.x(); + coordinates[1] = outsideBottomLeft.y(); + coordinates[2] = outsideBottomRight.x(); + coordinates[3] = outsideBottomRight.y(); + coordinates[4] = outsideTopRight.x(); + coordinates[5] = outsideTopRight.y(); + coordinates[6] = outsideTopLeft.x(); + coordinates[7] = outsideTopLeft.y(); + // Inside + coordinates[8] = insideBottomLeft.x(); + coordinates[9] = insideBottomLeft.y(); + coordinates[10] = insideTopLeft.x(); + coordinates[11] = insideTopLeft.y(); + coordinates[12] = insideTopRight.x(); + coordinates[13] = insideTopRight.y(); + coordinates[14] = insideBottomRight.x(); + coordinates[15] = insideBottomRight.y(); + + vgAppendPathData(path, 9, squaredBorderCommands, coordinates.constData()); + } + } else if (radius < qMax(borderWidth, borderHeight)){ + // rounded outside, squared inside + // Create command list + static const VGubyte roundedRectCommands[] = { + VG_MOVE_TO_ABS, + VG_HLINE_TO_REL, + VG_SCCWARC_TO_REL, + VG_VLINE_TO_REL, + VG_SCCWARC_TO_REL, + VG_HLINE_TO_REL, + VG_SCCWARC_TO_REL, + VG_VLINE_TO_REL, + VG_SCCWARC_TO_REL, + VG_MOVE_TO_ABS, + VG_VLINE_TO_REL, + VG_HLINE_TO_REL, + VG_VLINE_TO_REL, + VG_CLOSE_PATH + }; + + // Ajust for OpenVG's usage or radius + float adjustedRadius = radius * 2; + + // Create command data + QVector<VGfloat> coordinates(31); + // Outside Rounded Rect + coordinates[0] = rect.x() + adjustedRadius / 2; + coordinates[1] = rect.y(); + + coordinates[2] = rect.width() - adjustedRadius; + + coordinates[3] = adjustedRadius / 2; + coordinates[4] = adjustedRadius / 2; + coordinates[5] = 0; + coordinates[6] = adjustedRadius / 2; + coordinates[7] = adjustedRadius / 2; + + coordinates[8] = rect.height() - adjustedRadius; + + coordinates[9] = adjustedRadius / 2; + coordinates[10] = adjustedRadius / 2; + coordinates[11] = 0; + coordinates[12] = -adjustedRadius / 2; + coordinates[13] = adjustedRadius / 2; + + coordinates[14] = -(rect.width() - adjustedRadius); + + coordinates[15] = adjustedRadius / 2; + coordinates[16] = adjustedRadius / 2; + coordinates[17] = 0; + coordinates[18] = -adjustedRadius / 2; + coordinates[19] = -adjustedRadius / 2; + + coordinates[20] = -(rect.height() - adjustedRadius); + + coordinates[21] = adjustedRadius / 2; + coordinates[22] = adjustedRadius / 2; + coordinates[23] = 0; + coordinates[24] = adjustedRadius / 2; + coordinates[25] = -adjustedRadius / 2; + + // Inside Square (opposite direction) + coordinates[26] = rect.x() + borderWidth; + coordinates[27] = rect.y() + borderHeight; + coordinates[28] = rect.height() - (borderHeight * 2); + coordinates[29] = rect.width() - (borderWidth * 2); + coordinates[30] = -(rect.height() - (borderHeight * 2)); + + vgAppendPathData(path, 14, roundedRectCommands, coordinates.constData()); + } else { + // rounded outside, rounded inside + + static const VGubyte roundedBorderCommands[] = { + // Outer + VG_MOVE_TO_ABS, + VG_HLINE_TO_REL, + VG_SCCWARC_TO_REL, + VG_VLINE_TO_REL, + VG_SCCWARC_TO_REL, + VG_HLINE_TO_REL, + VG_SCCWARC_TO_REL, + VG_VLINE_TO_REL, + VG_SCCWARC_TO_REL, + // Inner + VG_MOVE_TO_ABS, + VG_SCWARC_TO_REL, + VG_VLINE_TO_REL, + VG_SCWARC_TO_REL, + VG_HLINE_TO_REL, + VG_SCWARC_TO_REL, + VG_VLINE_TO_REL, + VG_SCWARC_TO_REL, + VG_HLINE_TO_REL, + VG_CLOSE_PATH + }; + + // Adjust for OpenVG's usage or radius + float adjustedRadius = radius * 2; + float adjustedInnerRadius = (radius - qMax(borderWidth, borderHeight)) * 2; + + // Create command data + QVector<VGfloat> coordinates(52); + + // Outer + coordinates[0] = rect.x() + adjustedRadius / 2; + coordinates[1] = rect.y(); + + coordinates[2] = rect.width() - adjustedRadius; + + coordinates[3] = adjustedRadius / 2; + coordinates[4] = adjustedRadius / 2; + coordinates[5] = 0; + coordinates[6] = adjustedRadius / 2; + coordinates[7] = adjustedRadius / 2; + + coordinates[8] = rect.height() - adjustedRadius; + + coordinates[9] = adjustedRadius / 2; + coordinates[10] = adjustedRadius / 2; + coordinates[11] = 0; + coordinates[12] = -adjustedRadius / 2; + coordinates[13] = adjustedRadius / 2; + + coordinates[14] = -(rect.width() - adjustedRadius); + + coordinates[15] = adjustedRadius / 2; + coordinates[16] = adjustedRadius / 2; + coordinates[17] = 0; + coordinates[18] = -adjustedRadius / 2; + coordinates[19] = -adjustedRadius / 2; + + coordinates[20] = -(rect.height() - adjustedRadius); + + coordinates[21] = adjustedRadius / 2; + coordinates[22] = adjustedRadius / 2; + coordinates[23] = 0; + coordinates[24] = adjustedRadius / 2; + coordinates[25] = -adjustedRadius / 2; + + // Inner + coordinates[26] = rect.width() - (adjustedInnerRadius / 2 + borderWidth); + coordinates[27] = rect.height() - borderHeight; + + coordinates[28] = adjustedInnerRadius / 2; + coordinates[29] = adjustedInnerRadius / 2; + coordinates[30] = 0; + coordinates[31] = adjustedInnerRadius / 2; + coordinates[32] = -adjustedInnerRadius / 2; + + coordinates[33] = -((rect.height() - borderHeight * 2) - adjustedInnerRadius); + + coordinates[34] = adjustedInnerRadius / 2; + coordinates[35] = adjustedInnerRadius / 2; + coordinates[36] = 0; + coordinates[37] = -adjustedInnerRadius / 2; + coordinates[38] = -adjustedInnerRadius / 2; + + coordinates[39] = -((rect.width() - borderWidth * 2) - adjustedInnerRadius); + + coordinates[40] = adjustedInnerRadius / 2; + coordinates[41] = adjustedInnerRadius / 2; + coordinates[42] = 0; + coordinates[43] = -adjustedInnerRadius / 2; + coordinates[44] = adjustedInnerRadius / 2; + + coordinates[45] = (rect.height() - borderHeight * 2) - adjustedInnerRadius; + + coordinates[46] = adjustedInnerRadius / 2; + coordinates[47] = adjustedInnerRadius / 2; + coordinates[48] = 0; + coordinates[49] = adjustedInnerRadius / 2; + coordinates[50] = adjustedInnerRadius / 2; + + coordinates[51] = (rect.width() - borderWidth * 2) - adjustedInnerRadius; + + vgAppendPathData(path, 19, roundedBorderCommands, coordinates.constData()); + } +} + +void QSGOpenVGInternalRectangleNode::generateRectangleAndBorderPaths(const QRectF &rect, float penWidth, float radius, VGPath inside, VGPath outside) const +{ + //Borders can not be more than half the height/width of a rect + float borderWidth = qMin(penWidth, (float)rect.width() * 0.5f); + float borderHeight = qMin(penWidth, (float)rect.height() * 0.5f); + + //Radius should never exceeds half of the width or half of the height + float adjustedRadius = qMin((float)qMin(rect.width(), rect.height()) * 0.5f, radius); + + QRectF innerRect = rect; + innerRect.adjust(borderWidth, borderHeight, -borderWidth, -borderHeight); + + if (radius == 0) { + // Regular rect with border + generateRectanglePath(innerRect, 0, inside); + generateBorderPath(rect, borderWidth, borderHeight, 0, outside); + } else { + // Rounded Rect with border + float innerRadius = radius - qMax(borderWidth, borderHeight); + if (innerRadius < 0) + innerRadius = 0.0f; + + generateRectanglePath(innerRect, innerRadius, inside); + generateBorderPath(rect, borderWidth, borderHeight, adjustedRadius, outside); + } +} diff --git a/src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.h b/src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.h new file mode 100644 index 0000000000..e8d25c94f8 --- /dev/null +++ b/src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGOPENVGINTERNALRECTANGLENODE_H +#define QSGOPENVGINTERNALRECTANGLENODE_H + +#include <private/qsgadaptationlayer_p.h> +#include "qsgopenvgrenderable.h" +#include "qopenvgoffscreensurface.h" + +#include <VG/openvg.h> + +QT_BEGIN_NAMESPACE + +class QSGOpenVGInternalRectangleNode : public QSGInternalRectangleNode, public QSGOpenVGRenderable +{ +public: + QSGOpenVGInternalRectangleNode(); + ~QSGOpenVGInternalRectangleNode(); + + void setRect(const QRectF &rect) override; + void setColor(const QColor &color) override; + void setPenColor(const QColor &color) override; + void setPenWidth(qreal width) override; + void setGradientStops(const QGradientStops &stops) override; + void setRadius(qreal radius) override; + void setAligned(bool aligned) override; + void update() override; + + void render() override; + void setOpacity(float opacity) override; + void setTransform(const QOpenVGMatrix &transform) override; + +private: + void createVGResources(); + void destroyVGResources(); + + void generateRectanglePath(const QRectF &rect, float radius, VGPath path) const; + void generateRectangleAndBorderPaths(const QRectF &rect, float penWidth, float radius, VGPath inside, VGPath outside) const; + void generateBorderPath(const QRectF &rect, float borderWidth, float borderHeight, float radius, VGPath path) const; + + bool m_pathDirty = true; + bool m_fillDirty = true; + bool m_strokeDirty = true; + + QRectF m_rect; + QColor m_fillColor; + QColor m_strokeColor; + qreal m_penWidth = 0.0; + qreal m_radius = 0.0; + bool m_aligned = false; + QGradientStops m_gradientStops; + + VGPath m_rectanglePath; + VGPath m_borderPath; + VGPaint m_rectanglePaint; + VGPaint m_borderPaint; + + QOpenVGOffscreenSurface *m_offscreenSurface = nullptr; +}; + +QT_END_NAMESPACE + +#endif // QSGOPENVGINTERNALRECTANGLENODE_H diff --git a/src/plugins/scenegraph/openvg/qsgopenvglayer.cpp b/src/plugins/scenegraph/openvg/qsgopenvglayer.cpp new file mode 100644 index 0000000000..047539d431 --- /dev/null +++ b/src/plugins/scenegraph/openvg/qsgopenvglayer.cpp @@ -0,0 +1,315 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgopenvglayer.h" +#include "qsgopenvgrenderer_p.h" +#include "qsgopenvgcontext_p.h" + +QT_BEGIN_NAMESPACE + +QSGOpenVGLayer::QSGOpenVGLayer(QSGRenderContext *renderContext) + : m_item(nullptr) + , m_renderer(nullptr) + , m_device_pixel_ratio(1) + , m_mirrorHorizontal(false) + , m_mirrorVertical(false) + , m_live(true) + , m_grab(true) + , m_recursive(false) + , m_dirtyTexture(true) + , m_offscreenSurface(nullptr) + , m_secondaryOffscreenSurface(nullptr) +{ + m_context = static_cast<QSGOpenVGRenderContext*>(renderContext); +} + +QSGOpenVGLayer::~QSGOpenVGLayer() +{ + invalidated(); +} + +int QSGOpenVGLayer::textureId() const +{ + if (m_offscreenSurface) + return static_cast<int>(m_offscreenSurface->image()); + else + return 0; +} + +QSize QSGOpenVGLayer::textureSize() const +{ + if (m_offscreenSurface) { + return m_offscreenSurface->size(); + } + + return QSize(); +} + +bool QSGOpenVGLayer::hasAlphaChannel() const +{ + return true; +} + +bool QSGOpenVGLayer::hasMipmaps() const +{ + return false; +} + +void QSGOpenVGLayer::bind() +{ +} + +bool QSGOpenVGLayer::updateTexture() +{ + bool doGrab = (m_live || m_grab) && m_dirtyTexture; + if (doGrab) + grab(); + if (m_grab) + emit scheduledUpdateCompleted(); + m_grab = false; + return doGrab; +} + +void QSGOpenVGLayer::setItem(QSGNode *item) +{ + if (item == m_item) + return; + m_item = item; + + if (m_live && !m_item) { + delete m_offscreenSurface; + delete m_secondaryOffscreenSurface; + m_offscreenSurface = nullptr; + m_secondaryOffscreenSurface = nullptr; + } + + markDirtyTexture(); +} + +void QSGOpenVGLayer::setRect(const QRectF &rect) +{ + if (rect == m_rect) + return; + m_rect = rect; + markDirtyTexture(); +} + +void QSGOpenVGLayer::setSize(const QSize &size) +{ + if (size == m_size) + return; + m_size = size; + + if (m_live && m_size.isNull()) { + delete m_offscreenSurface; + delete m_secondaryOffscreenSurface; + m_offscreenSurface = nullptr; + m_secondaryOffscreenSurface = nullptr; + } + + markDirtyTexture(); +} + +void QSGOpenVGLayer::scheduleUpdate() +{ + if (m_grab) + return; + m_grab = true; + if (m_dirtyTexture) { + emit updateRequested(); + } +} + +QImage QSGOpenVGLayer::toImage() const +{ + return m_offscreenSurface->readbackQImage(); +} + +void QSGOpenVGLayer::setLive(bool live) +{ + if (live == m_live) + return; + m_live = live; + + if (m_live && (!m_item || m_size.isNull())) { + delete m_offscreenSurface; + delete m_secondaryOffscreenSurface; + m_offscreenSurface = nullptr; + m_secondaryOffscreenSurface = nullptr; + } + + markDirtyTexture(); +} + +void QSGOpenVGLayer::setRecursive(bool recursive) +{ + m_recursive = recursive; +} + +void QSGOpenVGLayer::setFormat(uint format) +{ + Q_UNUSED(format) +} + +void QSGOpenVGLayer::setHasMipmaps(bool mipmap) +{ + Q_UNUSED(mipmap) +} + +void QSGOpenVGLayer::setDevicePixelRatio(qreal ratio) +{ + m_device_pixel_ratio = ratio; +} + +void QSGOpenVGLayer::setMirrorHorizontal(bool mirror) +{ + if (m_mirrorHorizontal == mirror) + return; + m_mirrorHorizontal = mirror; + markDirtyTexture(); +} + +void QSGOpenVGLayer::setMirrorVertical(bool mirror) +{ + if (m_mirrorVertical == mirror) + return; + m_mirrorVertical = mirror; + markDirtyTexture(); +} + +void QSGOpenVGLayer::markDirtyTexture() +{ + m_dirtyTexture = true; + if (m_live || m_grab) { + emit updateRequested(); + } +} + +void QSGOpenVGLayer::invalidated() +{ + delete m_offscreenSurface; + delete m_secondaryOffscreenSurface; + delete m_renderer; + m_renderer = nullptr; + m_offscreenSurface = nullptr; + m_secondaryOffscreenSurface = nullptr; +} + +void QSGOpenVGLayer::grab() +{ + if (!m_item || m_size.isNull()) { + delete m_offscreenSurface; + delete m_secondaryOffscreenSurface; + m_offscreenSurface = nullptr; + m_secondaryOffscreenSurface = nullptr; + m_dirtyTexture = false; + return; + } + QSGNode *root = m_item; + while (root->firstChild() && root->type() != QSGNode::RootNodeType) + root = root->firstChild(); + if (root->type() != QSGNode::RootNodeType) + return; + + if (!m_renderer) { + m_renderer = new QSGOpenVGRenderer(m_context); + connect(m_renderer, SIGNAL(sceneGraphChanged()), this, SLOT(markDirtyTexture())); + } + m_renderer->setDevicePixelRatio(m_device_pixel_ratio); + m_renderer->setRootNode(static_cast<QSGRootNode *>(root)); + + bool deleteOffscreenSurfaceLater = false; + if (m_offscreenSurface == nullptr || m_offscreenSurface->size() != m_size ) { + if (m_recursive) { + deleteOffscreenSurfaceLater = true; + delete m_secondaryOffscreenSurface; + m_secondaryOffscreenSurface = new QOpenVGOffscreenSurface(m_size); + } else { + delete m_offscreenSurface; + delete m_secondaryOffscreenSurface; + m_offscreenSurface = new QOpenVGOffscreenSurface(m_size); + m_secondaryOffscreenSurface = nullptr; + } + } + + if (m_recursive && !m_secondaryOffscreenSurface) + m_secondaryOffscreenSurface = new QOpenVGOffscreenSurface(m_size); + + // Render texture. + root->markDirty(QSGNode::DirtyForceUpdate); // Force matrix, clip and opacity update. + m_renderer->nodeChanged(root, QSGNode::DirtyForceUpdate); // Force render list update. + + m_dirtyTexture = false; + + m_renderer->setDeviceRect(m_size); + m_renderer->setViewportRect(m_size); + QRect mirrored(m_mirrorHorizontal ? m_rect.right() * m_device_pixel_ratio : m_rect.left() * m_device_pixel_ratio, + m_mirrorVertical ? m_rect.top() * m_device_pixel_ratio : m_rect.bottom() * m_device_pixel_ratio, + m_mirrorHorizontal ? -m_rect.width() * m_device_pixel_ratio : m_rect.width() * m_device_pixel_ratio, + m_mirrorVertical ? m_rect.height() * m_device_pixel_ratio : -m_rect.height() * m_device_pixel_ratio); + m_renderer->setProjectionMatrixToRect(mirrored); + m_renderer->setClearColor(Qt::transparent); + + + if (m_recursive) + m_secondaryOffscreenSurface->makeCurrent(); + else + m_offscreenSurface->makeCurrent(); + + m_renderer->renderScene(); + + // Make the previous surface and context active again + if (m_recursive) { + if (deleteOffscreenSurfaceLater) { + delete m_offscreenSurface; + m_offscreenSurface = new QOpenVGOffscreenSurface(m_size); + } + m_secondaryOffscreenSurface->doneCurrent(); + qSwap(m_offscreenSurface, m_secondaryOffscreenSurface); + } else { + m_offscreenSurface->doneCurrent(); + } + + root->markDirty(QSGNode::DirtyForceUpdate); // Force matrix, clip, opacity and render list update. + + if (m_recursive) + markDirtyTexture(); // Continuously update if 'live' and 'recursive'. +} + +QT_END_NAMESPACE diff --git a/src/plugins/scenegraph/openvg/qsgopenvglayer.h b/src/plugins/scenegraph/openvg/qsgopenvglayer.h new file mode 100644 index 0000000000..2af0bfb40f --- /dev/null +++ b/src/plugins/scenegraph/openvg/qsgopenvglayer.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGOPENVGLAYER_H +#define QSGOPENVGLAYER_H + +#include <private/qsgadaptationlayer_p.h> +#include <private/qsgcontext_p.h> + +#include "qopenvgcontext_p.h" +#include "qopenvgoffscreensurface.h" + +QT_BEGIN_NAMESPACE + +class QSGOpenVGRenderer; +class QSGOpenVGRenderContext; + +class QSGOpenVGLayer : public QSGLayer +{ +public: + QSGOpenVGLayer(QSGRenderContext *renderContext); + ~QSGOpenVGLayer(); + + // QSGTexture interface +public: + int textureId() const override; + QSize textureSize() const override; + bool hasAlphaChannel() const override; + bool hasMipmaps() const override; + void bind() override; + + // QSGDynamicTexture interface +public: + bool updateTexture() override; + + // QSGLayer interface +public: + void setItem(QSGNode *item) override; + void setRect(const QRectF &rect) override; + void setSize(const QSize &size) override; + void scheduleUpdate() override; + QImage toImage() const override; + void setLive(bool live) override; + void setRecursive(bool recursive) override; + void setFormat(uint format) override; + void setHasMipmaps(bool mipmap) override; + void setDevicePixelRatio(qreal ratio) override; + void setMirrorHorizontal(bool mirror) override; + void setMirrorVertical(bool mirror) override; + +public slots: + void markDirtyTexture() override; + void invalidated() override; + +private: + void grab(); + + QSGNode *m_item; + QSGOpenVGRenderContext *m_context; + QSGOpenVGRenderer *m_renderer; + QRectF m_rect; + QSize m_size; + qreal m_device_pixel_ratio; + bool m_mirrorHorizontal; + bool m_mirrorVertical; + bool m_live; + bool m_grab; + bool m_recursive; + bool m_dirtyTexture; + + QOpenVGOffscreenSurface *m_offscreenSurface; + QOpenVGOffscreenSurface *m_secondaryOffscreenSurface; +}; + +QT_END_NAMESPACE + +#endif // QSGOPENVGLAYER_H diff --git a/src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.cpp b/src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.cpp new file mode 100644 index 0000000000..8aa179f705 --- /dev/null +++ b/src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.cpp @@ -0,0 +1,275 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgopenvgnodevisitor.h" +#include "qsgopenvginternalrectanglenode.h" +#include "qsgopenvginternalimagenode.h" +#include "qsgopenvgpublicnodes.h" +#include "qsgopenvgglyphnode_p.h" +#include "qsgopenvgpainternode.h" +#include "qsgopenvgspritenode.h" +#include "qsgopenvgrenderable.h" + +#include "qopenvgcontext_p.h" + +#include <QtQuick/qsgsimplerectnode.h> +#include <QtQuick/qsgsimpletexturenode.h> +#include <QtQuick/qsgrendernode.h> + +QT_BEGIN_NAMESPACE + +QSGOpenVGNodeVisitor::QSGOpenVGNodeVisitor() +{ + //Store the current matrix state + QVector<VGfloat> matrix(9); + vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE); + vgGetMatrix(matrix.data()); + + m_transformStack.push(QOpenVGMatrix(matrix.constData())); + + // Opacity + m_opacityState.push(1.0f); +} + +bool QSGOpenVGNodeVisitor::visit(QSGTransformNode *node) +{ + const QVector<float> matrixData = { node->matrix().constData()[0], node->matrix().constData()[1], node->matrix().constData()[3], + node->matrix().constData()[4], node->matrix().constData()[5], node->matrix().constData()[7], + node->matrix().constData()[12], node->matrix().constData()[13], node->matrix().constData()[15] }; + const QOpenVGMatrix matrix2d(matrixData.constData()); + + m_transformStack.push(m_transformStack.top() * matrix2d); + return true; +} + +void QSGOpenVGNodeVisitor::endVisit(QSGTransformNode *) +{ + m_transformStack.pop(); +} + +bool QSGOpenVGNodeVisitor::visit(QSGClipNode *node) +{ + VGMaskOperation maskOperation = VG_INTERSECT_MASK; + if (m_clipStack.count() == 0) { + vgSeti(VG_MASKING, VG_TRUE); + vgMask(0,VG_FILL_MASK, 0, 0, VG_MAXINT, VG_MAXINT); + } + + // Render clip node geometry to mask + vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE); + vgLoadIdentity(); + VGPath clipPath = generateClipPath(node->clipRect()); + vgRenderToMask(clipPath, VG_FILL_PATH, maskOperation); + + m_clipStack.push(clipPath); + + return true; +} + +void QSGOpenVGNodeVisitor::endVisit(QSGClipNode *) +{ + // Remove clip node geometry from mask + auto clipState = m_clipStack.pop(); + vgDestroyPath(clipState); + + if (m_clipStack.count() == 0) { + vgSeti(VG_MASKING, VG_FALSE); + } else { + // Recreate the mask + vgMask(0,VG_FILL_MASK, 0, 0, VG_MAXINT, VG_MAXINT); + vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE); + vgLoadIdentity(); + for (auto path : qAsConst(m_clipStack)) { + vgRenderToMask(path, VG_FILL_PATH, VG_INTERSECT_MASK); + } + } +} + +bool QSGOpenVGNodeVisitor::visit(QSGGeometryNode *node) +{ + if (QSGSimpleRectNode *rectNode = dynamic_cast<QSGSimpleRectNode *>(node)) { + // TODO: Try and render the QSGSimpleRectNode + Q_UNUSED(rectNode) + return false; + } else if (QSGSimpleTextureNode *tn = dynamic_cast<QSGSimpleTextureNode *>(node)) { + // TODO: Try and render the QSGSimpleTextureNode + Q_UNUSED(tn) + return false; + } else if (QSGOpenVGNinePatchNode *nn = dynamic_cast<QSGOpenVGNinePatchNode *>(node)) { + renderRenderableNode(nn); + } else if (QSGOpenVGRectangleNode *rn = dynamic_cast<QSGOpenVGRectangleNode *>(node)) { + renderRenderableNode(rn); + } else if (QSGOpenVGImageNode *n = dynamic_cast<QSGOpenVGImageNode *>(node)) { + renderRenderableNode(n); + } else { + // We dont know, so skip + return false; + } + + return true; +} + +void QSGOpenVGNodeVisitor::endVisit(QSGGeometryNode *) +{ +} + +bool QSGOpenVGNodeVisitor::visit(QSGOpacityNode *node) +{ + m_opacityState.push(m_opacityState.top() * node->opacity()); + return true; +} + +void QSGOpenVGNodeVisitor::endVisit(QSGOpacityNode *) +{ + m_opacityState.pop(); +} + +bool QSGOpenVGNodeVisitor::visit(QSGInternalImageNode *node) +{ + renderRenderableNode(static_cast<QSGOpenVGInternalImageNode*>(node)); + return true; +} + +void QSGOpenVGNodeVisitor::endVisit(QSGInternalImageNode *) +{ +} + +bool QSGOpenVGNodeVisitor::visit(QSGPainterNode *node) +{ + renderRenderableNode(static_cast<QSGOpenVGPainterNode*>(node)); + return true; +} + +void QSGOpenVGNodeVisitor::endVisit(QSGPainterNode *) +{ +} + +bool QSGOpenVGNodeVisitor::visit(QSGInternalRectangleNode *node) +{ + renderRenderableNode(static_cast<QSGOpenVGInternalRectangleNode*>(node)); + return true; +} + +void QSGOpenVGNodeVisitor::endVisit(QSGInternalRectangleNode *) +{ +} + +bool QSGOpenVGNodeVisitor::visit(QSGGlyphNode *node) +{ + renderRenderableNode(static_cast<QSGOpenVGGlyphNode*>(node)); + return true; +} + +void QSGOpenVGNodeVisitor::endVisit(QSGGlyphNode *) +{ +} + +bool QSGOpenVGNodeVisitor::visit(QSGRootNode *) +{ + return true; +} + +void QSGOpenVGNodeVisitor::endVisit(QSGRootNode *) +{ +} + +bool QSGOpenVGNodeVisitor::visit(QSGSpriteNode *node) +{ + renderRenderableNode(static_cast<QSGOpenVGSpriteNode*>(node)); + return true; +} + +void QSGOpenVGNodeVisitor::endVisit(QSGSpriteNode *) +{ +} + +bool QSGOpenVGNodeVisitor::visit(QSGRenderNode *) +{ + return true; +} + +void QSGOpenVGNodeVisitor::endVisit(QSGRenderNode *) +{ +} + +VGPath QSGOpenVGNodeVisitor::generateClipPath(const QRectF &rect) const +{ + VGPath clipPath = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1, 0, 0, 0, + VG_PATH_CAPABILITY_APPEND_TO); + + // Create command list + static const VGubyte rectCommands[] = { + VG_MOVE_TO_ABS, + VG_LINE_TO_ABS, + VG_LINE_TO_ABS, + VG_LINE_TO_ABS, + VG_CLOSE_PATH + }; + + const QOpenVGMatrix &transform = m_transformStack.top(); + + // Create command data + QVector<VGfloat> coordinates(8); + const QPointF topLeft = transform.map(rect.topLeft()); + const QPointF topRight = transform.map(rect.topRight()); + const QPointF bottomLeft = transform.map(rect.bottomLeft()); + const QPointF bottomRight = transform.map(rect.bottomRight()); + coordinates[0] = bottomLeft.x(); + coordinates[1] = bottomLeft.y(); + coordinates[2] = bottomRight.x(); + coordinates[3] = bottomRight.y(); + coordinates[4] = topRight.x(); + coordinates[5] = topRight.y(); + coordinates[6] = topLeft.x(); + coordinates[7] = topLeft.y(); + + vgAppendPathData(clipPath, 5, rectCommands, coordinates.constData()); + return clipPath; +} + +void QSGOpenVGNodeVisitor::renderRenderableNode(QSGOpenVGRenderable *node) +{ + if (!node) + return; + node->setTransform(m_transformStack.top()); + node->setOpacity(m_opacityState.top()); + node->render(); +} + +QT_END_NAMESPACE diff --git a/src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.h b/src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.h new file mode 100644 index 0000000000..4805d63024 --- /dev/null +++ b/src/plugins/scenegraph/openvg/qsgopenvgnodevisitor.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGOPENVGNODEVISITOR_H +#define QSGOPENVGNODEVISITOR_H + +#include <private/qsgadaptationlayer_p.h> +#include <QtCore/QStack> + +#include "qopenvgmatrix.h" + +#include <VG/openvg.h> + +QT_BEGIN_NAMESPACE + +class QSGOpenVGRenderable; +class QSGOpenVGNodeVisitor : public QSGNodeVisitorEx +{ +public: + QSGOpenVGNodeVisitor(); + + bool visit(QSGTransformNode *) override; + void endVisit(QSGTransformNode *) override; + bool visit(QSGClipNode *) override; + void endVisit(QSGClipNode *) override; + bool visit(QSGGeometryNode *) override; + void endVisit(QSGGeometryNode *) override; + bool visit(QSGOpacityNode *) override; + void endVisit(QSGOpacityNode *) override; + bool visit(QSGInternalImageNode *) override; + void endVisit(QSGInternalImageNode *) override; + bool visit(QSGPainterNode *) override; + void endVisit(QSGPainterNode *) override; + bool visit(QSGInternalRectangleNode *) override; + void endVisit(QSGInternalRectangleNode *) override; + bool visit(QSGGlyphNode *) override; + void endVisit(QSGGlyphNode *) override; + bool visit(QSGRootNode *) override; + void endVisit(QSGRootNode *) override; + bool visit(QSGSpriteNode *) override; + void endVisit(QSGSpriteNode *) override; + bool visit(QSGRenderNode *) override; + void endVisit(QSGRenderNode *) override; + +private: + VGPath generateClipPath(const QRectF &rect) const; + void renderRenderableNode(QSGOpenVGRenderable *node); + + QStack<QOpenVGMatrix> m_transformStack; + QStack<float> m_opacityState; + QStack<VGPath> m_clipStack; +}; + +QT_END_NAMESPACE + +#endif // QSGOPENVGNODEVISITOR_H diff --git a/src/plugins/scenegraph/openvg/qsgopenvgpainternode.cpp b/src/plugins/scenegraph/openvg/qsgopenvgpainternode.cpp new file mode 100644 index 0000000000..fb68ebf2bc --- /dev/null +++ b/src/plugins/scenegraph/openvg/qsgopenvgpainternode.cpp @@ -0,0 +1,253 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgopenvgpainternode.h" +#include "qsgopenvgtexture.h" +#include <qmath.h> + +#include <QtGui/QPainter> + +QT_BEGIN_NAMESPACE + +QSGOpenVGPainterNode::QSGOpenVGPainterNode(QQuickPaintedItem *item) + : m_preferredRenderTarget(QQuickPaintedItem::Image) + , m_item(item) + , m_texture(nullptr) + , m_dirtyContents(false) + , m_opaquePainting(false) + , m_linear_filtering(false) + , m_smoothPainting(false) + , m_fillColor(Qt::transparent) + , m_contentsScale(1.0) + , m_dirtyGeometry(false) +{ + // Set Dummy material and geometry to avoid asserts + setMaterial((QSGMaterial*)1); + setGeometry((QSGGeometry*)1); +} + +QSGOpenVGPainterNode::~QSGOpenVGPainterNode() +{ + delete m_texture; +} + +void QSGOpenVGPainterNode::setPreferredRenderTarget(QQuickPaintedItem::RenderTarget) +{ +} + +void QSGOpenVGPainterNode::setSize(const QSize &size) +{ + if (size == m_size) + return; + + m_size = size; + + m_dirtyGeometry = true; +} + +void QSGOpenVGPainterNode::setDirty(const QRect &dirtyRect) +{ + m_dirtyContents = true; + m_dirtyRect = dirtyRect; + markDirty(DirtyMaterial); +} + +void QSGOpenVGPainterNode::setOpaquePainting(bool opaque) +{ + if (opaque == m_opaquePainting) + return; + + m_opaquePainting = opaque; +} + +void QSGOpenVGPainterNode::setLinearFiltering(bool linearFiltering) +{ + if (linearFiltering == m_linear_filtering) + return; + + m_linear_filtering = linearFiltering; +} + +void QSGOpenVGPainterNode::setMipmapping(bool) +{ + +} + +void QSGOpenVGPainterNode::setSmoothPainting(bool s) +{ + if (s == m_smoothPainting) + return; + + m_smoothPainting = s; +} + +void QSGOpenVGPainterNode::setFillColor(const QColor &c) +{ + if (c == m_fillColor) + return; + + m_fillColor = c; + markDirty(DirtyMaterial); +} + +void QSGOpenVGPainterNode::setContentsScale(qreal s) +{ + if (s == m_contentsScale) + return; + + m_contentsScale = s; + markDirty(DirtyMaterial); +} + +void QSGOpenVGPainterNode::setFastFBOResizing(bool) +{ +} + +void QSGOpenVGPainterNode::setTextureSize(const QSize &size) +{ + if (size == m_textureSize) + return; + + m_textureSize = size; + m_dirtyGeometry = true; +} + +QImage QSGOpenVGPainterNode::toImage() const +{ + return m_image; +} + +void QSGOpenVGPainterNode::update() +{ + if (m_dirtyGeometry) { + if (!m_opaquePainting) + m_image = QImage(m_size, QImage::Format_ARGB32_Premultiplied); + else + m_image = QImage(m_size, QImage::Format_RGB32); + } + + if (m_dirtyContents) + paint(); + + m_dirtyGeometry = false; + m_dirtyContents = false; +} + +QSGTexture *QSGOpenVGPainterNode::texture() const +{ + return m_texture; +} + +void QSGOpenVGPainterNode::render() +{ + if (!m_texture) + return; + + // Set Draw Mode + if (opacity() < 1.0) { + //Transparent + vgSetPaint(opacityPaint(), VG_FILL_PATH); + vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_MULTIPLY); + } else { + vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL); + } + + if (m_linear_filtering) + vgSeti(VG_IMAGE_QUALITY, VG_IMAGE_QUALITY_BETTER); + else + vgSeti(VG_IMAGE_QUALITY, VG_IMAGE_QUALITY_NONANTIALIASED); + + // Set Transform + vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE); + vgLoadMatrix(transform().constData()); + + vgDrawImage(static_cast<VGImage>(m_texture->textureId())); +} + +void QSGOpenVGPainterNode::paint() +{ + QRect dirtyRect = m_dirtyRect.isNull() ? QRect(0, 0, m_size.width(), m_size.height()) : m_dirtyRect; + + QPainter painter; + + painter.begin(&m_image); + if (m_smoothPainting) { + painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform); + } + + QRect clipRect; + + if (m_contentsScale == 1) { + qreal scaleX = m_textureSize.width() / (qreal) m_size.width(); + qreal scaleY = m_textureSize.height() / (qreal) m_size.height(); + painter.scale(scaleX, scaleY); + clipRect = dirtyRect; + } else { + painter.scale(m_contentsScale, m_contentsScale); + + QRect sclip(qFloor(dirtyRect.x()/m_contentsScale), + qFloor(dirtyRect.y()/m_contentsScale), + qCeil(dirtyRect.width()/m_contentsScale+dirtyRect.x()/m_contentsScale-qFloor(dirtyRect.x()/m_contentsScale)), + qCeil(dirtyRect.height()/m_contentsScale+dirtyRect.y()/m_contentsScale-qFloor(dirtyRect.y()/m_contentsScale))); + + clipRect = sclip; + } + + if (!m_dirtyRect.isNull()) + painter.setClipRect(clipRect); + + painter.setCompositionMode(QPainter::CompositionMode_Source); + painter.fillRect(clipRect, m_fillColor); + painter.setCompositionMode(QPainter::CompositionMode_SourceOver); + + m_item->paint(&painter); + painter.end(); + + m_dirtyRect = QRect(); + + if (m_texture) + delete m_texture; + + uint textureFlags = m_opaquePainting ? 0 : QSGRenderContext::CreateTexture_Alpha; + m_texture = new QSGOpenVGTexture(m_image, textureFlags); +} + +QT_END_NAMESPACE + + diff --git a/src/plugins/scenegraph/openvg/qsgopenvgpainternode.h b/src/plugins/scenegraph/openvg/qsgopenvgpainternode.h new file mode 100644 index 0000000000..1fe992115f --- /dev/null +++ b/src/plugins/scenegraph/openvg/qsgopenvgpainternode.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGOPENVGPAINTERNODE_H +#define QSGOPENVGPAINTERNODE_H + +#include <private/qsgadaptationlayer_p.h> +#include <QtQuick/QQuickPaintedItem> +#include "qsgopenvgrenderable.h" + +QT_BEGIN_NAMESPACE + +class QSGOpenVGTexture; + +class QSGOpenVGPainterNode : public QSGPainterNode, public QSGOpenVGRenderable +{ +public: + QSGOpenVGPainterNode(QQuickPaintedItem *item); + ~QSGOpenVGPainterNode(); + + void setPreferredRenderTarget(QQuickPaintedItem::RenderTarget target) override; + void setSize(const QSize &size) override; + void setDirty(const QRect &dirtyRect) override; + void setOpaquePainting(bool opaque) override; + void setLinearFiltering(bool linearFiltering) override; + void setMipmapping(bool mipmapping) override; + void setSmoothPainting(bool s) override; + void setFillColor(const QColor &c) override; + void setContentsScale(qreal s) override; + void setFastFBOResizing(bool dynamic) override; + void setTextureSize(const QSize &size) override; + QImage toImage() const override; + void update() override; + QSGTexture *texture() const override; + + void render() override; + void paint(); + +private: + QQuickPaintedItem::RenderTarget m_preferredRenderTarget; + + QQuickPaintedItem *m_item; + QSGOpenVGTexture *m_texture; + QImage m_image; + + QSize m_size; + bool m_dirtyContents; + QRect m_dirtyRect; + bool m_opaquePainting; + bool m_linear_filtering; + bool m_smoothPainting; + QColor m_fillColor; + qreal m_contentsScale; + QSize m_textureSize; + + bool m_dirtyGeometry; +}; + +QT_END_NAMESPACE + +#endif // QSGOPENVGPAINTERNODE_H diff --git a/src/plugins/scenegraph/openvg/qsgopenvgpublicnodes.cpp b/src/plugins/scenegraph/openvg/qsgopenvgpublicnodes.cpp new file mode 100644 index 0000000000..1afc5ea7ca --- /dev/null +++ b/src/plugins/scenegraph/openvg/qsgopenvgpublicnodes.cpp @@ -0,0 +1,325 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgopenvgpublicnodes.h" +#include "qsgopenvghelpers.h" + +QT_BEGIN_NAMESPACE + +QSGOpenVGRectangleNode::QSGOpenVGRectangleNode() +{ + // Set Dummy material and geometry to avoid asserts + setMaterial((QSGMaterial*)1); + setGeometry((QSGGeometry*)1); + + m_rectPath = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1, 0, 0, 0, + VG_PATH_CAPABILITY_APPEND_TO); + m_rectPaint = vgCreatePaint(); +} + +QSGOpenVGRectangleNode::~QSGOpenVGRectangleNode() +{ + vgDestroyPaint(m_rectPaint); + vgDestroyPath(m_rectPath); +} + +void QSGOpenVGRectangleNode::setRect(const QRectF &rect) +{ + m_rect = rect; + m_pathDirty = true; + markDirty(DirtyMaterial); +} + +void QSGOpenVGRectangleNode::setColor(const QColor &color) +{ + m_color = color; + m_paintDirty = true; + markDirty(DirtyMaterial); +} + +void QSGOpenVGRectangleNode::setTransform(const QOpenVGMatrix &transform) +{ + // if there transform matrix is not affine, regenerate the path + if (transform.isAffine()) + m_pathDirty = true; + markDirty(DirtyGeometry); + + QSGOpenVGRenderable::setTransform(transform); +} + +void QSGOpenVGRectangleNode::render() +{ + // Set Transform + if (transform().isAffine()) { + // Use current transform matrix + vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE); + vgLoadMatrix(transform().constData()); + } else { + // map the path's to handle the perspective matrix + vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE); + vgLoadIdentity(); + } + + if (m_pathDirty) { + vgClearPath(m_rectPath, VG_PATH_CAPABILITY_APPEND_TO); + + if (transform().isAffine()) { + // Create command list + static const VGubyte rectCommands[] = { + VG_MOVE_TO_ABS, + VG_HLINE_TO_REL, + VG_VLINE_TO_REL, + VG_HLINE_TO_REL, + VG_CLOSE_PATH + }; + + // Create command data + QVector<VGfloat> coordinates(5); + coordinates[0] = m_rect.x(); + coordinates[1] = m_rect.y(); + coordinates[2] = m_rect.width(); + coordinates[3] = m_rect.height(); + coordinates[4] = -m_rect.width(); + + vgAppendPathData(m_rectPath, 5, rectCommands, coordinates.constData()); + + } else { + // Pre-transform path + static const VGubyte rectCommands[] = { + VG_MOVE_TO_ABS, + VG_LINE_TO_ABS, + VG_LINE_TO_ABS, + VG_LINE_TO_ABS, + VG_CLOSE_PATH + }; + + QVector<VGfloat> coordinates(8); + const QPointF topLeft = transform().map(m_rect.topLeft()); + const QPointF topRight = transform().map(m_rect.topRight()); + const QPointF bottomLeft = transform().map(m_rect.bottomLeft()); + const QPointF bottomRight = transform().map(m_rect.bottomRight()); + coordinates[0] = bottomLeft.x(); + coordinates[1] = bottomLeft.y(); + coordinates[2] = bottomRight.x(); + coordinates[3] = bottomRight.y(); + coordinates[4] = topRight.x(); + coordinates[5] = topRight.y(); + coordinates[6] = topLeft.x(); + coordinates[7] = topLeft.y(); + + vgAppendPathData(m_rectPath, 5, rectCommands, coordinates.constData()); + } + + m_pathDirty = false; + } + + if (m_paintDirty) { + vgSetPaint(m_rectPaint, VG_FILL_PATH); + vgSetParameteri(m_rectPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); + vgSetParameterfv(m_rectPaint, VG_PAINT_COLOR, 4, QSGOpenVGHelpers::qColorToVGColor(m_color).constData()); + + m_paintDirty = false; + } + + vgSetPaint(m_rectPaint, VG_FILL_PATH); + vgDrawPath(m_rectPath, VG_FILL_PATH); + +} + +QSGOpenVGImageNode::QSGOpenVGImageNode() +{ + // Set Dummy material and geometry to avoid asserts + setMaterial((QSGMaterial*)1); + setGeometry((QSGGeometry*)1); + +} + +QSGOpenVGImageNode::~QSGOpenVGImageNode() +{ + if (m_owns) { + m_texture->deleteLater(); + } +} + +void QSGOpenVGImageNode::setTexture(QSGTexture *texture) +{ + m_texture = texture; + markDirty(DirtyMaterial); +} + +void QSGOpenVGImageNode::setTextureCoordinatesTransform(QSGImageNode::TextureCoordinatesTransformMode transformNode) +{ + if (m_transformMode == transformNode) + return; + m_transformMode = transformNode; + markDirty(DirtyGeometry); +} + +void QSGOpenVGImageNode::render() +{ + if (!m_texture) { + return; + } + + // Set Draw Mode + if (opacity() < 1.0) { + //Transparent + vgSetPaint(opacityPaint(), VG_FILL_PATH); + vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_MULTIPLY); + } else { + vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL); + } + + // Set Transform + vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE); + vgLoadMatrix(transform().constData()); + + VGImage image = static_cast<VGImage>(m_texture->textureId()); + + //Apply the TextureCoordinateTransform Flag + if (m_transformMode != QSGImageNode::NoTransform) { + float translateX = 0.0f; + float translateY = 0.0f; + float scaleX = 1.0f; + float scaleY = 1.0f; + + if (m_transformMode & QSGImageNode::MirrorHorizontally) { + translateX = m_rect.width(); + scaleX = -1.0; + } + + if (m_transformMode & QSGImageNode::MirrorVertically) { + translateY = m_rect.height(); + scaleY = -1.0; + } + + vgTranslate(translateX, translateY); + vgScale(scaleX, scaleY); + } + + // If the the source rect is the same as the target rect + if (m_sourceRect == m_rect) { + vgDrawImage(image); + } else { + // Scale + float scaleX = m_rect.width() / m_sourceRect.width(); + float scaleY = m_rect.height() / m_sourceRect.height(); + vgScale(scaleX, scaleY); + VGImage subImage = vgChildImage(image, m_sourceRect.x(), m_sourceRect.y(), m_sourceRect.width(), m_sourceRect.height()); + vgDrawImage(subImage); + vgDestroyImage(subImage); + } + +} + +QSGOpenVGNinePatchNode::QSGOpenVGNinePatchNode() +{ + // Set Dummy material and geometry to avoid asserts + setMaterial((QSGMaterial*)1); + setGeometry((QSGGeometry*)1); + +} + +void QSGOpenVGNinePatchNode::setTexture(QSGTexture *texture) +{ + m_texture = texture; + markDirty(DirtyMaterial); +} + +void QSGOpenVGNinePatchNode::setBounds(const QRectF &bounds) +{ + if (m_bounds == bounds) + return; + m_bounds = bounds; + markDirty(DirtyGeometry); +} + +void QSGOpenVGNinePatchNode::setDevicePixelRatio(qreal ratio) +{ + if (m_pixelRatio == ratio) + return; + m_pixelRatio = ratio; + markDirty(DirtyGeometry); +} + +void QSGOpenVGNinePatchNode::setPadding(qreal left, qreal top, qreal right, qreal bottom) +{ + QMarginsF margins(left, top, right, bottom); + if (m_margins == margins) + return; + m_margins = margins; + markDirty(DirtyGeometry); +} + +void QSGOpenVGNinePatchNode::update() +{ + +} + +void QSGOpenVGNinePatchNode::render() +{ + if (!m_texture) + return; + + // Set Draw Mode + if (opacity() < 1.0) { + //Transparent + vgSetPaint(opacityPaint(), VG_FILL_PATH); + vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_MULTIPLY); + } else { + vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL); + } + + // Set Transform + vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE); + vgLoadMatrix(transform().constData()); + + VGImage image = static_cast<VGImage>(m_texture->textureId()); + + //Draw borderImage + QSGOpenVGHelpers::qDrawBorderImage(image, m_texture->textureSize(), m_bounds, m_bounds.marginsRemoved(m_margins), QRectF(0, 0, 1, 1)); +} + +QRectF QSGOpenVGNinePatchNode::bounds() const +{ + return m_bounds; +} + + +QT_END_NAMESPACE diff --git a/src/plugins/scenegraph/openvg/qsgopenvgpublicnodes.h b/src/plugins/scenegraph/openvg/qsgopenvgpublicnodes.h new file mode 100644 index 0000000000..34c8e50615 --- /dev/null +++ b/src/plugins/scenegraph/openvg/qsgopenvgpublicnodes.h @@ -0,0 +1,145 @@ +#ifndef QSGOPENVGPUBLICNODES_H +#define QSGOPENVGPUBLICNODES_H + +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtQuick/qsgrectanglenode.h> +#include <QtQuick/qsgimagenode.h> +#include <QtQuick/qsgninepatchnode.h> + +#include <QtGui/QPixmap> + +#include <VG/openvg.h> + +#include "qsgopenvgrenderable.h" + +QT_BEGIN_NAMESPACE + +class QSGOpenVGRectangleNode : public QSGRectangleNode, public QSGOpenVGRenderable +{ +public: + QSGOpenVGRectangleNode(); + ~QSGOpenVGRectangleNode(); + + void setRect(const QRectF &rect) override; + QRectF rect() const override { return m_rect; } + + void setColor(const QColor &color) override; + QColor color() const override { return m_color; } + + void setTransform(const QOpenVGMatrix &transform) override; + + void render() override; + +private: + QRectF m_rect; + QColor m_color; + + + bool m_pathDirty = true; + bool m_paintDirty = true; + + VGPath m_rectPath; + VGPaint m_rectPaint; +}; + +class QSGOpenVGImageNode : public QSGImageNode, public QSGOpenVGRenderable +{ +public: + QSGOpenVGImageNode(); + ~QSGOpenVGImageNode(); + + void setRect(const QRectF &rect) override { m_rect = rect; markDirty(DirtyMaterial); } + QRectF rect() const override { return m_rect; } + + void setSourceRect(const QRectF &r) override { m_sourceRect = r; } + QRectF sourceRect() const override { return m_sourceRect; } + + void setTexture(QSGTexture *texture) override; + QSGTexture *texture() const override { return m_texture; } + + void setFiltering(QSGTexture::Filtering filtering) override { m_filtering = filtering; markDirty(DirtyMaterial); } + QSGTexture::Filtering filtering() const override { return m_filtering; } + + void setMipmapFiltering(QSGTexture::Filtering) override { } + QSGTexture::Filtering mipmapFiltering() const override { return QSGTexture::None; } + + void setTextureCoordinatesTransform(TextureCoordinatesTransformMode transformNode) override; + TextureCoordinatesTransformMode textureCoordinatesTransform() const override { return m_transformMode; } + + void setOwnsTexture(bool owns) override { m_owns = owns; } + bool ownsTexture() const override { return m_owns; } + + void render() override; + +private: + QSGTexture *m_texture; + QRectF m_rect; + QRectF m_sourceRect; + bool m_owns; + QSGTexture::Filtering m_filtering; + TextureCoordinatesTransformMode m_transformMode; +}; + +class QSGOpenVGNinePatchNode : public QSGNinePatchNode, public QSGOpenVGRenderable +{ +public: + QSGOpenVGNinePatchNode(); + + void setTexture(QSGTexture *texture) override; + void setBounds(const QRectF &bounds) override; + void setDevicePixelRatio(qreal ratio) override; + void setPadding(qreal left, qreal top, qreal right, qreal bottom) override; + void update() override; + + void render() override; + + QRectF bounds() const; + +private: + QSGTexture *m_texture; + QRectF m_bounds; + qreal m_pixelRatio; + QMarginsF m_margins; +}; + +QT_END_NAMESPACE + +#endif // QSGOPENVGPUBLICNODES_H diff --git a/src/plugins/scenegraph/openvg/qsgopenvgrenderable.cpp b/src/plugins/scenegraph/openvg/qsgopenvgrenderable.cpp new file mode 100644 index 0000000000..97d0be99c8 --- /dev/null +++ b/src/plugins/scenegraph/openvg/qsgopenvgrenderable.cpp @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgopenvgrenderable.h" + +QT_BEGIN_NAMESPACE + +QSGOpenVGRenderable::QSGOpenVGRenderable() + : m_opacity(1.0f) +{ + m_opacityPaint = vgCreatePaint(); +} + +QSGOpenVGRenderable::~QSGOpenVGRenderable() +{ + vgDestroyPaint(m_opacityPaint); +} + +void QSGOpenVGRenderable::setOpacity(float opacity) +{ + if (m_opacity == opacity) + return; + + m_opacity = opacity; + VGfloat values[] = { + 1.0f, 1.0f, 1.0f, m_opacity + }; + vgSetParameterfv(m_opacityPaint, VG_PAINT_COLOR, 4, values); +} + +float QSGOpenVGRenderable::opacity() const +{ + return m_opacity; +} + +VGPaint QSGOpenVGRenderable::opacityPaint() const +{ + return m_opacityPaint; +} + +void QSGOpenVGRenderable::setTransform(const QOpenVGMatrix &transform) +{ + m_transform = transform; +} + +const QOpenVGMatrix &QSGOpenVGRenderable::transform() const +{ + return m_transform; +} + +QT_END_NAMESPACE diff --git a/src/plugins/scenegraph/openvg/qsgopenvgrenderable.h b/src/plugins/scenegraph/openvg/qsgopenvgrenderable.h new file mode 100644 index 0000000000..a544ae743e --- /dev/null +++ b/src/plugins/scenegraph/openvg/qsgopenvgrenderable.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGOPENVGRENDERABLE_H +#define QSGOPENVGRENDERABLE_H + +#include <QtGlobal> + +#include <VG/openvg.h> + +#include "qopenvgmatrix.h" + +QT_BEGIN_NAMESPACE + +class QSGOpenVGRenderable +{ +public: + QSGOpenVGRenderable(); + virtual ~QSGOpenVGRenderable(); + + virtual void render() = 0; + + virtual void setOpacity(float opacity); + float opacity() const; + VGPaint opacityPaint() const; + + virtual void setTransform(const QOpenVGMatrix &transform); + const QOpenVGMatrix &transform() const; + +private: + float m_opacity; + VGPaint m_opacityPaint; + QOpenVGMatrix m_transform; + +}; + +QT_END_NAMESPACE + +#endif // QSGOPENVGRENDERABLE_H diff --git a/src/plugins/scenegraph/openvg/qsgopenvgrenderer.cpp b/src/plugins/scenegraph/openvg/qsgopenvgrenderer.cpp new file mode 100644 index 0000000000..acd4cf88dc --- /dev/null +++ b/src/plugins/scenegraph/openvg/qsgopenvgrenderer.cpp @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgopenvgrenderer_p.h" +#include "qsgopenvgcontext_p.h" +#include "qsgopenvgnodevisitor.h" +#include "qopenvgcontext_p.h" +#include "qsgopenvghelpers.h" + +#include <QtGui/QWindow> + +#include <VG/openvg.h> + +QT_BEGIN_NAMESPACE + +QSGOpenVGRenderer::QSGOpenVGRenderer(QSGRenderContext *context) + : QSGRenderer(context) +{ + +} + +QSGOpenVGRenderer::~QSGOpenVGRenderer() +{ + +} + +void QSGOpenVGRenderer::renderScene(uint fboId) +{ + Q_UNUSED(fboId) + class B : public QSGBindable + { + public: + void bind() const { } + } bindable; + QSGRenderer::renderScene(bindable); +} + +void QSGOpenVGRenderer::render() +{ + //Clear the window geometry with the clear color + vgSetfv(VG_CLEAR_COLOR, 4, QSGOpenVGHelpers::qColorToVGColor(clearColor()).constData()); + vgClear(0, 0, VG_MAXINT, VG_MAXINT); + + // Visit each node to render scene + QSGOpenVGNodeVisitor rendererVisitor; + rendererVisitor.visitChildren(rootNode()); +} + +void QSGOpenVGRenderer::nodeChanged(QSGNode *node, QSGNode::DirtyState state) +{ + QSGRenderer::nodeChanged(node, state); +} + +QT_END_NAMESPACE diff --git a/src/plugins/scenegraph/openvg/qsgopenvgrenderer_p.h b/src/plugins/scenegraph/openvg/qsgopenvgrenderer_p.h new file mode 100644 index 0000000000..24cabd1b89 --- /dev/null +++ b/src/plugins/scenegraph/openvg/qsgopenvgrenderer_p.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGOPENVGRENDERER_H +#define QSGOPENVGRENDERER_H + +#include <private/qsgrenderer_p.h> + +QT_BEGIN_NAMESPACE + +class QSGOpenVGRenderer : public QSGRenderer +{ +public: + QSGOpenVGRenderer(QSGRenderContext *context); + virtual ~QSGOpenVGRenderer(); + + void nodeChanged(QSGNode *node, QSGNode::DirtyState state) override; + + void renderScene(uint fboId = 0) final; + void render() final; +}; + +QT_END_NAMESPACE + +#endif // QSGOPENVGRENDERER_H diff --git a/src/plugins/scenegraph/openvg/qsgopenvgrenderloop.cpp b/src/plugins/scenegraph/openvg/qsgopenvgrenderloop.cpp new file mode 100644 index 0000000000..290ee8028c --- /dev/null +++ b/src/plugins/scenegraph/openvg/qsgopenvgrenderloop.cpp @@ -0,0 +1,257 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgopenvgrenderloop_p.h" +#include "qsgopenvgcontext_p.h" + +#include <QtCore/QCoreApplication> +#include <QtCore/QElapsedTimer> + +#include <private/qquickwindow_p.h> +#include <private/qquickprofiler_p.h> + +#include "qopenvgcontext_p.h" + +QT_BEGIN_NAMESPACE + +QSGOpenVGRenderLoop::QSGOpenVGRenderLoop() + : vg(nullptr) +{ + sg = QSGContext::createDefaultContext(); + rc = sg->createRenderContext(); +} + +QSGOpenVGRenderLoop::~QSGOpenVGRenderLoop() +{ + delete rc; + delete sg; +} + +void QSGOpenVGRenderLoop::show(QQuickWindow *window) +{ + WindowData data; + data.updatePending = false; + data.grabOnly = false; + m_windows[window] = data; + + maybeUpdate(window); +} + +void QSGOpenVGRenderLoop::hide(QQuickWindow *window) +{ + QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window); + cd->fireAboutToStop(); +} + +void QSGOpenVGRenderLoop::windowDestroyed(QQuickWindow *window) +{ + m_windows.remove(window); + hide(window); + + QQuickWindowPrivate *d = QQuickWindowPrivate::get(window); + d->cleanupNodesOnShutdown(); + + if (m_windows.size() == 0) { + rc->invalidate(); + delete vg; + vg = nullptr; + QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + } else if (vg && window == vg->window()) { + vg->doneCurrent(); + } +} + +void QSGOpenVGRenderLoop::exposureChanged(QQuickWindow *window) +{ + if (window->isExposed()) { + m_windows[window].updatePending = true; + renderWindow(window); + } +} + +QImage QSGOpenVGRenderLoop::grab(QQuickWindow *window) +{ + if (!m_windows.contains(window)) + return QImage(); + + m_windows[window].grabOnly = true; + + renderWindow(window); + + QImage grabbed = grabContent; + grabContent = QImage(); + return grabbed; +} + +void QSGOpenVGRenderLoop::update(QQuickWindow *window) +{ + maybeUpdate(window); +} + +void QSGOpenVGRenderLoop::handleUpdateRequest(QQuickWindow *window) +{ + renderWindow(window); +} + +void QSGOpenVGRenderLoop::maybeUpdate(QQuickWindow *window) +{ + if (!m_windows.contains(window)) + return; + + m_windows[window].updatePending = true; + window->requestUpdate(); +} + +QAnimationDriver *QSGOpenVGRenderLoop::animationDriver() const +{ + return nullptr; +} + +QSGContext *QSGOpenVGRenderLoop::sceneGraphContext() const +{ + return sg; +} + +QSGRenderContext *QSGOpenVGRenderLoop::createRenderContext(QSGContext *) const +{ + return rc; +} + +void QSGOpenVGRenderLoop::releaseResources(QQuickWindow *window) +{ + Q_UNUSED(window) +} + +QSurface::SurfaceType QSGOpenVGRenderLoop::windowSurfaceType() const +{ + return QSurface::OpenVGSurface; +} + +void QSGOpenVGRenderLoop::renderWindow(QQuickWindow *window) +{ + QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window); + if (!cd->isRenderable() || !m_windows.contains(window)) + return; + + WindowData &data = const_cast<WindowData &>(m_windows[window]); + + if (vg == nullptr) { + vg = new QOpenVGContext(window); + vg->makeCurrent(); + cd->context->initialize(vg); + } else { + vg->makeCurrent(); + } + + bool alsoSwap = data.updatePending; + data.updatePending = false; + + if (!data.grabOnly) { + // Event delivery/processing triggered the window to be deleted or stop rendering. + if (!m_windows.contains(window)) + return; + } + QElapsedTimer renderTimer; + qint64 renderTime = 0, syncTime = 0, polishTime = 0; + bool profileFrames = QSG_OPENVG_LOG_TIME_RENDERLOOP().isDebugEnabled(); + if (profileFrames) + renderTimer.start(); + Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphPolishFrame); + + cd->polishItems(); + + if (profileFrames) + polishTime = renderTimer.nsecsElapsed(); + Q_QUICK_SG_PROFILE_SWITCH(QQuickProfiler::SceneGraphPolishFrame, + QQuickProfiler::SceneGraphRenderLoopFrame); + + emit window->afterAnimating(); + + cd->syncSceneGraph(); + + if (profileFrames) + syncTime = renderTimer.nsecsElapsed(); + Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame); + + // setup coordinate system for window + vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE); + vgLoadIdentity(); + vgTranslate(0.0f, window->size().height()); + vgScale(1.0, -1.0); + + cd->renderSceneGraph(window->size()); + + if (profileFrames) + renderTime = renderTimer.nsecsElapsed(); + Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame); + + if (data.grabOnly) { + grabContent = vg->readFramebuffer(window->size() * window->effectiveDevicePixelRatio()); + data.grabOnly = false; + } + + if (alsoSwap && window->isVisible()) { + vg->swapBuffers(); + cd->fireFrameSwapped(); + } + + qint64 swapTime = 0; + if (profileFrames) + swapTime = renderTimer.nsecsElapsed(); + Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphRenderLoopFrame); + + if (QSG_OPENVG_LOG_TIME_RENDERLOOP().isDebugEnabled()) { + static QTime lastFrameTime = QTime::currentTime(); + qCDebug(QSG_OPENVG_LOG_TIME_RENDERLOOP, + "Frame rendered with 'basic' renderloop in %dms, polish=%d, sync=%d, render=%d, swap=%d, frameDelta=%d", + int(swapTime / 1000000), + int(polishTime / 1000000), + int((syncTime - polishTime) / 1000000), + int((renderTime - syncTime) / 1000000), + int((swapTime - renderTime) / 10000000), + int(lastFrameTime.msecsTo(QTime::currentTime()))); + lastFrameTime = QTime::currentTime(); + } + + // Might have been set during syncSceneGraph() + if (data.updatePending) + maybeUpdate(window); +} + +QT_END_NAMESPACE diff --git a/src/plugins/scenegraph/openvg/qsgopenvgrenderloop_p.h b/src/plugins/scenegraph/openvg/qsgopenvgrenderloop_p.h new file mode 100644 index 0000000000..f35b689e00 --- /dev/null +++ b/src/plugins/scenegraph/openvg/qsgopenvgrenderloop_p.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGOPENVGRENDERLOOP_H +#define QSGOPENVGRENDERLOOP_H + +#include <private/qsgrenderloop_p.h> + +QT_BEGIN_NAMESPACE + +class QOpenVGContext; + +class QSGOpenVGRenderLoop : public QSGRenderLoop +{ +public: + QSGOpenVGRenderLoop(); + ~QSGOpenVGRenderLoop(); + + + void show(QQuickWindow *window) override; + void hide(QQuickWindow *window) override; + + void windowDestroyed(QQuickWindow *window) override; + + void renderWindow(QQuickWindow *window); + void exposureChanged(QQuickWindow *window) override; + QImage grab(QQuickWindow *window) override; + + void maybeUpdate(QQuickWindow *window) override; + void update(QQuickWindow *window) override; + void handleUpdateRequest(QQuickWindow *window) override; + + void releaseResources(QQuickWindow *) override; + + QSurface::SurfaceType windowSurfaceType() const override; + + QAnimationDriver *animationDriver() const override; + + QSGContext *sceneGraphContext() const override; + QSGRenderContext *createRenderContext(QSGContext *) const override; + + struct WindowData { + bool updatePending : 1; + bool grabOnly : 1; + }; + + QHash<QQuickWindow *, WindowData> m_windows; + + QSGContext *sg; + QSGRenderContext *rc; + QOpenVGContext *vg; + + QImage grabContent; +}; + +QT_END_NAMESPACE + +#endif // QSGOPENVGRENDERLOOP_H diff --git a/src/plugins/scenegraph/openvg/qsgopenvgspritenode.cpp b/src/plugins/scenegraph/openvg/qsgopenvgspritenode.cpp new file mode 100644 index 0000000000..fb24df7471 --- /dev/null +++ b/src/plugins/scenegraph/openvg/qsgopenvgspritenode.cpp @@ -0,0 +1,157 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgopenvgspritenode.h" +#include "qsgopenvgtexture.h" + +QT_BEGIN_NAMESPACE + +QSGOpenVGSpriteNode::QSGOpenVGSpriteNode() + : m_time(0.0f) +{ + // Set Dummy material and geometry to avoid asserts + setMaterial((QSGMaterial*)1); + setGeometry((QSGGeometry*)1); +} + +QSGOpenVGSpriteNode::~QSGOpenVGSpriteNode() +{ + +} + +void QSGOpenVGSpriteNode::setTexture(QSGTexture *texture) +{ + m_texture = static_cast<QSGOpenVGTexture*>(texture); + markDirty(DirtyMaterial); +} + +void QSGOpenVGSpriteNode::setTime(float time) +{ + if (m_time != time) { + m_time = time; + markDirty(DirtyMaterial); + } +} + +void QSGOpenVGSpriteNode::setSourceA(const QPoint &source) +{ + if (m_sourceA != source) { + m_sourceA = source; + markDirty(DirtyMaterial); + } +} + +void QSGOpenVGSpriteNode::setSourceB(const QPoint &source) +{ + if (m_sourceB != source) { + m_sourceB = source; + markDirty(DirtyMaterial); + } +} + +void QSGOpenVGSpriteNode::setSpriteSize(const QSize &size) +{ + if (m_spriteSize != size) { + m_spriteSize = size; + markDirty(DirtyMaterial); + } +} + +void QSGOpenVGSpriteNode::setSheetSize(const QSize &size) +{ + if (m_sheetSize != size) { + m_sheetSize = size; + markDirty(DirtyMaterial); + } +} + +void QSGOpenVGSpriteNode::setSize(const QSizeF &size) +{ + if (m_size != size) { + m_size = size; + markDirty(DirtyGeometry); + } +} + +void QSGOpenVGSpriteNode::setFiltering(QSGTexture::Filtering) +{ +} + +void QSGOpenVGSpriteNode::update() +{ +} + +void QSGOpenVGSpriteNode::render() +{ + if (!m_texture) + return; + + VGImage image = static_cast<VGImage>(m_texture->textureId()); + + QRectF sourceRect(m_sourceA, m_spriteSize); + QRectF targetRect(0, 0, m_size.width(), m_size.height()); + + VGImage sourceImage = vgChildImage(image, sourceRect.x(), sourceRect.y(), sourceRect.width(), sourceRect.height()); + + // Set Draw Mode + if (opacity() < 1.0) { + //Transparent + vgSetPaint(opacityPaint(), VG_FILL_PATH); + vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_MULTIPLY); + } else { + vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL); + } + + // Set Image Matrix + vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE); + vgLoadMatrix(transform().constData()); + + if (sourceRect != targetRect) { + // Scale + float scaleX = targetRect.width() / sourceRect.width(); + float scaleY = targetRect.height() / sourceRect.height(); + vgScale(scaleX, scaleY); + } + + vgDrawImage(sourceImage); + + vgDestroyImage(sourceImage); +} + +QT_END_NAMESPACE diff --git a/src/plugins/scenegraph/openvg/qsgopenvgspritenode.h b/src/plugins/scenegraph/openvg/qsgopenvgspritenode.h new file mode 100644 index 0000000000..3ade2ef8ad --- /dev/null +++ b/src/plugins/scenegraph/openvg/qsgopenvgspritenode.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGOPENVGSPRITENODE_H +#define QSGOPENVGSPRITENODE_H + +#include <private/qsgadaptationlayer_p.h> +#include "qsgopenvgrenderable.h" + +QT_BEGIN_NAMESPACE +class QSGOpenVGTexture; +class QSGOpenVGSpriteNode : public QSGSpriteNode, public QSGOpenVGRenderable +{ +public: + QSGOpenVGSpriteNode(); + ~QSGOpenVGSpriteNode(); + + void setTexture(QSGTexture *texture) override; + void setTime(float time) override; + void setSourceA(const QPoint &source) override; + void setSourceB(const QPoint &source) override; + void setSpriteSize(const QSize &size) override; + void setSheetSize(const QSize &size) override; + void setSize(const QSizeF &size) override; + void setFiltering(QSGTexture::Filtering filtering) override; + void update() override; + + void render() override; + +private: + QSGOpenVGTexture *m_texture; + float m_time; + QPoint m_sourceA; + QPoint m_sourceB; + QSize m_spriteSize; + QSize m_sheetSize; + QSizeF m_size; +}; + +QT_END_NAMESPACE + +#endif // QSGOPENVGSPRITENODE_H diff --git a/src/plugins/scenegraph/openvg/qsgopenvgtexture.cpp b/src/plugins/scenegraph/openvg/qsgopenvgtexture.cpp new file mode 100644 index 0000000000..dd2fdc7020 --- /dev/null +++ b/src/plugins/scenegraph/openvg/qsgopenvgtexture.cpp @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgopenvgtexture.h" +#include "qsgopenvghelpers.h" + +QT_BEGIN_NAMESPACE + +QSGOpenVGTexture::QSGOpenVGTexture(const QImage &image, uint flags) +{ + Q_UNUSED(flags) + + VGImageFormat format = QSGOpenVGHelpers::qImageFormatToVGImageFormat(image.format()); + m_image = vgCreateImage(format, image.width(), image.height(), VG_IMAGE_QUALITY_BETTER); + + // Do Texture Upload + vgImageSubData(m_image, image.constBits(), image.bytesPerLine(), format, 0, 0, image.width(), image.height()); +} + +QSGOpenVGTexture::~QSGOpenVGTexture() +{ + vgDestroyImage(m_image); +} + +int QSGOpenVGTexture::textureId() const +{ + return static_cast<int>(m_image); +} + +QSize QSGOpenVGTexture::textureSize() const +{ + VGint imageWidth = vgGetParameteri(m_image, VG_IMAGE_WIDTH); + VGint imageHeight = vgGetParameteri(m_image, VG_IMAGE_HEIGHT); + return QSize(imageWidth, imageHeight); +} + +bool QSGOpenVGTexture::hasAlphaChannel() const +{ + VGImageFormat format = static_cast<VGImageFormat>(vgGetParameteri(m_image, VG_IMAGE_FORMAT)); + + switch (format) { + case VG_sRGBA_8888: + case VG_sRGBA_8888_PRE: + case VG_sRGBA_5551: + case VG_sRGBA_4444: + case VG_lRGBA_8888: + case VG_lRGBA_8888_PRE: + case VG_A_8: + case VG_A_1: + case VG_A_4: + case VG_sARGB_8888: + case VG_sARGB_8888_PRE: + case VG_sARGB_1555: + case VG_sARGB_4444: + case VG_lARGB_8888: + case VG_lARGB_8888_PRE: + case VG_sBGRA_8888: + case VG_sBGRA_8888_PRE: + case VG_sBGRA_5551: + case VG_sBGRA_4444: + case VG_lBGRA_8888: + case VG_lBGRA_8888_PRE: + case VG_sABGR_8888: + case VG_sABGR_8888_PRE: + case VG_sABGR_1555: + case VG_sABGR_4444: + case VG_lABGR_8888: + case VG_lABGR_8888_PRE: + return true; + break; + default: + break; + } + return false; +} + +bool QSGOpenVGTexture::hasMipmaps() const +{ + return false; +} + +void QSGOpenVGTexture::bind() +{ + // No need to bind +} + +QT_END_NAMESPACE diff --git a/src/plugins/scenegraph/openvg/qsgopenvgtexture.h b/src/plugins/scenegraph/openvg/qsgopenvgtexture.h new file mode 100644 index 0000000000..523c9e690d --- /dev/null +++ b/src/plugins/scenegraph/openvg/qsgopenvgtexture.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGOPENVGTEXTURE_H +#define QSGOPENVGTEXTURE_H + +#include <private/qsgtexture_p.h> + +#include <VG/openvg.h> + +QT_BEGIN_NAMESPACE + +class QSGOpenVGTexture : public QSGTexture +{ +public: + QSGOpenVGTexture(const QImage &image, uint flags); + ~QSGOpenVGTexture(); + + int textureId() const override; + QSize textureSize() const override; + bool hasAlphaChannel() const override; + bool hasMipmaps() const override; + void bind() override; + +private: + VGImage m_image;; +}; + +QT_END_NAMESPACE + +#endif // QSGOPENVGTEXTURE_H diff --git a/src/plugins/scenegraph/scenegraph.pro b/src/plugins/scenegraph/scenegraph.pro index a90e8d4814..39c0c0815c 100644 --- a/src/plugins/scenegraph/scenegraph.pro +++ b/src/plugins/scenegraph/scenegraph.pro @@ -1,3 +1,5 @@ TEMPLATE = subdirs QT_FOR_CONFIG += quick qtConfig(d3d12): SUBDIRS += d3d12 +qtConfig(openvg): SUBDIRS += openvg + |