From 527f6e411fed3b27abe637a6bbcbb47f4110b69f Mon Sep 17 00:00:00 2001 From: David Boddie Date: Mon, 22 Jun 2009 13:59:22 +0200 Subject: qdoc: Fixed XHTML breakage again. Reviewed-by: Trust me --- tools/qdoc3/htmlgenerator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/qdoc3/htmlgenerator.cpp b/tools/qdoc3/htmlgenerator.cpp index 8ef4f0b..2a49f81 100644 --- a/tools/qdoc3/htmlgenerator.cpp +++ b/tools/qdoc3/htmlgenerator.cpp @@ -2290,7 +2290,7 @@ void HtmlGenerator::generateSectionInheritedList(const Section& section, QList >::ConstIterator p = section.inherited.begin(); while (p != section.inherited.end()) { if (nameAlignment) - out() << "
  • "; + out() << "
  • "; else out() << "
  • "; out() << (*p).second << " "; @@ -2577,7 +2577,7 @@ void HtmlGenerator::generateSectionInheritedList(const Section& section, { QList >::ConstIterator p = section.inherited.begin(); while (p != section.inherited.end()) { - out() << "
  • "; + out() << "
  • "; out() << (*p).second << " "; if ((*p).second == 1) { out() << section.singularMember; -- cgit v0.12 From faac8a24d682ef0cfee52bef3ec1754d27c212b9 Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Mon, 22 Jun 2009 11:15:32 +0200 Subject: add test for parallel root state (which currently isn't supported) --- tests/auto/qstatemachine/tst_qstatemachine.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/auto/qstatemachine/tst_qstatemachine.cpp b/tests/auto/qstatemachine/tst_qstatemachine.cpp index b39f0a1..1cc2a8e 100644 --- a/tests/auto/qstatemachine/tst_qstatemachine.cpp +++ b/tests/auto/qstatemachine/tst_qstatemachine.cpp @@ -118,6 +118,7 @@ private slots: void postEvent(); void stateFinished(); void parallelStates(); + void parallelRootState(); void allSourceToTargetConfigurations(); void signalTransitions(); void eventTransitions(); @@ -1633,6 +1634,29 @@ void tst_QStateMachine::parallelStates() QVERIFY(machine.configuration().contains(s2)); } +void tst_QStateMachine::parallelRootState() +{ + QStateMachine machine; + QState *root = machine.rootState(); + QCOMPARE(root->childMode(), QState::ExclusiveStates); + root->setChildMode(QState::ParallelStates); + QCOMPARE(root->childMode(), QState::ParallelStates); + + QState *s1 = new QState(root); + QFinalState *s1_f = new QFinalState(s1); + s1->setInitialState(s1_f); + QState *s2 = new QState(root); + QFinalState *s2_f = new QFinalState(s2); + s2->setInitialState(s2_f); + + QSignalSpy startedSpy(&machine, SIGNAL(started())); + QTest::ignoreMessage(QtWarningMsg, "QStateMachine::start: No initial state set for machine. Refusing to start."); + machine.start(); + QCoreApplication::processEvents(); + QEXPECT_FAIL("", "parallel root state is not supported (task 256587)", Continue); + QCOMPARE(startedSpy.count(), 1); +} + void tst_QStateMachine::allSourceToTargetConfigurations() { QStateMachine machine; -- cgit v0.12 From 24146ce4ad076fb6337b591d24e5a8c6a290fe41 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Mon, 22 Jun 2009 12:53:29 +0200 Subject: QApplication: Reduce number of kdeglobals file loads From 14 per X11 application down to 4. Reviewed-by: jbache --- src/gui/kernel/qapplication_x11.cpp | 48 +++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp index 942836a..babc5df 100644 --- a/src/gui/kernel/qapplication_x11.cpp +++ b/src/gui/kernel/qapplication_x11.cpp @@ -1085,10 +1085,8 @@ static void qt_set_input_encoding() } // Reads a KDE color setting -static QColor kdeColor(const QString &key) +static QColor kdeColor(const QString &key, const QSettings &kdeSettings) { - QSettings kdeSettings(QApplicationPrivate::kdeHome() + - QLatin1String("/share/config/kdeglobals"), QSettings::IniFormat); QVariant variant = kdeSettings.value(key); if (variant.isValid()) { QStringList values = variant.toStringList(); @@ -1307,36 +1305,40 @@ static void qt_set_x11_resources(const char* font = 0, const char* fg = 0, } if (kdeColors) { + const QSettings &theKdeSettings = + QSettings(QApplicationPrivate::kdeHome() + + QLatin1String("/share/config/kdeglobals"), QSettings::IniFormat); + // Setup KDE palette QColor color; - color = kdeColor(QLatin1String("buttonBackground")); + color = kdeColor(QLatin1String("buttonBackground"), theKdeSettings); if (!color.isValid()) - color = kdeColor(QLatin1String("Colors:Button/BackgroundNormal")); + color = kdeColor(QLatin1String("Colors:Button/BackgroundNormal"), theKdeSettings); if (color.isValid()) btn = color; - color = kdeColor(QLatin1String("background")); + color = kdeColor(QLatin1String("background"), theKdeSettings); if (!color.isValid()) - color = kdeColor(QLatin1String("Colors:Window/BackgroundNormal")); + color = kdeColor(QLatin1String("Colors:Window/BackgroundNormal"), theKdeSettings); if (color.isValid()) bg = color; - color = kdeColor(QLatin1String("foreground")); + color = kdeColor(QLatin1String("foreground"), theKdeSettings); if (!color.isValid()) - color = kdeColor(QLatin1String("Colors:View/ForegroundNormal")); + color = kdeColor(QLatin1String("Colors:View/ForegroundNormal"), theKdeSettings); if (color.isValid()) { fg = color; } - color = kdeColor(QLatin1String("windowForeground")); + color = kdeColor(QLatin1String("windowForeground"), theKdeSettings); if (!color.isValid()) - color = kdeColor(QLatin1String("Colors:Window/ForegroundNormal")); + color = kdeColor(QLatin1String("Colors:Window/ForegroundNormal"), theKdeSettings); if (color.isValid()) wfg = color; - color = kdeColor(QLatin1String("windowBackground")); + color = kdeColor(QLatin1String("windowBackground"), theKdeSettings); if (!color.isValid()) - color = kdeColor(QLatin1String("Colors:View/BackgroundNormal")); + color = kdeColor(QLatin1String("Colors:View/BackgroundNormal"), theKdeSettings); if (color.isValid()) base = color; } @@ -1355,29 +1357,33 @@ static void qt_set_x11_resources(const char* font = 0, const char* fg = 0, } // Use KDE3 or KDE4 color settings if present if (kdeColors) { - QColor color = kdeColor(QLatin1String("selectBackground")); + const QSettings &theKdeSettings = + QSettings(QApplicationPrivate::kdeHome() + + QLatin1String("/share/config/kdeglobals"), QSettings::IniFormat); + + QColor color = kdeColor(QLatin1String("selectBackground"), theKdeSettings); if (!color.isValid()) - color = kdeColor(QLatin1String("Colors:Selection/BackgroundNormal")); + color = kdeColor(QLatin1String("Colors:Selection/BackgroundNormal"), theKdeSettings); if (color.isValid()) highlight = color; - color = kdeColor(QLatin1String("selectForeground")); + color = kdeColor(QLatin1String("selectForeground"), theKdeSettings); if (!color.isValid()) - color = kdeColor(QLatin1String("Colors:Selection/ForegroundNormal")); + color = kdeColor(QLatin1String("Colors:Selection/ForegroundNormal"), theKdeSettings); if (color.isValid()) highlightText = color; - color = kdeColor(QLatin1String("alternateBackground")); + color = kdeColor(QLatin1String("alternateBackground"), theKdeSettings); if (!color.isValid()) - color = kdeColor(QLatin1String("Colors:View/BackgroundAlternate")); + color = kdeColor(QLatin1String("Colors:View/BackgroundAlternate"), theKdeSettings); if (color.isValid()) pal.setColor(QPalette::AlternateBase, color); else pal.setBrush(QPalette::AlternateBase, pal.base().color().darker(110)); - color = kdeColor(QLatin1String("buttonForeground")); + color = kdeColor(QLatin1String("buttonForeground"), theKdeSettings); if (!color.isValid()) - color = kdeColor(QLatin1String("Colors:Button/ForegroundNormal")); + color = kdeColor(QLatin1String("Colors:Button/ForegroundNormal"), theKdeSettings); if (color.isValid()) pal.setColor(QPalette::ButtonText, color); } -- cgit v0.12 From db92a780ceb130b6fa91ad866e521237c4b255b8 Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Mon, 22 Jun 2009 14:44:55 +0200 Subject: perform normalization of signatures for signal transitions Make state->addTransition(foo, SIGNAL( bar( ) ), ...) work. --- src/corelib/statemachine/qstate.cpp | 11 +++++++---- src/corelib/statemachine/qstatemachine.cpp | 12 ++++++++---- tests/auto/qstatemachine/tst_qstatemachine.cpp | 25 +++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/corelib/statemachine/qstate.cpp b/src/corelib/statemachine/qstate.cpp index c42c9c9..fd7ddef 100644 --- a/src/corelib/statemachine/qstate.cpp +++ b/src/corelib/statemachine/qstate.cpp @@ -333,10 +333,13 @@ QSignalTransition *QState::addTransition(QObject *sender, const char *signal, return 0; } int offset = (*signal == '0'+QSIGNAL_CODE) ? 1 : 0; - if (sender->metaObject()->indexOfSignal(signal+offset) == -1) { - qWarning("QState::addTransition: no such signal %s::%s", - sender->metaObject()->className(), signal+offset); - return 0; + const QMetaObject *meta = sender->metaObject(); + if (meta->indexOfSignal(signal+offset) == -1) { + if (meta->indexOfSignal(QMetaObject::normalizedSignature(signal+offset)) == -1) { + qWarning("QState::addTransition: no such signal %s::%s", + meta->className(), signal+offset); + return 0; + } } QSignalTransition *trans = new QSignalTransition(sender, signal, QList() << target); addTransition(trans); diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index 758bdbe..682dd97 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -1316,11 +1316,15 @@ void QStateMachinePrivate::registerSignalTransition(QSignalTransition *transitio QByteArray signal = QSignalTransitionPrivate::get(transition)->signal; if (signal.startsWith('0'+QSIGNAL_CODE)) signal.remove(0, 1); - int signalIndex = sender->metaObject()->indexOfSignal(signal); + const QMetaObject *meta = sender->metaObject(); + int signalIndex = meta->indexOfSignal(signal); if (signalIndex == -1) { - qWarning("QSignalTransition: no such signal: %s::%s", - sender->metaObject()->className(), signal.constData()); - return; + signalIndex = meta->indexOfSignal(QMetaObject::normalizedSignature(signal)); + if (signalIndex == -1) { + qWarning("QSignalTransition: no such signal: %s::%s", + meta->className(), signal.constData()); + return; + } } QVector &connectedSignalIndexes = connections[sender]; if (connectedSignalIndexes.size() <= signalIndex) diff --git a/tests/auto/qstatemachine/tst_qstatemachine.cpp b/tests/auto/qstatemachine/tst_qstatemachine.cpp index 1cc2a8e..553833c 100644 --- a/tests/auto/qstatemachine/tst_qstatemachine.cpp +++ b/tests/auto/qstatemachine/tst_qstatemachine.cpp @@ -1981,6 +1981,31 @@ void tst_QStateMachine::signalTransitions() QCOMPARE(machine.configuration().size(), 1); QVERIFY(machine.configuration().contains(s3)); } + // signature normalization + { + QStateMachine machine; + SignalEmitter emitter; + QState *s0 = new QState(machine.rootState()); + QFinalState *s1 = new QFinalState(machine.rootState()); + QSignalTransition *t0 = s0->addTransition(&emitter, SIGNAL( signalWithNoArg( ) ), s1); + QVERIFY(t0 != 0); + QCOMPARE(t0->signal(), QByteArray(SIGNAL( signalWithNoArg( ) ))); + + QSignalTransition *t1 = s0->addTransition(&emitter, SIGNAL( signalWithStringArg( const QString & ) ), s1); + QVERIFY(t1 != 0); + QCOMPARE(t1->signal(), QByteArray(SIGNAL( signalWithStringArg( const QString & ) ))); + + QSignalSpy startedSpy(&machine, SIGNAL(started())); + QSignalSpy finishedSpy(&machine, SIGNAL(finished())); + machine.setInitialState(s0); + machine.start(); + QTRY_COMPARE(startedSpy.count(), 1); + QCOMPARE(finishedSpy.count(), 0); + + emitter.emitSignalWithNoArg(); + + QTRY_COMPARE(finishedSpy.count(), 1); + } } void tst_QStateMachine::eventTransitions() -- cgit v0.12 From 51aba60ca75f6f094951d3ffaea803072db75d29 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Thu, 18 Jun 2009 17:50:32 +0200 Subject: QNetworkDiskCache: add code snippets in documentation should make it easier to apply a network disk cache with code snippets now Reviewed-by: David Boddie Reviewed-by: Martin Petersson --- .../code/src_network_access_qnetworkdiskcache.cpp | 24 ++++++++++++++++++++++ src/network/access/qnetworkdiskcache.cpp | 14 +++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 doc/src/snippets/code/src_network_access_qnetworkdiskcache.cpp diff --git a/doc/src/snippets/code/src_network_access_qnetworkdiskcache.cpp b/doc/src/snippets/code/src_network_access_qnetworkdiskcache.cpp new file mode 100644 index 0000000..acd3938 --- /dev/null +++ b/doc/src/snippets/code/src_network_access_qnetworkdiskcache.cpp @@ -0,0 +1,24 @@ +//! [0] +QNetworkAccessManager *manager = new QNetworkAccessManager(this); +QNetworkDiskCache *diskCache = new QNetworkDiskCache(this); +diskCache->setCacheDirectory("cacheDir"); +manager->setCache(diskCache); +//! [0] + +//! [1] +// do a normal request (preferred from network, as this is the default) +QNetworkRequest request(QUrl(QString("http://www.qtsoftware.com"))); +manager->get(request); + +// do a request preferred from cache +QNetworkRequest request2(QUrl(QString("http://www.qtsoftware.com"))); +request2.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); +manager->get(request2); +//! [1] + +//! [2] +void replyFinished(QNetworkReply *reply) { + QVariant fromCache = reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute); + qDebug() << "page from cache?" << fromCache.toBool(); +} +//! [2] diff --git a/src/network/access/qnetworkdiskcache.cpp b/src/network/access/qnetworkdiskcache.cpp index 5df6b0f..50aaa6a 100644 --- a/src/network/access/qnetworkdiskcache.cpp +++ b/src/network/access/qnetworkdiskcache.cpp @@ -81,6 +81,20 @@ QT_BEGIN_NAMESPACE use on the system to 50MB. Note you have to set the cache directory before it will work. + + A network disk cache can be enabled by: + + \snippet doc/src/snippets/code/src_network_access_qnetworkdiskcache.cpp 0 + + When sending requests, to control the preference of when to use the cache + and when to use the network, consider the following: + + \snippet doc/src/snippets/code/src_network_access_qnetworkdiskcache.cpp 1 + + To check whether the response came from the cache or from the network, the + following can be applied: + + \snippet doc/src/snippets/code/src_network_access_qnetworkdiskcache.cpp 2 */ /*! -- cgit v0.12 From 2dcb97ff789dd7a9b7534348ca49c96c09783055 Mon Sep 17 00:00:00 2001 From: Suneel BS Date: Fri, 8 May 2009 14:47:36 +0530 Subject: Fixed fill-rule for polygon SVG element. Polygon element should apply the fill rule which is specified in its fill-rule attribute. Default fill rule is 'WindingFill' (nonzero). Modified and autotest added by Kim. Reviewed-by: Kim --- src/svg/qsvggraphics.cpp | 5 +- src/svg/qsvggraphics_p.h | 5 ++ src/svg/qsvgstyle.cpp | 3 ++ tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp | 72 ++++++++++++++++++++++------ 4 files changed, 68 insertions(+), 17 deletions(-) diff --git a/src/svg/qsvggraphics.cpp b/src/svg/qsvggraphics.cpp index 6782429..e09f382 100644 --- a/src/svg/qsvggraphics.cpp +++ b/src/svg/qsvggraphics.cpp @@ -198,9 +198,8 @@ QRectF QSvgPath::bounds() const } QSvgPolygon::QSvgPolygon(QSvgNode *parent, const QPolygonF &poly) - : QSvgNode(parent), m_poly(poly) + : QSvgNode(parent), m_poly(poly), m_fillRule(Qt::WindingFill) { - } QRectF QSvgPolygon::bounds() const @@ -217,7 +216,7 @@ QRectF QSvgPolygon::bounds() const void QSvgPolygon::draw(QPainter *p, QSvgExtraStates &states) { - QT_SVG_DRAW_SHAPE(p->drawPolygon(m_poly)); + QT_SVG_DRAW_SHAPE(p->drawPolygon(m_poly, m_fillRule)); } diff --git a/src/svg/qsvggraphics_p.h b/src/svg/qsvggraphics_p.h index 8a412c4..4a19c7e 100644 --- a/src/svg/qsvggraphics_p.h +++ b/src/svg/qsvggraphics_p.h @@ -155,8 +155,13 @@ public: virtual void draw(QPainter *p, QSvgExtraStates &states); virtual Type type() const; virtual QRectF bounds() const; + void setFillRule(Qt::FillRule f) + { + m_fillRule = f; + } private: QPolygonF m_poly; + Qt::FillRule m_fillRule; }; class QSvgPolyline : public QSvgNode diff --git a/src/svg/qsvgstyle.cpp b/src/svg/qsvgstyle.cpp index fa996f4..9d46649 100644 --- a/src/svg/qsvgstyle.cpp +++ b/src/svg/qsvgstyle.cpp @@ -107,6 +107,9 @@ static void recursivelySetFill(QSvgNode *node, Qt::FillRule f) if (node->type() == QSvgNode::PATH) { QSvgPath *path = static_cast(node); path->qpath()->setFillRule(f); + } else if (node->type() == QSvgNode::POLYGON) { + QSvgPolygon *polygon = static_cast(node); + polygon->setFillRule(f); } else if (node->type() == QSvgNode::G) { QList renderers = static_cast(node)->renderers(); foreach(QSvgNode *n, renderers) { diff --git a/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp b/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp index e8cb089..b148f8c 100644 --- a/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp +++ b/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp @@ -331,7 +331,7 @@ void tst_QSvgRenderer::nestedQXmlStreamReader() const QCOMPARE(reader.readNext(), QXmlStreamReader::StartDocument); QCOMPARE(reader.readNext(), QXmlStreamReader::StartElement); QCOMPARE(reader.name().toString(), QLatin1String("bar")); - + QPicture picture; QPainter painter(&picture); QSvgRenderer renderer(&reader); @@ -653,22 +653,66 @@ void tst_QSvgRenderer::testGzHelper() void tst_QSvgRenderer::fillRule() { - QByteArray data( + static const char *svgs[] = { + // Paths + // Default fill-rule (nonzero) "" - "" - "" - ""); - - QSvgRenderer renderer(data); - - QImage image(128, 128, QImage::Format_ARGB32_Premultiplied); - image.fill(0); + " " + " " + "", + // nonzero + "" + " " + " " + "", + // evenodd + "" + " " + " " + "", - QPainter painter(&image); - renderer.render(&painter); - painter.end(); + // Polygons + // Default fill-rule (nonzero) + "" + " " + " " + "", + // nonzero + "" + " " + " " + "", + // evenodd + "" + " " + " " + "" + }; - QCOMPARE(image.pixel(64, 64), QColor(Qt::red).rgba()); + const int COUNT = sizeof(svgs) / sizeof(svgs[0]); + QImage refImageNonZero(30, 30, QImage::Format_ARGB32_Premultiplied); + QImage refImageEvenOdd(30, 30, QImage::Format_ARGB32_Premultiplied); + refImageNonZero.fill(0xffff0000); + refImageEvenOdd.fill(0xffff0000); + QPainter p; + p.begin(&refImageNonZero); + p.fillRect(QRectF(0, 0, 10, 10), Qt::blue); + p.end(); + p.begin(&refImageEvenOdd); + p.fillRect(QRectF(0, 0, 10, 10), Qt::blue); + p.fillRect(QRectF(10, 10, 10, 10), Qt::blue); + p.end(); + + for (int i = 0; i < COUNT; ++i) { + QByteArray data(svgs[i]); + QSvgRenderer renderer(data); + QImage image(30, 30, QImage::Format_ARGB32_Premultiplied); + image.fill(0); + p.begin(&image); + renderer.render(&p); + p.end(); + QCOMPARE(image, i % 3 == 2 ? refImageEvenOdd : refImageNonZero); + } } QTEST_MAIN(tst_QSvgRenderer) -- cgit v0.12 From 6e057c7fce3718bcefc8ccae645aa3c377c7c587 Mon Sep 17 00:00:00 2001 From: Suneel BS Date: Fri, 8 May 2009 12:32:52 +0530 Subject: Clamped opacity to the range [0, 1] in the SVG module. Modified and autotest added by Kim. Reviewed-by: Kim --- src/svg/qsvghandler.cpp | 14 +++--- tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp | 74 ++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 7 deletions(-) diff --git a/src/svg/qsvghandler.cpp b/src/svg/qsvghandler.cpp index e2c1312..8185fc6 100644 --- a/src/svg/qsvghandler.cpp +++ b/src/svg/qsvghandler.cpp @@ -497,10 +497,8 @@ static bool constructColor(const QString &colorStr, const QString &opacity, if (!resolveColor(colorStr, color, handler)) return false; if (!opacity.isEmpty()) { - qreal op = toDouble(opacity); - if (op <= 1) - op *= 255; - color.setAlpha(int(op)); + qreal op = qMin(qreal(1.0), qMax(qreal(0.0), toDouble(opacity))); + color.setAlphaF(op); } return true; } @@ -644,8 +642,10 @@ static void parseBrush(QSvgNode *node, QSvgStyleProperty *style = styleFromUrl(node, value); if (style) { QSvgFillStyle *prop = new QSvgFillStyle(style); - if (!opacity.isEmpty()) - prop->setFillOpacity(toDouble(opacity)); + if (!opacity.isEmpty()) { + qreal clampedOpacity = qMin(qreal(1.0), qMax(qreal(0.0), toDouble(opacity))); + prop->setFillOpacity(clampedOpacity); + } node->appendStyleProperty(prop, myId); } else { qWarning("Couldn't resolve property: %s", qPrintable(idFromUrl(value))); @@ -1943,7 +1943,7 @@ static void parseOpacity(QSvgNode *node, qreal op = value.toDouble(&ok); if (ok) { - QSvgOpacityStyle *opacity = new QSvgOpacityStyle(op); + QSvgOpacityStyle *opacity = new QSvgOpacityStyle(qMin(qreal(1.0), qMax(qreal(0.0), op))); node->appendStyleProperty(opacity, someId(attributes)); } } diff --git a/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp b/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp index b148f8c..d1c11ed 100644 --- a/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp +++ b/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp @@ -76,6 +76,7 @@ private slots: void matrixForElement() const; void gradientStops() const; void fillRule(); + void opacity(); #ifndef QT_NO_COMPRESS void testGzLoading(); @@ -715,5 +716,78 @@ void tst_QSvgRenderer::fillRule() } } +static void opacity_drawSvgAndVerify(const QByteArray &data) +{ + QSvgRenderer renderer(data); + QVERIFY(renderer.isValid()); + QImage image(10, 10, QImage::Format_ARGB32_Premultiplied); + image.fill(0xffff00ff); + QPainter painter(&image); + renderer.render(&painter); + painter.end(); + QCOMPARE(image.pixel(5, 5), 0xff7f7f7f); +} + +void tst_QSvgRenderer::opacity() +{ + static const char *opacities[] = {"-1,4641", "0", "0.5", "1", "1.337"}; + static const char *firstColors[] = {"#7f7f7f", "#7f7f7f", "#402051", "blue", "#123456"}; + static const char *secondColors[] = {"red", "#bad", "#bedead", "#7f7f7f", "#7f7f7f"}; + + // Fill-opacity + for (int i = 0; i < 5; ++i) { + QByteArray data(""); + opacity_drawSvgAndVerify(data); + } + // Stroke-opacity + for (int i = 0; i < 5; ++i) { + QByteArray data(""); + opacity_drawSvgAndVerify(data); + } + // As gradients: + // Fill-opacity + for (int i = 0; i < 5; ++i) { + QByteArray data(""); + opacity_drawSvgAndVerify(data); + } + // When support for gradients on strokes has been implemented, add the code below. + /* + // Stroke-opacity + for (int i = 0; i < 5; ++i) { + QByteArray data(""); + opacity_drawSvgAndVerify(data); + } + */ +} + + QTEST_MAIN(tst_QSvgRenderer) #include "tst_qsvgrenderer.moc" -- cgit v0.12 From 87fc9a9a6fa74973a5812fb495615edb4df10e27 Mon Sep 17 00:00:00 2001 From: Suneel BS Date: Fri, 8 May 2009 10:03:53 +0530 Subject: Fixed path bug in the SVG module. In path, if 'moveto' is followed by multiple pairs of coordinates, those pairs shall be treated as 'lineto'. Autotest added by Kim. Reviewed-by: Kim --- src/svg/qsvghandler.cpp | 10 ++++++ tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp | 54 ++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/src/svg/qsvghandler.cpp b/src/svg/qsvghandler.cpp index 8185fc6..9486512 100644 --- a/src/svg/qsvghandler.cpp +++ b/src/svg/qsvghandler.cpp @@ -1377,6 +1377,11 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path) y = y0 = arg[1] + offsetY; path.moveTo(x0, y0); arg.pop_front(); arg.pop_front(); + + // As per 1.2 spec 8.3.2 The "moveto" commands + // If a 'moveto' is followed by multiple pairs of coordinates without explicit commands, + // the subsequent pairs shall be treated as implicit 'lineto' commands. + pathElem = QLatin1Char('l'); } break; case 'M': { @@ -1389,6 +1394,11 @@ static bool parsePathDataFast(const QStringRef &dataStr, QPainterPath &path) path.moveTo(x0, y0); arg.pop_front(); arg.pop_front(); + + // As per 1.2 spec 8.3.2 The "moveto" commands + // If a 'moveto' is followed by multiple pairs of coordinates without explicit commands, + // the subsequent pairs shall be treated as implicit 'lineto' commands. + pathElem = QLatin1Char('L'); } break; case 'z': diff --git a/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp b/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp index d1c11ed..c7bfee8 100644 --- a/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp +++ b/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp @@ -77,6 +77,7 @@ private slots: void gradientStops() const; void fillRule(); void opacity(); + void paths(); #ifndef QT_NO_COMPRESS void testGzLoading(); @@ -788,6 +789,59 @@ void tst_QSvgRenderer::opacity() */ } +void tst_QSvgRenderer::paths() +{ + static const char *svgs[] = { + // Absolute coordinates, explicit commands. + "" + " " + " " + "", + // Absolute coordinates, implicit commands. + "" + " " + " " + "", + // Relative coordinates, explicit commands. + "" + " " + " " + "", + // Relative coordinates, implicit commands. + "" + " " + " " + "", + // Absolute coordinates, explicit commands, minimal whitespace. + "" + " " + " " + "", + // Absolute coordinates, explicit commands, extra whitespace. + "" + " " + " " + "" + }; + + const int COUNT = sizeof(svgs) / sizeof(svgs[0]); + QImage images[COUNT]; + QPainter p; + + for (int i = 0; i < COUNT; ++i) { + QByteArray data(svgs[i]); + QSvgRenderer renderer(data); + QVERIFY(renderer.isValid()); + images[i] = QImage(50, 50, QImage::Format_ARGB32_Premultiplied); + images[i].fill(0); + p.begin(&images[i]); + renderer.render(&p); + p.end(); + if (i != 0) { + QCOMPARE(images[i], images[0]); + } + } +} QTEST_MAIN(tst_QSvgRenderer) #include "tst_qsvgrenderer.moc" -- cgit v0.12 From d6daae2c0dbab5c547f4bdec2d3bafe3a5ed62b6 Mon Sep 17 00:00:00 2001 From: Suneel BS Date: Thu, 7 May 2009 21:39:53 +0530 Subject: Fixed forward gradient reference in the SVG module. Autotest added by Kim. Task-number: 204686 Reviewed-by: Kim --- src/svg/qsvghandler.cpp | 47 +++++++++++++++++++++++----- src/svg/qsvgstyle.cpp | 4 +-- src/svg/qsvgstyle_p.h | 34 ++++++++++++++++++++ tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp | 16 ++++++++++ 4 files changed, 91 insertions(+), 10 deletions(-) diff --git a/src/svg/qsvghandler.cpp b/src/svg/qsvghandler.cpp index 9486512..345dcf3 100644 --- a/src/svg/qsvghandler.cpp +++ b/src/svg/qsvghandler.cpp @@ -639,17 +639,22 @@ static void parseBrush(QSvgNode *node, f = Qt::OddEvenFill; if (value.startsWith(QLatin1String("url"))) { value = value.remove(0, 3); + QSvgFillStyle *prop = new QSvgFillStyle(0); QSvgStyleProperty *style = styleFromUrl(node, value); if (style) { - QSvgFillStyle *prop = new QSvgFillStyle(style); - if (!opacity.isEmpty()) { - qreal clampedOpacity = qMin(qreal(1.0), qMax(qreal(0.0), toDouble(opacity))); - prop->setFillOpacity(clampedOpacity); - } - node->appendStyleProperty(prop, myId); + prop->setFillStyle(style); } else { - qWarning("Couldn't resolve property: %s", qPrintable(idFromUrl(value))); + QString id = idFromUrl(value); + prop->setGradientId(id); + prop->setGradientResolved(false); + } + if (!opacity.isEmpty()) { + qreal clampedOpacity = qMin(qreal(1.0), qMax(qreal(0.0), toDouble(opacity))); + prop->setFillOpacity(clampedOpacity); } + if (!fillRule.isEmpty()) + prop->setFillRule(f); + node->appendStyleProperty(prop,myId); } else if (value != QLatin1String("none")) { QColor color; if (constructColor(value, opacity, color, handler)) { @@ -3580,8 +3585,34 @@ bool QSvgHandler::endElement(const QStringRef &localName) node->popFormat(); } - if (node == Graphics) + if (node == Graphics) { + // Iterate through the m_renderers to resolve any unresolved gradients. + QSvgNode* curNode = static_cast(m_nodes.top()); + if (curNode->type() == QSvgNode::DOC || + curNode->type() == QSvgNode::G || + curNode->type() == QSvgNode::DEFS || + curNode->type() == QSvgNode::SWITCH) { + QSvgStructureNode* structureNode = static_cast(curNode); + QList ren = structureNode->renderers(); + QList::iterator itr = ren.begin(); + while (itr != ren.end()) { + QSvgNode *eleNode = *itr++; + QSvgFillStyle *prop = static_cast(eleNode->styleProperty(QSvgStyleProperty::FILL)); + if (prop && !(prop->isGradientResolved())) { + QString id = prop->getGradientId(); + QSvgStyleProperty *style = structureNode->scopeStyle(id); + if (style) { + prop->setFillStyle(style); + } else { + qWarning("Couldn't resolve property : %s",qPrintable(id)); + prop->setBrush(QBrush(Qt::NoBrush)); + } + } + } + } m_nodes.pop(); + } + else if (m_style && !m_skipNodes.isEmpty() && m_skipNodes.top() != Style) m_style = 0; diff --git a/src/svg/qsvgstyle.cpp b/src/svg/qsvgstyle.cpp index 9d46649..fec6231 100644 --- a/src/svg/qsvgstyle.cpp +++ b/src/svg/qsvgstyle.cpp @@ -81,12 +81,12 @@ void QSvgQualityStyle::revert(QPainter *, QSvgExtraStates &) } QSvgFillStyle::QSvgFillStyle(const QBrush &brush) - : m_fill(brush), m_style(0), m_fillRuleSet(false), m_fillOpacitySet(false) + : m_fill(brush), m_style(0), m_fillRuleSet(false), m_fillOpacitySet(false), m_gradientResolved (true) { } QSvgFillStyle::QSvgFillStyle(QSvgStyleProperty *style) - : m_style(style), m_fillRuleSet(false), m_fillOpacitySet(false) + : m_style(style), m_fillRuleSet(false), m_fillOpacitySet(false), m_gradientResolved (true) { } diff --git a/src/svg/qsvgstyle_p.h b/src/svg/qsvgstyle_p.h index 4bbc6cf..e65b6f5 100644 --- a/src/svg/qsvgstyle_p.h +++ b/src/svg/qsvgstyle_p.h @@ -229,6 +229,38 @@ public: { return m_fill; } + + void setGradientId(const QString &Id) + { + m_gradientId = Id; + } + + QString getGradientId() const + { + return m_gradientId; + } + + + void setGradientResolved(bool resolved) + { + m_gradientResolved = resolved; + } + + bool isGradientResolved() const + { + return m_gradientResolved; + } + + void setFillStyle(QSvgStyleProperty* style) + { + m_style = style; + } + + void setBrush(QBrush brush) + { + m_fill = brush; + } + private: // fill v v 'inherit' | // fill-opacity v v 'inherit' | @@ -241,6 +273,8 @@ private: bool m_fillOpacitySet; qreal m_fillOpacity; qreal m_oldOpacity; + QString m_gradientId; + bool m_gradientResolved; }; class QSvgViewportFillStyle : public QSvgStyleProperty diff --git a/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp b/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp index c7bfee8..820bcba 100644 --- a/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp +++ b/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp @@ -75,6 +75,7 @@ private slots: void stylePropagation() const; void matrixForElement() const; void gradientStops() const; + void gradientRefs(); void fillRule(); void opacity(); void paths(); @@ -535,7 +536,10 @@ void tst_QSvgRenderer::gradientStops() const QCOMPARE(image, refImage); } +} +void tst_QSvgRenderer::gradientRefs() +{ const char *svgs[] = { "" "" @@ -567,6 +571,17 @@ void tst_QSvgRenderer::gradientStops() const "" "" "" + "", + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" "" }; for (int i = 0 ; i < sizeof(svgs) / sizeof(svgs[0]) ; ++i) @@ -591,6 +606,7 @@ void tst_QSvgRenderer::gradientStops() const } } + #ifndef QT_NO_COMPRESS void tst_QSvgRenderer::testGzLoading() { -- cgit v0.12 From d910b0c8a184ed53531c80deb26b27dd762c133e Mon Sep 17 00:00:00 2001 From: Suneel BS Date: Thu, 7 May 2009 20:12:04 +0530 Subject: Fixed bug in the SVG module where display="none" was not respected. Elements with display="none" should not be rendered. Modified and autotest added by Kim. Reviewed-by: Kim --- src/svg/qsvgstructure.cpp | 98 +++++++++++++--------------- src/svg/qsvgtinydocument.cpp | 12 +++- tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp | 66 +++++++++++++++++++ 3 files changed, 123 insertions(+), 53 deletions(-) diff --git a/src/svg/qsvgstructure.cpp b/src/svg/qsvgstructure.cpp index 67a21bf..c1ad4bf 100644 --- a/src/svg/qsvgstructure.cpp +++ b/src/svg/qsvgstructure.cpp @@ -68,13 +68,11 @@ void QSvgG::draw(QPainter *p, QSvgExtraStates &states) QList::iterator itr = m_renderers.begin(); applyStyle(p, states); - if (displayMode() != QSvgNode::NoneMode) { - while (itr != m_renderers.end()) { - QSvgNode *node = *itr; - if (node->isVisible()) - node->draw(p, states); - ++itr; - } + while (itr != m_renderers.end()) { + QSvgNode *node = *itr; + if ((node->isVisible()) && (node->displayMode() != QSvgNode::NoneMode)) + node->draw(p, states); + ++itr; } revertStyle(p, states); } @@ -321,63 +319,61 @@ void QSvgSwitch::draw(QPainter *p, QSvgExtraStates &states) QList::iterator itr = m_renderers.begin(); applyStyle(p, states); - if (displayMode() != QSvgNode::NoneMode) { - while (itr != m_renderers.end()) { - QSvgNode *node = *itr; - if (node->isVisible()) { - const QStringList &features = node->requiredFeatures(); - const QStringList &extensions = node->requiredExtensions(); - const QStringList &languages = node->requiredLanguages(); - const QStringList &formats = node->requiredFormats(); - const QStringList &fonts = node->requiredFonts(); - - bool okToRender = true; - if (!features.isEmpty()) { - QStringList::const_iterator sitr = features.constBegin(); - for (; sitr != features.constEnd(); ++sitr) { - if (!isSupportedSvgFeature(*sitr)) { - okToRender = false; - break; - } + while (itr != m_renderers.end()) { + QSvgNode *node = *itr; + if (node->isVisible() && (node->displayMode() != QSvgNode::NoneMode)) { + const QStringList &features = node->requiredFeatures(); + const QStringList &extensions = node->requiredExtensions(); + const QStringList &languages = node->requiredLanguages(); + const QStringList &formats = node->requiredFormats(); + const QStringList &fonts = node->requiredFonts(); + + bool okToRender = true; + if (!features.isEmpty()) { + QStringList::const_iterator sitr = features.constBegin(); + for (; sitr != features.constEnd(); ++sitr) { + if (!isSupportedSvgFeature(*sitr)) { + okToRender = false; + break; } } + } - if (okToRender && !extensions.isEmpty()) { - QStringList::const_iterator sitr = extensions.constBegin(); - for (; sitr != extensions.constEnd(); ++sitr) { - if (!isSupportedSvgExtension(*sitr)) { - okToRender = false; - break; - } + if (okToRender && !extensions.isEmpty()) { + QStringList::const_iterator sitr = extensions.constBegin(); + for (; sitr != extensions.constEnd(); ++sitr) { + if (!isSupportedSvgExtension(*sitr)) { + okToRender = false; + break; } } + } - if (okToRender && !languages.isEmpty()) { - QStringList::const_iterator sitr = languages.constBegin(); - okToRender = false; - for (; sitr != languages.constEnd(); ++sitr) { - if ((*sitr).startsWith(m_systemLanguagePrefix)) { - okToRender = true; - break; - } + if (okToRender && !languages.isEmpty()) { + QStringList::const_iterator sitr = languages.constBegin(); + okToRender = false; + for (; sitr != languages.constEnd(); ++sitr) { + if ((*sitr).startsWith(m_systemLanguagePrefix)) { + okToRender = true; + break; } } + } - if (okToRender && !formats.isEmpty()) { - okToRender = false; - } + if (okToRender && !formats.isEmpty()) { + okToRender = false; + } - if (okToRender && !fonts.isEmpty()) { - okToRender = false; - } + if (okToRender && !fonts.isEmpty()) { + okToRender = false; + } - if (okToRender) { - node->draw(p, states); - break; - } + if (okToRender) { + node->draw(p, states); + break; } - ++itr; } + ++itr; } revertStyle(p, states); } diff --git a/src/svg/qsvgtinydocument.cpp b/src/svg/qsvgtinydocument.cpp index de214bb..3058569 100644 --- a/src/svg/qsvgtinydocument.cpp +++ b/src/svg/qsvgtinydocument.cpp @@ -231,8 +231,10 @@ void QSvgTinyDocument::draw(QPainter *p, const QRectF &bounds) m_time.start(); } - p->save(); + if (displayMode() == QSvgNode::NoneMode) + return; + p->save(); //sets default style on the painter //### not the most optimal way mapSourceToTarget(p, bounds); @@ -244,7 +246,7 @@ void QSvgTinyDocument::draw(QPainter *p, const QRectF &bounds) applyStyle(p, m_states); while (itr != m_renderers.end()) { QSvgNode *node = *itr; - if (node->isVisible()) + if ((node->isVisible()) && (node->displayMode() != QSvgNode::NoneMode)) node->draw(p, m_states); ++itr; } @@ -262,6 +264,12 @@ void QSvgTinyDocument::draw(QPainter *p, const QString &id, qDebug("Couldn't find node %s. Skipping rendering.", qPrintable(id)); return; } + if (m_time.isNull()) { + m_time.start(); + } + + if (node->displayMode() == QSvgNode::NoneMode) + return; p->save(); diff --git a/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp b/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp index 820bcba..f11aff9 100644 --- a/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp +++ b/tests/auto/qsvgrenderer/tst_qsvgrenderer.cpp @@ -79,6 +79,7 @@ private slots: void fillRule(); void opacity(); void paths(); + void displayMode(); #ifndef QT_NO_COMPRESS void testGzLoading(); @@ -859,5 +860,70 @@ void tst_QSvgRenderer::paths() } } +void tst_QSvgRenderer::displayMode() +{ + static const char *svgs[] = { + // All visible. + "" + " " + " " + " " + " " + "", + // Don't display svg element. + "" + " " + " " + " " + " " + "", + // Don't display g element. + "" + " " + " " + " " + " " + "", + // Don't display first rect element. + "" + " " + " " + " " + " " + "", + // Don't display second rect element. + "" + " " + " " + " " + " " + "", + // Don't display svg element, but set display mode to "inline" for other elements. + "" + " " + " " + " " + " " + "" + }; + + QRgb expectedColors[] = {0xff0000ff, 0xff00ff00, 0xff00ff00, 0xff0000ff, 0xffff0000, 0xff00ff00}; + + const int COUNT = sizeof(svgs) / sizeof(svgs[0]); + QPainter p; + + for (int i = 0; i < COUNT; ++i) { + QByteArray data(svgs[i]); + QSvgRenderer renderer(data); + QVERIFY(renderer.isValid()); + QImage image(10, 10, QImage::Format_ARGB32_Premultiplied); + image.fill(0xff00ff00); + p.begin(&image); + renderer.render(&p); + p.end(); + QCOMPARE(image.pixel(5, 5), expectedColors[i]); + } +} + QTEST_MAIN(tst_QSvgRenderer) #include "tst_qsvgrenderer.moc" -- cgit v0.12 From fbc9a2e0a429e5fc2b178ab3875c2e3550129c12 Mon Sep 17 00:00:00 2001 From: Harald Fernengel Date: Mon, 22 Jun 2009 16:45:29 +0200 Subject: Mention -maxwarnings in debug output Fixes the very frequently asked question "how do I see the full output?" --- src/testlib/qtestlog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/testlib/qtestlog.cpp b/src/testlib/qtestlog.cpp index 4a9675a..64c1312 100644 --- a/src/testlib/qtestlog.cpp +++ b/src/testlib/qtestlog.cpp @@ -139,7 +139,7 @@ namespace QTest { if (!counter.deref()) { QTest::testLogger->addMessage(QAbstractTestLogger::QSystem, - "Maximum amount of warnings exceeded."); + "Maximum amount of warnings exceeded. Use -maxwarnings to override."); return; } } -- cgit v0.12 From 308ed3913b406c43dfdab4fa734a332863dc4cbc Mon Sep 17 00:00:00 2001 From: Thierry Bastian Date: Mon, 22 Jun 2009 14:50:05 +0200 Subject: QDockWidget: removed separator for not resizable dock widget Task-number: 212058 --- src/gui/widgets/qdockarealayout.cpp | 99 ++++++++++++++++++---------------- src/gui/widgets/qdockarealayout_p.h | 6 ++- src/gui/widgets/qmainwindowlayout.cpp | 4 +- src/gui/widgets/qtoolbararealayout.cpp | 4 +- 4 files changed, 61 insertions(+), 52 deletions(-) diff --git a/src/gui/widgets/qdockarealayout.cpp b/src/gui/widgets/qdockarealayout.cpp index 135bcda..3125304 100644 --- a/src/gui/widgets/qdockarealayout.cpp +++ b/src/gui/widgets/qdockarealayout.cpp @@ -155,6 +155,11 @@ QSize QDockAreaLayoutItem::maximumSize() const return QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); } +bool QDockAreaLayoutItem::hasFixedSize(Qt::Orientation o) const +{ + return perp(o, minimumSize()) == perp(o, maximumSize()); +} + bool QDockAreaLayoutItem::expansive(Qt::Orientation o) const { if ((flags & GapItem) || placeHolderItem != 0) @@ -216,7 +221,7 @@ static quintptr tabId(const QDockAreaLayoutItem &item) #endif QDockAreaLayoutInfo::QDockAreaLayoutInfo() - : sep(0), dockPos(QInternal::LeftDock), o(Qt::Horizontal), rect(0, 0, -1, -1), mainWindow(0) + : sep(0), dockPos(QInternal::LeftDock), o(Qt::Horizontal), mainWindow(0) #ifndef QT_NO_TABBAR , tabbed(false), tabBar(0), tabBarShape(QTabBar::RoundedSouth) #endif @@ -226,7 +231,7 @@ QDockAreaLayoutInfo::QDockAreaLayoutInfo() QDockAreaLayoutInfo::QDockAreaLayoutInfo(int _sep, QInternal::DockPosition _dockPos, Qt::Orientation _o, int tbshape, QMainWindow *window) - : sep(_sep), dockPos(_dockPos), o(_o), rect(0, 0, -1, -1), mainWindow(window) + : sep(_sep), dockPos(_dockPos), o(_o), mainWindow(window) #ifndef QT_NO_TABBAR , tabbed(false), tabBar(0), tabBarShape(static_cast(tbshape)) #endif @@ -244,7 +249,7 @@ QSize QDockAreaLayoutInfo::size() const void QDockAreaLayoutInfo::clear() { item_list.clear(); - rect = QRect(0, 0, -1, -1); + rect = QRect(); #ifndef QT_NO_TABBAR tabbed = false; tabBar = 0; @@ -388,10 +393,9 @@ QSize QDockAreaLayoutInfo::sizeHint() const return QSize(0, 0); int a = 0, b = 0; - bool prev_gap = false; - bool first = true; int min_perp = 0; int max_perp = QWIDGETSIZE_MAX; + const QDockAreaLayoutItem *previous = 0; for (int i = 0; i < item_list.size(); ++i) { const QDockAreaLayoutItem &item = item_list.at(i); if (item.skip()) @@ -409,14 +413,15 @@ QSize QDockAreaLayoutInfo::sizeHint() const } else #endif { - if (!first && !gap && !prev_gap) + if (previous && !gap && !(previous->flags & QDockAreaLayoutItem::GapItem) + && !previous->hasFixedSize(o)) { a += sep; + } a += gap ? item.size : pick(o, size_hint); } b = qMax(b, perp(o, size_hint)); - prev_gap = gap; - first = false; + previous = &item; } max_perp = qMax(max_perp, min_perp); @@ -539,21 +544,20 @@ void QDockAreaLayoutInfo::fitItems() int max_size = realMaxSize(*this); int last_index = -1; - bool prev_gap = false; - bool first = true; + const QDockAreaLayoutItem *previous = 0; for (int i = 0; i < item_list.size(); ++i) { QDockAreaLayoutItem &item = item_list[i]; if (item.skip()) continue; bool gap = item.flags & QDockAreaLayoutItem::GapItem; - if (!first && !gap && !prev_gap) { - QLayoutStruct &ls = layout_struct_list[j++]; - ls.init(); - ls.minimumSize = sep; - ls.maximumSize = sep; - ls.sizeHint = sep; - ls.empty = false; + if (previous && !gap) { + if (!(previous->flags & QDockAreaLayoutItem::GapItem)) { + QLayoutStruct &ls = layout_struct_list[j++]; + ls.init(); + ls.minimumSize = ls.maximumSize = ls.sizeHint = previous->hasFixedSize(o) ? 0 : sep; + ls.empty = false; + } } if (item.flags & QDockAreaLayoutItem::KeepSize) { @@ -592,8 +596,7 @@ void QDockAreaLayoutInfo::fitItems() } item.flags &= ~QDockAreaLayoutItem::KeepSize; - prev_gap = gap; - first = false; + previous = &item; } layout_struct_list.resize(j); @@ -607,8 +610,8 @@ void QDockAreaLayoutInfo::fitItems() qGeomCalc(layout_struct_list, 0, j, pick(o, rect.topLeft()), size, 0); j = 0; - prev_gap = false; - first = true; + bool prev_gap = false; + bool first = true; for (int i = 0; i < item_list.size(); ++i) { QDockAreaLayoutItem &item = item_list[i]; if (item.skip()) @@ -1408,11 +1411,12 @@ QList QDockAreaLayoutInfo::findSeparator(const QPoint &_pos) const if (next == -1 || (item_list.at(next).flags & QDockAreaLayoutItem::GapItem)) continue; - int margin = (sep == 1? 2 : 0); - if (pos >= item.pos + item.size - margin && item.pos + item.size + sep + margin > pos) { - QList result; - result.append(i); - return result; + QRect sepRect = separatorRect(i); + if (!sepRect.isNull() && sep == 1) + sepRect.adjust(-2, -2, 2, 2); + //we also make sure we don't find a separator that's not there + if (sepRect.contains(_pos) && !item.hasFixedSize(o)) { + return QList() << i; } } @@ -1478,6 +1482,12 @@ QMainWindowLayout *QDockAreaLayoutInfo::mainWindowLayout() const return result; } +bool QDockAreaLayoutInfo::hasFixedSize() const +{ + return perp(o, minimumSize()) == perp(o, maximumSize()); +} + + void QDockAreaLayoutInfo::apply(bool animate) { QWidgetAnimator *widgetAnimator = mainWindowLayout()->widgetAnimator; @@ -1629,7 +1639,7 @@ void QDockAreaLayoutInfo::paintSeparators(QPainter *p, QWidget *widget, if (next == -1) break; QRect r = separatorRect(i); - if (clip.contains(r)) + if (clip.contains(r) && !item.hasFixedSize(o)) paintSep(p, widget, r, o, r.contains(mouse)); } } @@ -2009,10 +2019,8 @@ bool QDockAreaLayoutInfo::restoreState(QDataStream &stream, QList void QDockAreaLayoutInfo::updateSeparatorWidgets() const { - QDockAreaLayoutInfo *that = const_cast(this); - if (tabbed) { - that->separatorWidgets.clear(); + separatorWidgets.clear(); return; } @@ -2040,7 +2048,7 @@ void QDockAreaLayoutInfo::updateSeparatorWidgets() const sepWidget = separatorWidgets.at(j); } else { sepWidget = mainWindowLayout()->getSeparatorWidget(); - that->separatorWidgets.append(sepWidget); + separatorWidgets.append(sepWidget); } j++; @@ -2053,10 +2061,10 @@ void QDockAreaLayoutInfo::updateSeparatorWidgets() const sepWidget->show(); } - for (int k = j; k < that->separatorWidgets.size(); ++k) { - that->separatorWidgets[k]->hide(); + for (int k = j; k < separatorWidgets.size(); ++k) { + separatorWidgets[k]->hide(); } - that->separatorWidgets.resize(j); + separatorWidgets.resize(j); Q_ASSERT(separatorWidgets.size() == j); } @@ -2271,7 +2279,7 @@ QDockAreaLayout::QDockAreaLayout(QMainWindow *win) docks[QInternal::BottomDock] = QDockAreaLayoutInfo(sep, QInternal::BottomDock, Qt::Horizontal, tabShape, win); centralWidgetItem = 0; - centralWidgetRect = QRect(0, 0, -1, -1); + corners[Qt::TopLeftCorner] = Qt::TopDockWidgetArea; corners[Qt::TopRightCorner] = Qt::TopDockWidgetArea; @@ -2442,9 +2450,9 @@ QList QDockAreaLayout::findSeparator(const QPoint &pos) const if (info.isEmpty()) continue; QRect rect = separatorRect(i); - if (sep == 1) + if (!rect.isNull() && sep == 1) rect.adjust(-2, -2, 2, 2); - if (rect.contains(pos)) { + if (rect.contains(pos) && !info.hasFixedSize()) { result << i; break; } else if (info.rect.contains(pos)) { @@ -2504,9 +2512,10 @@ QRect QDockAreaLayout::itemRect(QList path) const QRect QDockAreaLayout::separatorRect(int index) const { - if (docks[index].isEmpty()) + const QDockAreaLayoutInfo &dock = docks[index]; + if (dock.isEmpty()) return QRect(); - QRect r = docks[index].rect; + QRect r = dock.rect; switch (index) { case QInternal::LeftDock: return QRect(r.right() + 1, r.top(), sep, r.height()); @@ -2854,8 +2863,8 @@ void QDockAreaLayout::clear() for (int i = 0; i < QInternal::DockCount; ++i) docks[i].clear(); - rect = QRect(0, 0, -1, -1); - centralWidgetRect = QRect(0, 0, -1, -1); + rect = QRect(); + centralWidgetRect = QRect(); } QSize QDockAreaLayout::sizeHint() const @@ -3080,7 +3089,7 @@ void QDockAreaLayout::paintSeparators(QPainter *p, QWidget *widget, if (dock.isEmpty()) continue; QRect r = separatorRect(i); - if (clip.contains(r)) { + if (clip.contains(r) && !dock.hasFixedSize()) { Qt::Orientation opposite = dock.o == Qt::Horizontal ? Qt::Vertical : Qt::Horizontal; paintSep(p, widget, r, opposite, r.contains(mouse)); @@ -3154,8 +3163,6 @@ int QDockAreaLayout::separatorMove(QList separator, const QPoint &origin, // Allocates new sepearator widgets with getSeparatorWidget void QDockAreaLayout::updateSeparatorWidgets() const { - QDockAreaLayout *that = const_cast(this); - int j = 0; for (int i = 0; i < QInternal::DockCount; ++i) { @@ -3168,7 +3175,7 @@ void QDockAreaLayout::updateSeparatorWidgets() const sepWidget = separatorWidgets.at(j); } else { sepWidget = qobject_cast(mainWindow->layout())->getSeparatorWidget(); - that->separatorWidgets.append(sepWidget); + separatorWidgets.append(sepWidget); } j++; @@ -3183,7 +3190,7 @@ void QDockAreaLayout::updateSeparatorWidgets() const for (int i = j; i < separatorWidgets.size(); ++i) separatorWidgets.at(i)->hide(); - that->separatorWidgets.resize(j); + separatorWidgets.resize(j); } QLayoutItem *QDockAreaLayout::itemAt(int *x, int index) const diff --git a/src/gui/widgets/qdockarealayout_p.h b/src/gui/widgets/qdockarealayout_p.h index 0b8d832..137aeba 100644 --- a/src/gui/widgets/qdockarealayout_p.h +++ b/src/gui/widgets/qdockarealayout_p.h @@ -103,6 +103,7 @@ struct QDockAreaLayoutItem QSize maximumSize() const; QSize sizeHint() const; bool expansive(Qt::Orientation o) const; + bool hasFixedSize(Qt::Orientation o) const; QLayoutItem *widgetItem; QDockAreaLayoutInfo *subinfo; @@ -167,6 +168,7 @@ public: void clear(); bool isEmpty() const; + bool hasFixedSize() const; QList findSeparator(const QPoint &pos) const; int next(int idx) const; int prev(int idx) const; @@ -188,7 +190,7 @@ public: QMainWindowLayout *mainWindowLayout() const; int sep; - QVector separatorWidgets; + mutable QVector separatorWidgets; QInternal::DockPosition dockPos; Qt::Orientation o; QRect rect; @@ -231,7 +233,7 @@ public: QDockAreaLayout(QMainWindow *win); QDockAreaLayoutInfo docks[4]; int sep; // separator extent - QVector separatorWidgets; + mutable QVector separatorWidgets; bool isValid() const; diff --git a/src/gui/widgets/qmainwindowlayout.cpp b/src/gui/widgets/qmainwindowlayout.cpp index 308f956..10e07d3 100644 --- a/src/gui/widgets/qmainwindowlayout.cpp +++ b/src/gui/widgets/qmainwindowlayout.cpp @@ -490,10 +490,10 @@ void QMainWindowLayoutState::clear() #ifndef QT_NO_DOCKWIDGET dockAreaLayout.clear(); #else - centralWidgetRect = QRect(0, 0, -1, -1); + centralWidgetRect = QRect(); #endif - rect = QRect(0, 0, -1, -1); + rect = QRect(); } bool QMainWindowLayoutState::isValid() const diff --git a/src/gui/widgets/qtoolbararealayout.cpp b/src/gui/widgets/qtoolbararealayout.cpp index aaab885..8a10355 100644 --- a/src/gui/widgets/qtoolbararealayout.cpp +++ b/src/gui/widgets/qtoolbararealayout.cpp @@ -567,7 +567,7 @@ bool QToolBarAreaLayoutInfo::insertGap(QList path, QLayoutItem *item) void QToolBarAreaLayoutInfo::clear() { lines.clear(); - rect = QRect(0, 0, -1, -1); + rect = QRect(); } QRect QToolBarAreaLayoutInfo::itemRect(QList path) const @@ -1101,7 +1101,7 @@ void QToolBarAreaLayout::clear() { for (int i = 0; i < QInternal::DockCount; ++i) docks[i].clear(); - rect = QRect(0, 0, -1, -1); + rect = QRect(); } QToolBarAreaLayoutItem &QToolBarAreaLayout::item(QList path) -- cgit v0.12 From 4360626c48c90b4d1928398b964679b3acde8cc4 Mon Sep 17 00:00:00 2001 From: Rhys Weatherley Date: Tue, 23 Jun 2009 09:54:49 +1000 Subject: Integrate the OpenVG graphics system into Qt 4.6 This change also moves the EGL support classes from QtOpenGL to QtGui so they can be shared between OpenGL and OpenVG. --- bin/syncqt | 2 + config.tests/unix/egl/egl.cpp | 10 + config.tests/unix/egl/egl.pro | 10 + config.tests/unix/egl4gles1/egl4gles1.cpp | 10 + config.tests/unix/egl4gles1/egl4gles1.pro | 10 + config.tests/unix/opengles1/opengles1.cpp | 2 - config.tests/unix/opengles1cl/opengles1cl.cpp | 2 - config.tests/unix/opengles2/opengles2.cpp | 2 - config.tests/unix/openvg/openvg.cpp | 16 + config.tests/unix/openvg/openvg.pro | 11 + config.tests/unix/shivavg/shivavg.cpp | 10 + config.tests/unix/shivavg/shivavg.pro | 7 + configure | 131 +- doc/src/modules.qdoc | 1 + doc/src/qtopengl.qdoc | 2 +- doc/src/qtopenvg.qdoc | 73 + mkspecs/common/linux.conf | 3 + mkspecs/features/egl.prf | 3 + mkspecs/features/qt.prf | 3 +- mkspecs/features/unix/openvg.prf | 3 + mkspecs/features/win32/openvg.prf | 3 + src/corelib/global/qglobal.h | 12 + src/gui/egl/egl.pri | 28 + src/gui/egl/qegl.cpp | 403 +++ src/gui/egl/qegl_p.h | 140 + src/gui/egl/qegl_qws.cpp | 111 + src/gui/egl/qegl_symbian.cpp | 109 + src/gui/egl/qegl_wince.cpp | 116 + src/gui/egl/qegl_x11.cpp | 144 + src/gui/egl/qeglproperties.cpp | 496 +++ src/gui/egl/qeglproperties_p.h | 138 + src/gui/gui.pro | 2 + src/opengl/opengl.pro | 17 +- src/opengl/qegl.cpp | 842 ----- src/opengl/qegl_p.h | 188 -- src/opengl/qegl_qws.cpp | 125 - src/opengl/qegl_wince.cpp | 105 - src/opengl/qegl_x11egl.cpp | 133 - src/opengl/qgl_egl_p.h | 2 +- src/opengl/qgl_qws.cpp | 61 +- src/opengl/qgl_wince.cpp | 4 +- src/opengl/qgl_x11egl.cpp | 6 +- src/opengl/qglpixelbuffer_egl.cpp | 10 +- src/openvg/openvg.pro | 48 + src/openvg/qpaintengine_vg.cpp | 3231 ++++++++++++++++++++ src/openvg/qpaintengine_vg_p.h | 163 + src/openvg/qpixmapdata_vg.cpp | 344 +++ src/openvg/qpixmapdata_vg_p.h | 113 + src/openvg/qpixmapfilter_vg.cpp | 340 ++ src/openvg/qpixmapfilter_vg_p.h | 108 + src/openvg/qvg.h | 65 + src/openvg/qvg_p.h | 110 + src/openvg/qvgcompositionhelper_p.h | 91 + src/openvg/qwindowsurface_vg.cpp | 120 + src/openvg/qwindowsurface_vg_p.h | 92 + src/openvg/qwindowsurface_vgegl.cpp | 751 +++++ src/openvg/qwindowsurface_vgegl_p.h | 163 + src/plugins/graphicssystems/graphicssystems.pro | 6 + src/plugins/graphicssystems/openvg/main.cpp | 71 + src/plugins/graphicssystems/openvg/openvg.pro | 20 + .../graphicssystems/openvg/qgraphicssystem_vg.cpp | 70 + .../graphicssystems/openvg/qgraphicssystem_vg_p.h | 71 + src/plugins/graphicssystems/shivavg/README | 8 + src/plugins/graphicssystems/shivavg/main.cpp | 71 + src/plugins/graphicssystems/shivavg/shivavg.pro | 16 + .../shivavg/shivavggraphicssystem.cpp | 62 + .../shivavg/shivavggraphicssystem.h | 60 + .../shivavg/shivavgwindowsurface.cpp | 370 +++ .../graphicssystems/shivavg/shivavgwindowsurface.h | 76 + src/src.pro | 4 + tests/arthur/common/qengines.cpp | 1 + tools/qdoc3/test/qt-cpp-ignore.qdocconf | 2 + 72 files changed, 8715 insertions(+), 1438 deletions(-) create mode 100644 config.tests/unix/egl/egl.cpp create mode 100644 config.tests/unix/egl/egl.pro create mode 100644 config.tests/unix/egl4gles1/egl4gles1.cpp create mode 100644 config.tests/unix/egl4gles1/egl4gles1.pro create mode 100644 config.tests/unix/openvg/openvg.cpp create mode 100644 config.tests/unix/openvg/openvg.pro create mode 100644 config.tests/unix/shivavg/shivavg.cpp create mode 100644 config.tests/unix/shivavg/shivavg.pro create mode 100644 doc/src/qtopenvg.qdoc create mode 100644 mkspecs/features/egl.prf create mode 100644 mkspecs/features/unix/openvg.prf create mode 100644 mkspecs/features/win32/openvg.prf create mode 100644 src/gui/egl/egl.pri create mode 100644 src/gui/egl/qegl.cpp create mode 100644 src/gui/egl/qegl_p.h create mode 100644 src/gui/egl/qegl_qws.cpp create mode 100644 src/gui/egl/qegl_symbian.cpp create mode 100644 src/gui/egl/qegl_wince.cpp create mode 100644 src/gui/egl/qegl_x11.cpp create mode 100644 src/gui/egl/qeglproperties.cpp create mode 100644 src/gui/egl/qeglproperties_p.h delete mode 100644 src/opengl/qegl.cpp delete mode 100644 src/opengl/qegl_p.h delete mode 100644 src/opengl/qegl_qws.cpp delete mode 100644 src/opengl/qegl_wince.cpp delete mode 100644 src/opengl/qegl_x11egl.cpp create mode 100644 src/openvg/openvg.pro create mode 100644 src/openvg/qpaintengine_vg.cpp create mode 100644 src/openvg/qpaintengine_vg_p.h create mode 100644 src/openvg/qpixmapdata_vg.cpp create mode 100644 src/openvg/qpixmapdata_vg_p.h create mode 100644 src/openvg/qpixmapfilter_vg.cpp create mode 100644 src/openvg/qpixmapfilter_vg_p.h create mode 100644 src/openvg/qvg.h create mode 100644 src/openvg/qvg_p.h create mode 100644 src/openvg/qvgcompositionhelper_p.h create mode 100644 src/openvg/qwindowsurface_vg.cpp create mode 100644 src/openvg/qwindowsurface_vg_p.h create mode 100644 src/openvg/qwindowsurface_vgegl.cpp create mode 100644 src/openvg/qwindowsurface_vgegl_p.h create mode 100644 src/plugins/graphicssystems/openvg/main.cpp create mode 100644 src/plugins/graphicssystems/openvg/openvg.pro create mode 100644 src/plugins/graphicssystems/openvg/qgraphicssystem_vg.cpp create mode 100644 src/plugins/graphicssystems/openvg/qgraphicssystem_vg_p.h create mode 100644 src/plugins/graphicssystems/shivavg/README create mode 100644 src/plugins/graphicssystems/shivavg/main.cpp create mode 100644 src/plugins/graphicssystems/shivavg/shivavg.pro create mode 100644 src/plugins/graphicssystems/shivavg/shivavggraphicssystem.cpp create mode 100644 src/plugins/graphicssystems/shivavg/shivavggraphicssystem.h create mode 100644 src/plugins/graphicssystems/shivavg/shivavgwindowsurface.cpp create mode 100644 src/plugins/graphicssystems/shivavg/shivavgwindowsurface.h diff --git a/bin/syncqt b/bin/syncqt index f58a4d1..2fe5329 100755 --- a/bin/syncqt +++ b/bin/syncqt @@ -24,6 +24,7 @@ $basedir =~ s=\\=/=g; my %modules = ( # path to module name map "QtGui" => "$basedir/src/gui", "QtOpenGL" => "$basedir/src/opengl", + "QtOpenVG" => "$basedir/src/openvg", "QtCore" => "$basedir/src/corelib", "QtXml" => "$basedir/src/xml", "QtXmlPatterns" => "$basedir/src/xmlpatterns", @@ -689,6 +690,7 @@ foreach (@modules_to_sync) { $master_contents .= "#include \n" if("$_" eq "xml"); $master_contents .= "#include \n" if("$_" eq "xmlpatterns"); $master_contents .= "#include \n" if("$_" eq "opengl"); + $master_contents .= "#include \n" if("$_" eq "openvg"); } } } diff --git a/config.tests/unix/egl/egl.cpp b/config.tests/unix/egl/egl.cpp new file mode 100644 index 0000000..0c7f32c --- /dev/null +++ b/config.tests/unix/egl/egl.cpp @@ -0,0 +1,10 @@ +#include + +int main(int, char **) +{ + EGLint x = 0; + EGLDisplay dpy = 0; + EGLContext ctx = 0; + eglDestroyContext(dpy, ctx); + return 0; +} diff --git a/config.tests/unix/egl/egl.pro b/config.tests/unix/egl/egl.pro new file mode 100644 index 0000000..f04d053 --- /dev/null +++ b/config.tests/unix/egl/egl.pro @@ -0,0 +1,10 @@ +SOURCES = egl.cpp + +for(p, QMAKE_LIBDIR_EGL) { + exists($$p):LIBS += -L$$p +} + +!isEmpty(QMAKE_INCDIR_EGL): INCLUDEPATH += $$QMAKE_INCDIR_EGL +!isEmpty(QMAKE_LIBS_EGL): LIBS += $$QMAKE_LIBS_EGL + +CONFIG -= qt diff --git a/config.tests/unix/egl4gles1/egl4gles1.cpp b/config.tests/unix/egl4gles1/egl4gles1.cpp new file mode 100644 index 0000000..c1acb90 --- /dev/null +++ b/config.tests/unix/egl4gles1/egl4gles1.cpp @@ -0,0 +1,10 @@ +#include + +int main(int, char **) +{ + EGLint x = 0; + EGLDisplay dpy = 0; + EGLContext ctx = 0; + eglDestroyContext(dpy, ctx); + return 0; +} diff --git a/config.tests/unix/egl4gles1/egl4gles1.pro b/config.tests/unix/egl4gles1/egl4gles1.pro new file mode 100644 index 0000000..667ea8e --- /dev/null +++ b/config.tests/unix/egl4gles1/egl4gles1.pro @@ -0,0 +1,10 @@ +SOURCES = egl4gles1.cpp + +for(p, QMAKE_LIBDIR_EGL) { + exists($$p):LIBS += -L$$p +} + +!isEmpty(QMAKE_INCDIR_EGL): INCLUDEPATH += $$QMAKE_INCDIR_EGL +!isEmpty(QMAKE_LIBS_EGL): LIBS += $$QMAKE_LIBS_EGL + +CONFIG -= qt diff --git a/config.tests/unix/opengles1/opengles1.cpp b/config.tests/unix/opengles1/opengles1.cpp index a0060b4..de690c9 100644 --- a/config.tests/unix/opengles1/opengles1.cpp +++ b/config.tests/unix/opengles1/opengles1.cpp @@ -1,10 +1,8 @@ #include -#include int main(int, char **) { GLfloat a = 1.0f; - eglInitialize(0, 0, 0); glColor4f(a, a, a, a); glClear(GL_COLOR_BUFFER_BIT); diff --git a/config.tests/unix/opengles1cl/opengles1cl.cpp b/config.tests/unix/opengles1cl/opengles1cl.cpp index f864276..23ae710 100644 --- a/config.tests/unix/opengles1cl/opengles1cl.cpp +++ b/config.tests/unix/opengles1cl/opengles1cl.cpp @@ -1,10 +1,8 @@ #include -#include int main(int, char **) { GLfixed a = 0; - eglInitialize(0, 0, 0); glColor4x(a, a, a, a); glClear(GL_COLOR_BUFFER_BIT); diff --git a/config.tests/unix/opengles2/opengles2.cpp b/config.tests/unix/opengles2/opengles2.cpp index 493530d..63c7b35 100644 --- a/config.tests/unix/opengles2/opengles2.cpp +++ b/config.tests/unix/opengles2/opengles2.cpp @@ -1,9 +1,7 @@ -#include #include int main(int, char **) { - eglInitialize(0, 0, 0); glUniform1f(1, GLfloat(1.0)); glClear(GL_COLOR_BUFFER_BIT); diff --git a/config.tests/unix/openvg/openvg.cpp b/config.tests/unix/openvg/openvg.cpp new file mode 100644 index 0000000..8f763cd --- /dev/null +++ b/config.tests/unix/openvg/openvg.cpp @@ -0,0 +1,16 @@ +// There is some variation in OpenVG engines as to what case +// the VG includes use. The Khronos reference implementation +// for OpenVG 1.1 uses upper case, so we treat that as canonical. +#if defined(QT_LOWER_CASE_VG_INCLUDES) +#include +#else +#include +#endif + +int main(int, char **) +{ + VGint i; + i = 2; + vgFlush(); + return 0; +} diff --git a/config.tests/unix/openvg/openvg.pro b/config.tests/unix/openvg/openvg.pro new file mode 100644 index 0000000..8dd227b --- /dev/null +++ b/config.tests/unix/openvg/openvg.pro @@ -0,0 +1,11 @@ +SOURCES += openvg.cpp + +!isEmpty(QMAKE_INCDIR_OPENVG): INCLUDEPATH += $$QMAKE_INCDIR_OPENVG +!isEmpty(QMAKE_LIBDIR_OPENVG): LIBS += -L$$QMAKE_LIBDIR_OPENVG +!isEmpty(QMAKE_LIBS_OPENVG): LIBS += $$QMAKE_LIBS_OPENVG + +lower_case_includes { + DEFINES += QT_LOWER_CASE_VG_INCLUDES +} + +CONFIG -= qt diff --git a/config.tests/unix/shivavg/shivavg.cpp b/config.tests/unix/shivavg/shivavg.cpp new file mode 100644 index 0000000..b5d3291 --- /dev/null +++ b/config.tests/unix/shivavg/shivavg.cpp @@ -0,0 +1,10 @@ +#include + +int main(int, char **) +{ + VGint i; + i = 2; + vgFlush(); + vgDestroyContextSH(); + return 0; +} diff --git a/config.tests/unix/shivavg/shivavg.pro b/config.tests/unix/shivavg/shivavg.pro new file mode 100644 index 0000000..0c1bd07 --- /dev/null +++ b/config.tests/unix/shivavg/shivavg.pro @@ -0,0 +1,7 @@ +SOURCES += shivavg.cpp + +!isEmpty(QMAKE_INCDIR_OPENVG): INCLUDEPATH += $$QMAKE_INCDIR_OPENVG +!isEmpty(QMAKE_LIBDIR_OPENVG): LIBS += -L$$QMAKE_LIBDIR_OPENVG +!isEmpty(QMAKE_LIBS_OPENVG): LIBS += $$QMAKE_LIBS_OPENVG + +CONFIG -= qt diff --git a/configure b/configure index e0b8b3e..a146175 100755 --- a/configure +++ b/configure @@ -588,6 +588,11 @@ CFG_XRANDR=runtime CFG_XRENDER=auto CFG_MITSHM=auto CFG_OPENGL=auto +CFG_OPENVG=no +CFG_OPENVG_LC_INCLUDES=no +CFG_OPENVG_SHIVA=no +CFG_EGL=no +CFG_EGL_GLES_INCLUDES=no CFG_SSE=auto CFG_FONTCONFIG=auto CFG_QWS_FREETYPE=auto @@ -888,6 +893,16 @@ while [ "$#" -gt 0 ]; do VAL=$1 fi ;; + -openvg) + VAR=openvg + # this option may or may not be followed by an argument + if [ -z "$2" ] || echo "$2" | grep '^-' >/dev/null 2>&1; then + VAL=yes + else + shift; + VAL=$1 + fi + ;; -hostprefix) VAR=`echo $1 | sed "s,^-\(.*\),\1,"` # this option may or may not be followed by an argument @@ -1132,6 +1147,13 @@ while [ "$#" -gt 0 ]; do UNKNOWN_OPT=yes fi ;; + openvg) + if [ "$VAL" = "auto" ] || [ "$VAL" = "yes" ] || [ "$VAL" = "no" ]; then + CFG_OPENVG="$VAL" + else + UNKNOWN_OPT=yes + fi + ;; graphicssystem) if [ "$PLATFORM_QWS" = "yes" ]; then echo "Error: Graphics System plugins are not supported on QWS." @@ -3480,7 +3502,12 @@ Qt/X11 only: to force the use of the Desktop (OpenGL 1.x or 2.x), OpenGL ES 1.x Common profile, 1.x Common Lite profile or 2.x APIs instead. On X11, the EGL API will be used - to manage GL contexts in the case of OpenGL ES. + to manage GL contexts in the case of OpenGL ES + + -no-openvg ........ Do not support OpenVG. + + -openvg ........... Enable OpenVG support. + Requires EGL support, typically supplied by an OpenGL + or other graphics implementation. $SMN -no-sm ............. Do not support X Session Management. $SMY -sm ................ Support X Session Management, links in -lSM -lICE. @@ -4685,6 +4712,27 @@ if [ "$PLATFORM_MAC" = "yes" -a ! -z "$QT_NAMESPACE" ]; then fi if [ "$PLATFORM_X11" = "yes" -o "$PLATFORM_QWS" = "yes" ]; then + + # detect EGL support + if "$unixtests/compile.test" "$XQMAKESPEC" "$QMAKE_CONFIG" $OPT_VERBOSE "$relpath" "$outpath" "config.tests/unix/egl" "EGL (EGL/egl.h)" $L_FLAGS $I_FLAGS $l_FLAGS; then + # EGL specified by QMAKE_*_EGL, included with + CFG_EGL=yes + CFG_EGL_GLES_INCLUDES=no + elif "$unixtests/compile.test" "$XQMAKESPEC" "$QMAKE_CONFIG" $OPT_VERBOSE "$relpath" "$outpath" "config.tests/unix/egl4gles1" "EGL (GLES/egl.h)" $L_FLAGS $I_FLAGS $l_FLAGS; then + # EGL specified by QMAKE_*_EGL, included with + CFG_EGL=yes + CFG_EGL_GLES_INCLUDES=yes + fi + if ( [ "$CFG_OPENGL" = "es1" ] || [ "$CFG_OPENGL" = "es1cl" ] || [ "$CFG_OPENGL" = "es2" ] ) && [ "$CFG_EGL" != "yes" ] && [ "$PLATFORM_X11" = "yes" ]; then + echo "The EGL functionality test failed!" + echo " EGL is required for OpenGL ES on X11 to manage contexts & surfaces." + echo " You might need to modify the include and library search paths by editing" + echo " QMAKE_INCDIR_EGL, QMAKE_LIBDIR_EGL and QMAKE_LIBS_EGL in" + echo " ${XQMAKESPEC}." + exit 1 + fi + + # auto-detect Glib support if [ "$CFG_GLIB" != "no" ]; then if [ -n "$PKG_CONFIG" ]; then @@ -4814,8 +4862,8 @@ if [ "$PLATFORM_X11" = "yes" ]; then if [ $? != "0" ]; then echo "The OpenGL ES 1.x Common Lite Profile functionality test failed!" echo " You might need to modify the include and library search paths by editing" - echo " QMAKE_INCDIR_OPENGL, QMAKE_LIBDIR_OPENGL and QMAKE_LIBS_OPENGL in" - echo " ${XQMAKESPEC}." + echo " QMAKE_INCDIR_OPENGL, QMAKE_LIBDIR_OPENGL and QMAKE_LIBS_OPENGL in" + echo " ${XQMAKESPEC}." exit 1 fi elif [ "$CFG_OPENGL" = "es1" ]; then @@ -4824,8 +4872,8 @@ if [ "$PLATFORM_X11" = "yes" ]; then if [ $? != "0" ]; then echo "The OpenGL ES 1.x functionality test failed!" echo " You might need to modify the include and library search paths by editing" - echo " QMAKE_INCDIR_OPENGL, QMAKE_LIBDIR_OPENGL and QMAKE_LIBS_OPENGL in" - echo " ${XQMAKESPEC}." + echo " QMAKE_INCDIR_OPENGL, QMAKE_LIBDIR_OPENGL and QMAKE_LIBS_OPENGL in" + echo " ${XQMAKESPEC}." exit 1 fi elif [ "$CFG_OPENGL" = "es2" ]; then @@ -4834,8 +4882,8 @@ if [ "$PLATFORM_X11" = "yes" ]; then if [ $? != "0" ]; then echo "The OpenGL ES 2.0 functionality test failed!" echo " You might need to modify the include and library search paths by editing" - echo " QMAKE_INCDIR_OPENGL, QMAKE_LIBDIR_OPENGL and QMAKE_LIBS_OPENGL in" - echo " ${XQMAKESPEC}." + echo " QMAKE_INCDIR_OPENGL, QMAKE_LIBDIR_OPENGL and QMAKE_LIBS_OPENGL in" + echo " ${XQMAKESPEC}." exit 1 fi elif [ "$CFG_OPENGL" = "desktop" ]; then @@ -4844,8 +4892,8 @@ if [ "$PLATFORM_X11" = "yes" ]; then if [ $? != "0" ]; then echo "The OpenGL functionality test failed!" echo " You might need to modify the include and library search paths by editing" - echo " QMAKE_INCDIR_OPENGL, QMAKE_LIBDIR_OPENGL and QMAKE_LIBS_OPENGL in" - echo " ${XQMAKESPEC}." + echo " QMAKE_INCDIR_OPENGL, QMAKE_LIBDIR_OPENGL and QMAKE_LIBS_OPENGL in" + echo " ${XQMAKESPEC}." exit 1 fi case "$PLATFORM" in @@ -5500,6 +5548,33 @@ if [ "$CFG_OPENSSL" != "no" ]; then fi fi +# detect OpenVG support +if [ "$CFG_OPENVG" != "no" ]; then + if "$unixtests/compile.test" "$XQMAKESPEC" "$QMAKE_CONFIG" $OPT_VERBOSE "$relpath" "$outpath" "config.tests/unix/openvg" "OpenVG" $L_FLAGS $I_FLAGS $l_FLAGS $CONFIG_ARG; then + if [ "$CFG_OPENVG" = "auto" ]; then + CFG_OPENVG=yes + fi + elif "$unixtests/compile.test" "$XQMAKESPEC" "$QMAKE_CONFIG lower_case_includes" $OPT_VERBOSE "$relpath" "$outpath" "config.tests/unix/openvg" "OpenVG (lc includes)" $L_FLAGS $I_FLAGS $l_FLAGS $CONFIG_ARG; then + if [ "$CFG_OPENVG" = "auto" ]; then + CFG_OPENVG=yes + fi + CFG_OPENVG_LC_INCLUDES=yes + else + if [ "$CFG_OPENVG" != "auto" ] && [ "$CFG_CONFIGURE_EXIT_ON_ERROR" = "yes" ]; then + echo "$CFG_OPENVG was specified for OpenVG but cannot be enabled due to functionality tests!" + echo " Turn on verbose messaging (-v) to $0 to see the final report." + echo " If you believe this message is in error you may use the continue" + echo " switch (-continue) to $0 to continue." + exit 101 + else + CFG_OPENVG=no + fi + fi + if [ "$CFG_OPENVG" == "yes" ] && "$unixtests/compile.test" "$XQMAKESPEC" "$QMAKE_CONFIG" $OPT_VERBOSE "$relpath" "$outpath" "config.tests/unix/shivavg" "ShivaVG" $L_FLAGS $I_FLAGS $l_FLAGS $CONFIG_ARG; then + CFG_OPENVG_SHIVA=yes + fi +fi + if [ "$CFG_PTMALLOC" != "no" ]; then # build ptmalloc, copy .a file to lib/ echo "Building ptmalloc. Please wait..." @@ -5629,6 +5704,30 @@ else QT_CONFIG="$QT_CONFIG accessibility" fi +# enable egl +if [ "$CFG_EGL" = "no" ]; then + QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_EGL" +else + QT_CONFIG="$QT_CONFIG egl" + if [ "$CFG_EGL_GLES_INCLUDES" = "yes" ]; then + QCONFIG_FLAGS="$QCONFIG_FLAGS QT_GLES_EGL" + fi +fi + +# enable openvg +if [ "$CFG_OPENVG" = "no" ]; then + QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_OPENVG" +else + QT_CONFIG="$QT_CONFIG openvg" + if [ "$CFG_OPENVG_LC_INCLUDES" = "yes" ]; then + QCONFIG_FLAGS="$QCONFIG_FLAGS QT_LOWER_CASE_VG_INCLUDES" + fi + if [ "$CFG_OPENVG_SHIVA" = "yes" ]; then + QT_CONFIG="$QT_CONFIG shivavg" + QCONFIG_FLAGS="$QCONFIG_FLAGS QT_SHIVAVG" + fi +fi + # enable opengl if [ "$CFG_OPENGL" = "no" ]; then QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_OPENGL" @@ -6971,6 +7070,20 @@ elif [ "$CFG_OPENGL" = "es2" ]; then else echo "OpenGL support ...... no" fi +if [ "$CFG_EGL" != "no" ]; then + if [ "$CFG_EGL_GLES_INCLUDES" != "no" ]; then + echo "EGL support ......... yes " + else + echo "EGL support ......... yes " + fi +fi +if [ "$CFG_OPENVG" ]; then + if [ "$CFG_OPENVG_SHIVA" = "yes" ]; then + echo "OpenVG support ...... ShivaVG" + else + echo "OpenVG support ...... $CFG_OPENVG" + fi +fi if [ "$PLATFORM_X11" = "yes" ]; then echo "NAS sound support ... $CFG_NAS" echo "XShape support ...... $CFG_XSHAPE" diff --git a/doc/src/modules.qdoc b/doc/src/modules.qdoc index 145b361..5f0f868 100644 --- a/doc/src/modules.qdoc +++ b/doc/src/modules.qdoc @@ -55,6 +55,7 @@ \row \o \l{QtGui} \o Graphical user interface (GUI) components \row \o \l{QtNetwork} \o Classes for network programming \row \o \l{QtOpenGL} \o OpenGL support classes + \row \o \l{QtOpenVG} \o OpenVG support classes \row \o \l{QtScript} \o Classes for evaluating Qt Scripts \row \o \l{QtScriptTools} \o Additional Qt Script components \row \o \l{QtSql} \o Classes for database integration using SQL diff --git a/doc/src/qtopengl.qdoc b/doc/src/qtopengl.qdoc index 69d33bb..f60ef89 100644 --- a/doc/src/qtopengl.qdoc +++ b/doc/src/qtopengl.qdoc @@ -44,7 +44,7 @@ \title QtOpenGL Module \contentspage Qt's Modules \previouspage QtNetwork - \nextpage QtSql + \nextpage QtOpenVG \ingroup modules \brief The QtOpenGL module offers classes that make it easy to diff --git a/doc/src/qtopenvg.qdoc b/doc/src/qtopenvg.qdoc new file mode 100644 index 0000000..ad036ef --- /dev/null +++ b/doc/src/qtopenvg.qdoc @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \module QtOpenVG + \title QtOpenVG Module + \contentspage Qt's Modules + \previouspage QtOpenGL + \nextpage QtSql + \ingroup modules + + \brief The QtOpenVG module offers classes that make it easy to + use OpenVG in Qt applications. + + From the OpenVG 1.1 Specification: + + \quotation + + OpenVG is an application programming interface (API) for hardware-accelerated two- + dimensional vector and raster graphics developed under the auspices of the Khronos + Group (www.khronos.org). It provides a device-independent and vendor-neutral interface + for sophisticated 2D graphical applications, while allowing device manufacturers to + provide hardware acceleration where appropriate. + + \endquotation + + The specification, and a reference implementation of it are available from the + \l{http://www.khronos.org/registry/vg/}{Khronos Group}. + + \bold{Note:} Khronos and OpenVG are trademarks of The Khronos Group Inc. OpenGL is a + registered trademark, and OpenGL ES is a trademark, of Silicon Graphics, Inc. + + + The Qt OpenVG module makes it easy to use OpenVG in Qt applications. + */ diff --git a/mkspecs/common/linux.conf b/mkspecs/common/linux.conf index ff87c74..fa84841 100644 --- a/mkspecs/common/linux.conf +++ b/mkspecs/common/linux.conf @@ -13,12 +13,15 @@ QMAKE_INCDIR_QT = $$[QT_INSTALL_HEADERS] QMAKE_LIBDIR_QT = $$[QT_INSTALL_LIBS] QMAKE_INCDIR_OPENGL = /usr/X11R6/include QMAKE_LIBDIR_OPENGL = /usr/X11R6/lib +QMAKE_INCDIR_EGL = +QMAKE_LIBDIR_EGL = QMAKE_LIBS = QMAKE_LIBS_DYNLOAD = -ldl QMAKE_LIBS_X11 = -lXext -lX11 -lm QMAKE_LIBS_X11SM = -lSM -lICE QMAKE_LIBS_NIS = -lnsl +QMAKE_LIBS_EGL = -lEGL QMAKE_LIBS_OPENGL = -lGLU -lGL QMAKE_LIBS_OPENGL_QT = -lGL QMAKE_LIBS_THREAD = -lpthread diff --git a/mkspecs/features/egl.prf b/mkspecs/features/egl.prf new file mode 100644 index 0000000..22002c3 --- /dev/null +++ b/mkspecs/features/egl.prf @@ -0,0 +1,3 @@ +!isEmpty(QMAKE_INCDIR_EGL): INCLUDEPATH += $$QMAKE_INCDIR_EGL +!isEmpty(QMAKE_LIBDIR_EGL): LIBS += -L$$QMAKE_LIBDIR_EGL +!isEmpty(QMAKE_LIBS_EGL): LIBS += $$QMAKE_LIBS_EGL diff --git a/mkspecs/features/qt.prf b/mkspecs/features/qt.prf index 0c6e09a..332eaca 100644 --- a/mkspecs/features/qt.prf +++ b/mkspecs/features/qt.prf @@ -36,7 +36,7 @@ INCLUDEPATH = $$QMAKE_INCDIR_QT $$INCLUDEPATH #prepending prevents us from picki win32:INCLUDEPATH += $$QMAKE_INCDIR_QT/ActiveQt # As order does matter for static libs, we reorder the QT variable here -TMPLIBS = webkit phonon dbus testlib script scripttools svg qt3support sql xmlpatterns xml opengl gui network core +TMPLIBS = webkit phonon dbus testlib script scripttools svg qt3support sql xmlpatterns xml egl opengl openvg gui network core for(QTLIB, $$list($$TMPLIBS)) { contains(QT, $$QTLIB): QT_ORDERED += $$QTLIB } @@ -140,6 +140,7 @@ for(QTLIB, $$list($$lower($$unique(QT)))) { else:isEqual(QTLIB, xml):qlib = QtXml else:isEqual(QTLIB, xmlpatterns):qlib = QtXmlPatterns else:isEqual(QTLIB, opengl):qlib = QtOpenGL + else:isEqual(QTLIB, openvg):qlib = QtOpenVG else:isEqual(QTLIB, sql):qlib = QtSql else:isEqual(QTLIB, core):qlib = QtCore else:isEqual(QTLIB, canvas):qlib = QtCanvas diff --git a/mkspecs/features/unix/openvg.prf b/mkspecs/features/unix/openvg.prf new file mode 100644 index 0000000..7bd7fbe --- /dev/null +++ b/mkspecs/features/unix/openvg.prf @@ -0,0 +1,3 @@ +!isEmpty(QMAKE_INCDIR_OPENVG): INCLUDEPATH += $$QMAKE_INCDIR_OPENVG +!isEmpty(QMAKE_LIBDIR_OPENVG): QMAKE_LIBDIR += -L$$QMAKE_LIBDIR_OPENVG +!isEmpty(QMAKE_LIBS_OPENVG): LIBS += $QMAKE_LIBS_OPENVG diff --git a/mkspecs/features/win32/openvg.prf b/mkspecs/features/win32/openvg.prf new file mode 100644 index 0000000..d4aa296 --- /dev/null +++ b/mkspecs/features/win32/openvg.prf @@ -0,0 +1,3 @@ +QMAKE_LIBS += $$QMAKE_LIBS_OPENVG +QMAKE_LFLAGS += $$QMAKE_LFLAGS_OPENVG + diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 3e6771c..0721c39 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -1143,6 +1143,11 @@ class QDataStream; # else # define Q_OPENGL_EXPORT Q_DECL_IMPORT # endif +# if defined(QT_BUILD_OPENVG_LIB) +# define Q_OPENVG_EXPORT Q_DECL_EXPORT +# else +# define Q_OPENVG_EXPORT Q_DECL_IMPORT +# endif # if defined(QT_BUILD_XML_LIB) # define Q_XML_EXPORT Q_DECL_EXPORT # else @@ -1182,6 +1187,7 @@ class QDataStream; # define Q_SVG_EXPORT Q_DECL_IMPORT # define Q_CANVAS_EXPORT Q_DECL_IMPORT # define Q_OPENGL_EXPORT Q_DECL_IMPORT +# define Q_OPENVG_EXPORT Q_DECL_IMPORT # define Q_XML_EXPORT Q_DECL_IMPORT # define Q_XMLPATTERNS_EXPORT Q_DECL_IMPORT # define Q_SCRIPT_EXPORT Q_DECL_IMPORT @@ -1207,6 +1213,7 @@ class QDataStream; # define Q_NETWORK_EXPORT Q_DECL_EXPORT # define Q_SVG_EXPORT Q_DECL_EXPORT # define Q_OPENGL_EXPORT Q_DECL_EXPORT +# define Q_OPENVG_EXPORT Q_DECL_EXPORT # define Q_XML_EXPORT Q_DECL_EXPORT # define Q_XMLPATTERNS_EXPORT Q_DECL_EXPORT # define Q_SCRIPT_EXPORT Q_DECL_EXPORT @@ -2252,6 +2259,7 @@ QT3_SUPPORT Q_CORE_EXPORT const char *qInstallPathSysconf(); #define QT_MODULE_TEST 0x04000 #define QT_MODULE_DBUS 0x08000 #define QT_MODULE_SCRIPTTOOLS 0x10000 +#define QT_MODULE_OPENVG 0x20000 /* Qt editions */ #define QT_EDITION_CONSOLE (QT_MODULE_CORE \ @@ -2271,6 +2279,7 @@ QT3_SUPPORT Q_CORE_EXPORT const char *qInstallPathSysconf(); | QT_MODULE_GUI \ | QT_MODULE_NETWORK \ | QT_MODULE_OPENGL \ + | QT_MODULE_OPENVG \ | QT_MODULE_SQL \ | QT_MODULE_XML \ | QT_MODULE_XMLPATTERNS \ @@ -2314,6 +2323,9 @@ QT_LICENSED_MODULE(Network) #if (QT_EDITION & QT_MODULE_OPENGL) QT_LICENSED_MODULE(OpenGL) #endif +#if (QT_EDITION & QT_MODULE_OPENVG) +QT_LICENSED_MODULE(OpenVG) +#endif #if (QT_EDITION & QT_MODULE_SQL) QT_LICENSED_MODULE(Sql) #endif diff --git a/src/gui/egl/egl.pri b/src/gui/egl/egl.pri new file mode 100644 index 0000000..651507f --- /dev/null +++ b/src/gui/egl/egl.pri @@ -0,0 +1,28 @@ +HEADERS += \ + egl/qegl_p.h \ + egl/qeglproperties_p.h + +SOURCES += \ + egl/qegl.cpp \ + egl/qeglproperties.cpp + +contains(QT_CONFIG, wince*): SOURCES += egl/qegl_wince.cpp + +unix { + embedded { + SOURCES += egl/qegl_qws.cpp + } else { + symbian { + SOURCES += egl/qegl_symbian.cpp + } else { + SOURCES += egl/qegl_x11.cpp + } + } +} + +for(p, QMAKE_LIBDIR_EGL) { + exists($$p):LIBS += -L$$p +} + +!isEmpty(QMAKE_INCDIR_EGL): INCLUDEPATH += $$QMAKE_INCDIR_EGL +!isEmpty(QMAKE_LIBS_EGL): LIBS += $$QMAKE_LIBS_EGL diff --git a/src/gui/egl/qegl.cpp b/src/gui/egl/qegl.cpp new file mode 100644 index 0000000..89d9d1b --- /dev/null +++ b/src/gui/egl/qegl.cpp @@ -0,0 +1,403 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include "qegl_p.h" + +QT_BEGIN_NAMESPACE + +QEglContext::QEglContext() + : apiType(QEgl::OpenGL) + , dpy(EGL_NO_DISPLAY) + , ctx(EGL_NO_CONTEXT) + , surf(EGL_NO_SURFACE) + , cfg(0) + , share(false) + , current(false) + , reserved(0) +{ +} + +QEglContext::~QEglContext() +{ + destroy(); +} + +bool QEglContext::isValid() const +{ + return (ctx != EGL_NO_CONTEXT); +} + +bool QEglContext::isSharing() const +{ + return share; +} + +bool QEglContext::isCurrent() const +{ + return current; +} + +// Open the EGL display associated with "device". +bool QEglContext::openDisplay(QPaintDevice *device) +{ + if (dpy == EGL_NO_DISPLAY) + dpy = defaultDisplay(device); + return (dpy != EGL_NO_DISPLAY); +} + +// Choose a configuration that matches "properties". +bool QEglContext::chooseConfig + (const QEglProperties& properties, QEgl::PixelFormatMatch match) +{ + QEglProperties props(properties); + do { + // Get the number of matching configurations for this set of properties. + EGLint matching = 0; + if (!eglChooseConfig(dpy, props.properties(), 0, 256, &matching) || !matching) + continue; + + // If we want the best pixel format, then return the first + // matching configuration. + if (match == QEgl::BestPixelFormat) { + eglChooseConfig(dpy, props.properties(), &cfg, 1, &matching); + if (matching < 1) + continue; + return true; + } + + // Fetch all of the matching configurations and find the + // first that matches the pixel format we wanted. + EGLint size = matching; + EGLConfig *configs = new EGLConfig [size]; + eglChooseConfig(dpy, props.properties(), configs, size, &matching); + for (EGLint index = 0; index < size; ++index) { + EGLint red, green, blue, alpha; + eglGetConfigAttrib(dpy, configs[index], EGL_RED_SIZE, &red); + eglGetConfigAttrib(dpy, configs[index], EGL_GREEN_SIZE, &green); + eglGetConfigAttrib(dpy, configs[index], EGL_BLUE_SIZE, &blue); + eglGetConfigAttrib(dpy, configs[index], EGL_ALPHA_SIZE, &alpha); + if (red == props.value(EGL_RED_SIZE) && + green == props.value(EGL_GREEN_SIZE) && + blue == props.value(EGL_BLUE_SIZE) && + (props.value(EGL_ALPHA_SIZE) == 0 || + alpha == props.value(EGL_ALPHA_SIZE))) { + cfg = configs[index]; + delete [] configs; + return true; + } + } + delete [] configs; + } while (props.reduceConfiguration()); + +#ifdef EGL_BIND_TO_TEXTURE_RGBA + // Don't report an error just yet if we failed to get a pbuffer + // configuration with texture rendering. Only report failure if + // we cannot get any pbuffer configurations at all. + if (props.value(EGL_BIND_TO_TEXTURE_RGBA) == EGL_DONT_CARE && + props.value(EGL_BIND_TO_TEXTURE_RGB) == EGL_DONT_CARE) +#endif + { + qWarning() << "QEglContext::chooseConfig(): Could not find a suitable EGL configuration"; + qWarning() << "Requested:" << props.toString(); + qWarning() << "Available:"; + dumpAllConfigs(); + } + return false; +} + +// Create the EGLContext. +bool QEglContext::createContext(QEglContext *shareContext) +{ + // We need to select the correct API before calling eglCreateContext(). +#ifdef EGL_OPENGL_ES_API + if (apiType == QEgl::OpenGL) + eglBindAPI(EGL_OPENGL_ES_API); +#endif +#ifdef EGL_OPENVG_API + if (apiType == QEgl::OpenVG) + eglBindAPI(EGL_OPENVG_API); +#endif + + // Create a new context for the configuration. + QEglProperties contextProps; +#if defined(QT_OPENGL_ES_2) + if (apiType == QEgl::OpenGL) + contextProps.setValue(EGL_CONTEXT_CLIENT_VERSION, 2); +#endif + if (shareContext && shareContext->ctx == EGL_NO_CONTEXT) + shareContext = 0; + if (shareContext) { + ctx = eglCreateContext(dpy, cfg, shareContext->ctx, contextProps.properties()); + if (ctx == EGL_NO_CONTEXT) { + qWarning() << "QEglContext::createContext(): Could not share context:" << errorString(eglGetError()); + shareContext = 0; + } + } + if (ctx == EGL_NO_CONTEXT) { + ctx = eglCreateContext(dpy, cfg, 0, contextProps.properties()); + if (ctx == EGL_NO_CONTEXT) { + qWarning() << "QEglContext::createContext(): Unable to create EGL context:" << errorString(eglGetError()); + return false; + } + } + share = (shareContext != 0); + return true; +} + +// Recreate the surface for a paint device because the native id has changed. +bool QEglContext::recreateSurface(QPaintDevice *device) +{ + // Bail out if the surface has not been created for the first time yet. + if (surf == EGL_NO_SURFACE) + return true; + + // Destroy the old surface. + eglDestroySurface(dpy, surf); + surf = EGL_NO_SURFACE; + + // Create a new one. + return createSurface(device); +} + +// Destroy the EGL surface object. +void QEglContext::destroySurface() +{ + if (surf != EGL_NO_SURFACE) { + eglDestroySurface(dpy, surf); + surf = EGL_NO_SURFACE; + } +} + +// Destroy the context. Note: this does not destroy the surface. +void QEglContext::destroy() +{ + if (ctx != EGL_NO_CONTEXT) + eglDestroyContext(dpy, ctx); + dpy = EGL_NO_DISPLAY; + ctx = EGL_NO_CONTEXT; + surf = EGL_NO_SURFACE; + cfg = 0; + share = false; +} + +bool QEglContext::makeCurrent() +{ + if (ctx == EGL_NO_CONTEXT) { + qWarning() << "QEglContext::makeCurrent(): Cannot make invalid context current"; + return false; + } + + current = true; + + bool ok = eglMakeCurrent(dpy, surf, surf, ctx); + if (!ok) + qWarning() << "QEglContext::makeCurrent():" << errorString(eglGetError()); + return ok; +} + +bool QEglContext::doneCurrent() +{ + // If the context is invalid, we assume that an error was reported + // when makeCurrent() was called. + if (ctx == EGL_NO_CONTEXT) + return false; + + current = false; + + // We need to select the correct API before calling eglMakeCurrent() + // with EGL_NO_CONTEXT because threads can have both OpenGL and OpenVG + // contexts active at the same time. +#ifdef EGL_OPENGL_ES_API + if (apiType == QEgl::OpenGL) + eglBindAPI(EGL_OPENGL_ES_API); +#endif +#ifdef EGL_OPENVG_API + if (apiType == QEgl::OpenVG) + eglBindAPI(EGL_OPENVG_API); +#endif + + bool ok = eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (!ok) + qWarning() << "QEglContext::doneCurrent():" << errorString(eglGetError()); + return ok; +} + +bool QEglContext::swapBuffers() +{ + if(ctx == EGL_NO_CONTEXT) + return false; + + bool ok = eglSwapBuffers(dpy, surf); + if (!ok) + qWarning() << "QEglContext::swapBuffers():" << errorString(eglGetError()); + return ok; +} + +// Wait for native rendering operations to complete before starting +// to use OpenGL/OpenVG operations. +void QEglContext::waitNative() +{ +#ifdef EGL_CORE_NATIVE_ENGINE + eglWaitNative(EGL_CORE_NATIVE_ENGINE); +#endif +} + +// Wait for client OpenGL/OpenVG operations to complete before +// using native rendering operations. +void QEglContext::waitClient() +{ +#ifdef EGL_OPENGL_ES_API + if (apiType == QEgl::OpenGL) { + eglBindAPI(EGL_OPENGL_ES_API); + eglWaitClient(); + } +#else + if (apiType == QEgl::OpenGL) + eglWaitGL(); +#endif +#ifdef EGL_OPENVG_API + if (apiType == QEgl::OpenVG) { + eglBindAPI(EGL_OPENVG_API); + eglWaitClient(); + } +#endif +} + +// Query the actual size of the EGL surface. +QSize QEglContext::surfaceSize() const +{ + int w, h; + eglQuerySurface(dpy, surf, EGL_WIDTH, &w); + eglQuerySurface(dpy, surf, EGL_HEIGHT, &h); + return QSize(w, h); +} + +// Query the value of a configuration attribute. +bool QEglContext::configAttrib(int name, EGLint *value) const +{ + return eglGetConfigAttrib(dpy, cfg, name, value); +} + +// Retrieve all of the properties on "cfg". If zero, return +// the context's configuration. +QEglProperties QEglContext::configProperties(EGLConfig cfg) const +{ + if (!cfg) + cfg = config(); + QEglProperties props; + for (int name = 0x3020; name <= 0x304F; ++name) { + EGLint value; + if (name != EGL_NONE && eglGetConfigAttrib(dpy, cfg, name, &value)) + props.setValue(name, value); + } + eglGetError(); // Clear the error state. + return props; +} + +// Initialize and return the default display. +EGLDisplay QEglContext::defaultDisplay(QPaintDevice *device) +{ + static EGLDisplay dpy = EGL_NO_DISPLAY; + if (dpy == EGL_NO_DISPLAY) { + dpy = getDisplay(device); + if (dpy == EGL_NO_DISPLAY) { + qWarning() << "QEglContext::defaultDisplay(): Cannot open EGL display"; + return EGL_NO_DISPLAY; + } + if (!eglInitialize(dpy, NULL, NULL)) { + qWarning() << "QEglContext::defaultDisplay(): Cannot initialize EGL display:" << errorString(eglGetError()); + return EGL_NO_DISPLAY; + } +#ifdef EGL_OPENGL_ES_API + eglBindAPI(EGL_OPENGL_ES_API); +#endif + } + return dpy; +} + +// Return the error string associated with a specific code. +QString QEglContext::errorString(EGLint code) +{ + static const char * const errors[] = { + "Success (0x3000)", // No tr + "Not initialized (0x3001)", // No tr + "Bad access (0x3002)", // No tr + "Bad alloc (0x3003)", // No tr + "Bad attribute (0x3004)", // No tr + "Bad config (0x3005)", // No tr + "Bad context (0x3006)", // No tr + "Bad current surface (0x3007)", // No tr + "Bad display (0x3008)", // No tr + "Bad match (0x3009)", // No tr + "Bad native pixmap (0x300A)", // No tr + "Bad native window (0x300B)", // No tr + "Bad parameter (0x300C)", // No tr + "Bad surface (0x300D)", // No tr + "Context lost (0x300E)" // No tr + }; + if (code >= 0x3000 && code <= 0x300E) { + return QString::fromLatin1(errors[code - 0x3000]); + } else { + return QLatin1String("0x") + QString::number(int(code), 16); + } +} + +// Dump all of the EGL configurations supported by the system. +void QEglContext::dumpAllConfigs() +{ + QEglProperties props; + EGLint count = 0; + if (!eglGetConfigs(dpy, 0, 0, &count) || count < 1) + return; + EGLConfig *configs = new EGLConfig [count]; + eglGetConfigs(dpy, configs, count, &count); + for (EGLint index = 0; index < count; ++index) { + props = configProperties(configs[index]); + qWarning() << props.toString(); + } + delete [] configs; +} + +QT_END_NAMESPACE diff --git a/src/gui/egl/qegl_p.h b/src/gui/egl/qegl_p.h new file mode 100644 index 0000000..89949e2 --- /dev/null +++ b/src/gui/egl/qegl_p.h @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QEGL_P_H +#define QEGL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience of +// the QGLWidget and QVGWidget classes. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +#include "qeglproperties_p.h" + +QT_BEGIN_INCLUDE_NAMESPACE + +#if !defined(EGL_VERSION_1_3) && !defined(QEGL_NATIVE_TYPES_DEFINED) +#undef EGLNativeWindowType +#undef EGLNativePixmapType +#undef EGLNativeDisplayType +typedef NativeWindowType EGLNativeWindowType; +typedef NativePixmapType EGLNativePixmapType; +typedef NativeDisplayType EGLNativeDisplayType; +#define QEGL_NATIVE_TYPES_DEFINED 1 +#endif +QT_END_INCLUDE_NAMESPACE + +QT_BEGIN_NAMESPACE + +class Q_GUI_EXPORT QEglContext +{ +public: + QEglContext(); + ~QEglContext(); + + bool isValid() const; + bool isSharing() const; + bool isCurrent() const; + + QEgl::API api() const { return apiType; } + void setApi(QEgl::API api) { apiType = api; } + + bool openDisplay(QPaintDevice *device); + bool chooseConfig(const QEglProperties& properties, QEgl::PixelFormatMatch match = QEgl::ExactPixelFormat); + bool createContext(QEglContext *shareContext = 0); + bool createSurface(QPaintDevice *device, const QEglProperties *properties = 0); + bool recreateSurface(QPaintDevice *device); + void destroySurface(); + + void destroy(); + + bool makeCurrent(); + bool doneCurrent(); + bool swapBuffers(); + + void waitNative(); + void waitClient(); + + QSize surfaceSize() const; + + bool configAttrib(int name, EGLint *value) const; + + static void clearError() { eglGetError(); } + static EGLint error() { return eglGetError(); } + static QString errorString(EGLint code); + + EGLDisplay display() const { return dpy; } + EGLContext context() const { return ctx; } + EGLSurface surface() const { return surf; } + void setSurface(EGLSurface surface) { surf = surface; } + EGLConfig config() const { return cfg; } + + QEglProperties configProperties(EGLConfig cfg = 0) const; + + static EGLDisplay defaultDisplay(QPaintDevice *device); + + void dumpAllConfigs(); + +private: + QEgl::API apiType; + EGLDisplay dpy; + EGLContext ctx; + EGLSurface surf; + EGLConfig cfg; + bool share; + bool current; + void *reserved; // For extension data in future versions. + + static EGLDisplay getDisplay(QPaintDevice *device); +}; + +QT_END_NAMESPACE + +#endif // QEGL_P_H diff --git a/src/gui/egl/qegl_qws.cpp b/src/gui/egl/qegl_qws.cpp new file mode 100644 index 0000000..69eaf1b --- /dev/null +++ b/src/gui/egl/qegl_qws.cpp @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include "qegl_p.h" + +#if !defined(QT_NO_EGL) + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +// Create the surface for a QPixmap, QImage, or QWidget. +// We don't have QGLScreen to create EGL surfaces for us, +// so surface creation needs to be done in QtOpenGL or +// QtOpenVG for Qt/Embedded. +bool QEglContext::createSurface(QPaintDevice *device, const QEglProperties *properties) +{ + Q_UNUSED(device); + Q_UNUSED(properties); + return false; +} + +EGLDisplay QEglContext::getDisplay(QPaintDevice *device) +{ + Q_UNUSED(device); + return eglGetDisplay(EGLNativeDisplayType(EGL_DEFAULT_DISPLAY)); +} + +static QScreen *screenForDevice(QPaintDevice *device) +{ + QScreen *screen = qt_screen; + if (!screen) + return 0; + if (screen->classId() == QScreen::MultiClass) { + int screenNumber; + if (device && device->devType() == QInternal::Widget) + screenNumber = qApp->desktop()->screenNumber(static_cast(device)); + else + screenNumber = 0; + screen = screen->subScreens()[screenNumber]; + } + while (screen->classId() == QScreen::ProxyClass) { + screen = static_cast(screen)->screen(); + } + return screen; +} + +// Set pixel format and other properties based on a paint device. +void QEglProperties::setPaintDeviceFormat(QPaintDevice *dev) +{ + if (!dev) + return; + + // Find the QGLScreen for this paint device. + QScreen *screen = screenForDevice(dev); + if (!screen) + return; + int devType = dev->devType(); + if (devType == QInternal::Image) + setPixelFormat(static_cast(dev)->format()); + else + setPixelFormat(screen->pixelFormat()); +} + +QT_END_NAMESPACE + +#endif // !QT_NO_EGL diff --git a/src/gui/egl/qegl_symbian.cpp b/src/gui/egl/qegl_symbian.cpp new file mode 100644 index 0000000..16a72a1 --- /dev/null +++ b/src/gui/egl/qegl_symbian.cpp @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include "qegl_p.h" + +#include + +QT_BEGIN_NAMESPACE + +bool QEglContext::createSurface(QPaintDevice *device, const QEglProperties *properties) +{ + // Create the native drawable for the paint device. + int devType = device->devType(); + EGLNativePixmapType pixmapDrawable = 0; + EGLNativeWindowType windowDrawable = 0; + bool ok; + if (devType == QInternal::Pixmap) { + pixmapDrawable = 0; + ok = (pixmapDrawable != 0); + } else if (devType == QInternal::Widget) { + QWidget *w = static_cast(device); + windowDrawable = (EGLNativeWindowType)(w->winId()->DrawableWindow()); + ok = (windowDrawable != 0); + } else { + ok = false; + } + if (!ok) { + qWarning("QEglContext::createSurface(): Cannot create the native EGL drawable"); + return false; + } + + // Create the EGL surface to draw into, based on the native drawable. + const int *props; + if (properties) + props = properties->properties(); + else + props = 0; + if (devType == QInternal::Widget) + surf = eglCreateWindowSurface(dpy, cfg, windowDrawable, 0); + else + surf = eglCreatePixmapSurface(dpy, cfg, pixmapDrawable, 0); + if (surf == EGL_NO_SURFACE) { + qWarning("QEglContext::createSurface(): Unable to create EGL surface, error = 0x%x", eglGetError()); + return false; + } + return true; +} + +EGLDisplay QEglContext::getDisplay(QPaintDevice *device) +{ + EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (dpy == EGL_NO_DISPLAY) + qWarning("QEglContext::defaultDisplay(): Falling back to EGL_DEFAULT_DISPLAY"); + return dpy; +} + +// Set pixel format and other properties based on a paint device. +void QEglProperties::setPaintDeviceFormat(QPaintDevice *dev) +{ + int devType = dev->devType(); + if (devType == QInternal::Image) + setPixelFormat(static_cast(dev)->format()); + else + setPixelFormat(QImage::Format_RGB32); +} + + +QT_END_NAMESPACE diff --git a/src/gui/egl/qegl_wince.cpp b/src/gui/egl/qegl_wince.cpp new file mode 100644 index 0000000..7bcbcf8 --- /dev/null +++ b/src/gui/egl/qegl_wince.cpp @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include "qegl_p.h" + +#include + + +QT_BEGIN_NAMESPACE + +bool QEglContext::createSurface(QPaintDevice *device, const QEglProperties *properties) +{ + // Create the native drawable for the paint device. + int devType = device->devType(); + EGLNativePixmapType pixmapDrawable = 0; + EGLNativeWindowType windowDrawable = 0; + bool ok; + if (devType == QInternal::Pixmap) { + pixmapDrawable = 0; + ok = (pixmapDrawable != 0); + } else if (devType == QInternal::Widget) { + windowDrawable = (EGLNativeWindowType)(static_cast(device))->winId(); + ok = (windowDrawable != 0); + } else { + ok = false; + } + if (!ok) { + qWarning("QEglContext::createSurface(): Cannot create the native EGL drawable"); + return false; + } + + // Create the EGL surface to draw into, based on the native drawable. + const int *props; + if (properties) + props = properties->properties(); + else + props = 0; + if (devType == QInternal::Widget) + surf = eglCreateWindowSurface(dpy, cfg, windowDrawable, props); + else + surf = eglCreatePixmapSurface(dpy, cfg, pixmapDrawable, props); + if (surf == EGL_NO_SURFACE) { + qWarning("QEglContext::createSurface(): Unable to create EGL surface, error = 0x%x", eglGetError()); + return false; + } + return true; +} + +EGLDisplay QEglContext::getDisplay(QPaintDevice *device) +{ + EGLDisplay dpy = 0; + HWND win = (static_cast(device))->winId(); + HDC myDc = GetDC(win); + if (!myDc) { + qWarning("QEglContext::defaultDisplay(): WinCE display is not open"); + } + dpy = eglGetDisplay(EGLNativeDisplayType(myDc)); + if (dpy == EGL_NO_DISPLAY) { + qWarning("QEglContext::defaultDisplay(): Falling back to EGL_DEFAULT_DISPLAY"); + dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); + } + return dpy; +} + +// Set pixel format and other properties based on a paint device. +void QEglProperties::setPaintDeviceFormat(QPaintDevice *dev) +{ + int devType = dev->devType(); + if (devType == QInternal::Image) + setPixelFormat(static_cast(dev)->format()); + else + setPixelFormat(QImage::Format_RGB16); // XXX +} + +QT_END_NAMESPACE diff --git a/src/gui/egl/qegl_x11.cpp b/src/gui/egl/qegl_x11.cpp new file mode 100644 index 0000000..be89efe --- /dev/null +++ b/src/gui/egl/qegl_x11.cpp @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include "qegl_p.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +bool QEglContext::createSurface(QPaintDevice *device, const QEglProperties *properties) +{ + // Create the native drawable for the paint device. + int devType = device->devType(); + EGLNativePixmapType pixmapDrawable = 0; + EGLNativeWindowType windowDrawable = 0; + bool ok; + if (devType == QInternal::Pixmap) { + pixmapDrawable = (EGLNativePixmapType)(static_cast(device))->handle(); + ok = (pixmapDrawable != 0); + } else if (devType == QInternal::Widget) { + windowDrawable = (EGLNativeWindowType)(static_cast(device))->winId(); + ok = (windowDrawable != 0); + } else { + ok = false; + } + if (!ok) { + qWarning("QEglContext::createSurface(): Cannot create the native EGL drawable"); + return false; + } + + // Create the EGL surface to draw into, based on the native drawable. + const int *props; + if (properties) + props = properties->properties(); + else + props = 0; + if (devType == QInternal::Widget) + surf = eglCreateWindowSurface(dpy, cfg, windowDrawable, props); + else + surf = eglCreatePixmapSurface(dpy, cfg, pixmapDrawable, props); + if (surf == EGL_NO_SURFACE) { + qWarning() << "QEglContext::createSurface(): Unable to create EGL surface:" + << errorString(eglGetError()); + return false; + } + return true; +} + +EGLDisplay QEglContext::getDisplay(QPaintDevice *device) +{ + Q_UNUSED(device); + Display *xdpy = QX11Info::display(); + if (!xdpy) { + qWarning("QEglContext::getDisplay(): X11 display is not open"); + return EGL_NO_DISPLAY; + } + return eglGetDisplay(EGLNativeDisplayType(xdpy)); +} + +static int countBits(unsigned long mask) +{ + int count = 0; + while (mask != 0) { + if (mask & 1) + ++count; + mask >>= 1; + } + return count; +} + +// Set the pixel format parameters from the visual in "xinfo". +void QEglProperties::setVisualFormat(const QX11Info *xinfo) +{ + if (!xinfo) + return; + Visual *visual = (Visual*)xinfo->visual(); + if (!visual) + return; + if (visual->c_class != TrueColor && visual->c_class != DirectColor) + return; + setValue(EGL_RED_SIZE, countBits(visual->red_mask)); + setValue(EGL_GREEN_SIZE, countBits(visual->green_mask)); + setValue(EGL_BLUE_SIZE, countBits(visual->blue_mask)); + setValue(EGL_ALPHA_SIZE, 0); // XXX +} + +extern const QX11Info *qt_x11Info(const QPaintDevice *pd); + +// Set pixel format and other properties based on a paint device. +void QEglProperties::setPaintDeviceFormat(QPaintDevice *dev) +{ + if (!dev) + return; + if (dev->devType() == QInternal::Image) + setPixelFormat(static_cast(dev)->format()); + else + setVisualFormat(qt_x11Info(dev)); +} + +QT_END_NAMESPACE diff --git a/src/gui/egl/qeglproperties.cpp b/src/gui/egl/qeglproperties.cpp new file mode 100644 index 0000000..e0ae8a6 --- /dev/null +++ b/src/gui/egl/qeglproperties.cpp @@ -0,0 +1,496 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qeglproperties_p.h" + +QT_BEGIN_NAMESPACE + +#include +#include + +// Initialize a property block. +QEglProperties::QEglProperties() +{ + props.append(EGL_NONE); +} + +// Fetch the current value associated with a property. +int QEglProperties::value(int name) const +{ + for (int index = 0; index < (props.size() - 1); index += 2) { + if (props[index] == name) + return props[index + 1]; + } + + // If the attribute has not been explicitly set, return the EGL default + // The following defaults were taken from the EGL 1.4 spec: + switch(name) { + case EGL_BUFFER_SIZE: return 0; + case EGL_RED_SIZE: return 0; + case EGL_GREEN_SIZE: return 0; + case EGL_BLUE_SIZE: return 0; + case EGL_ALPHA_SIZE: return 0; +#if defined(EGL_LUMINANCE_SIZE) + case EGL_LUMINANCE_SIZE: return 0; +#endif +#if defined(EGL_ALPHA_MASK_SIZE) + case EGL_ALPHA_MASK_SIZE: return 0; +#endif + case EGL_BIND_TO_TEXTURE_RGB: return EGL_DONT_CARE; + case EGL_BIND_TO_TEXTURE_RGBA: return EGL_DONT_CARE; +#if defined(EGL_COLOR_BUFFER_TYPE) + case EGL_COLOR_BUFFER_TYPE: return EGL_RGB_BUFFER; +#endif + case EGL_CONFIG_CAVEAT: return EGL_DONT_CARE; + case EGL_CONFIG_ID: return EGL_DONT_CARE; + case EGL_DEPTH_SIZE: return 0; + case EGL_LEVEL: return 0; + case EGL_NATIVE_RENDERABLE: return EGL_DONT_CARE; + case EGL_NATIVE_VISUAL_TYPE: return EGL_DONT_CARE; + case EGL_MAX_SWAP_INTERVAL: return EGL_DONT_CARE; + case EGL_MIN_SWAP_INTERVAL: return EGL_DONT_CARE; +#if defined(EGL_RENDERABLE_TYPE) + case EGL_RENDERABLE_TYPE: return EGL_OPENGL_ES_BIT; +#endif + case EGL_SAMPLE_BUFFERS: return 0; + case EGL_SAMPLES: return 0; + case EGL_STENCIL_SIZE: return 0; + case EGL_SURFACE_TYPE: return EGL_WINDOW_BIT; + case EGL_TRANSPARENT_TYPE: return EGL_NONE; + case EGL_TRANSPARENT_RED_VALUE: return EGL_DONT_CARE; + case EGL_TRANSPARENT_GREEN_VALUE: return EGL_DONT_CARE; + case EGL_TRANSPARENT_BLUE_VALUE: return EGL_DONT_CARE; + +#if defined(EGL_VERSION_1_3) + case EGL_CONFORMANT: return 0; + case EGL_MATCH_NATIVE_PIXMAP: return EGL_NONE; +#endif + + case EGL_MAX_PBUFFER_HEIGHT: + case EGL_MAX_PBUFFER_WIDTH: + case EGL_MAX_PBUFFER_PIXELS: + case EGL_NATIVE_VISUAL_ID: + case EGL_NONE: + // Attribute does not affect config selection. + return EGL_DONT_CARE; + default: + // Attribute is unknown in EGL <= 1.4. + return EGL_DONT_CARE; + } +} + +// Set the value associated with a property, replacing an existing +// value if there is one. +void QEglProperties::setValue(int name, int value) +{ + for (int index = 0; index < (props.size() - 1); index += 2) { + if (props[index] == name) { + props[index + 1] = value; + return; + } + } + props[props.size() - 1] = name; + props.append(value); + props.append(EGL_NONE); +} + +// Remove a property value. Returns false if the property is not present. +bool QEglProperties::removeValue(int name) +{ + for (int index = 0; index < (props.size() - 1); index += 2) { + if (props[index] == name) { + while ((index + 2) < props.size()) { + props[index] = props[index + 2]; + ++index; + } + props.resize(props.size() - 2); + return true; + } + } + return false; +} + +// Sets the red, green, blue, and alpha sizes based on a pixel format. +// Normally used to match a configuration request to the screen format. +void QEglProperties::setPixelFormat(QImage::Format pixelFormat) +{ + int red, green, blue, alpha; + switch (pixelFormat) { + case QImage::Format_RGB32: + case QImage::Format_RGB888: + red = green = blue = 8; alpha = 0; break; + case QImage::Format_ARGB32: + case QImage::Format_ARGB32_Premultiplied: + red = green = blue = alpha = 8; break; + case QImage::Format_RGB16: + red = 5; green = 6; blue = 5; alpha = 0; break; + case QImage::Format_ARGB8565_Premultiplied: + red = 5; green = 6; blue = 5; alpha = 8; break; + case QImage::Format_RGB666: + red = green = blue = 6; alpha = 0; break; + case QImage::Format_ARGB6666_Premultiplied: + red = green = blue = alpha = 6; break; + case QImage::Format_RGB555: + red = green = blue = 5; alpha = 0; break; + case QImage::Format_ARGB8555_Premultiplied: + red = green = blue = 5; alpha = 8; break; + case QImage::Format_RGB444: + red = green = blue = 4; alpha = 0; break; + case QImage::Format_ARGB4444_Premultiplied: + red = green = blue = alpha = 4; break; + default: + qWarning() << "QEglProperties::setPixelFormat(): Unsupported pixel format"; + red = green = blue = alpha = 1; break; + } + setValue(EGL_RED_SIZE, red); + setValue(EGL_GREEN_SIZE, green); + setValue(EGL_BLUE_SIZE, blue); + setValue(EGL_ALPHA_SIZE, alpha); +} + +void QEglProperties::setRenderableType(QEgl::API api) +{ +#if defined(EGL_RENDERABLE_TYPE) +#if defined(QT_OPENGL_ES_2) + if (api == QEgl::OpenGL) + setValue(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT); +#elif defined(QT_OPENGL_ES) + if (api == QEgl::OpenGL) + setValue(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT); +#endif +#if defined(EGL_OPENVG_BIT) + if (api == QEgl::OpenVG) + setValue(EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT); +#endif +#else + Q_UNUSED(api); +#endif +} + +// Reduce the complexity of a configuration request to ask for less +// because the previous request did not result in success. Returns +// true if the complexity was reduced, or false if no further +// reductions in complexity are possible. +bool QEglProperties::reduceConfiguration() +{ + if (removeValue(EGL_SAMPLE_BUFFERS)) { + removeValue(EGL_SAMPLES); + return true; + } + if (removeValue(EGL_ALPHA_SIZE)) + return true; + if (removeValue(EGL_STENCIL_SIZE)) + return true; + if (removeValue(EGL_DEPTH_SIZE)) + return true; + return false; +} + +static void addTag(QString& str, const QString& tag) +{ + int lastnl = str.lastIndexOf(QLatin1String("\n")); + if (lastnl == -1) + lastnl = 0; + if ((str.length() - lastnl) >= 50) + str += QLatin1String("\n "); + str += tag; +} + +// Convert a property list to a string suitable for debug output. +QString QEglProperties::toString() const +{ + QString str; + int val; + + val = value(EGL_CONFIG_ID); + if (val != EGL_DONT_CARE) { + str += QLatin1String("id="); + str += QString::number(val); + str += QLatin1Char(' '); + } + +#ifdef EGL_RENDERABLE_TYPE + val = value(EGL_RENDERABLE_TYPE); + if (val != EGL_DONT_CARE) { + str += QLatin1String("type="); + QStringList types; + if ((val & EGL_OPENGL_ES_BIT) != 0) + types += QLatin1String("es1"); +#ifdef EGL_OPENGL_ES2_BIT + if ((val & EGL_OPENGL_ES2_BIT) != 0) + types += QLatin1String("es2"); +#endif + if ((val & EGL_OPENVG_BIT) != 0) + types += QLatin1String("vg"); + if ((val & ~7) != 0) + types += QString::number(val); + str += types.join(QLatin1String(",")); + } else { + str += QLatin1String("type=any"); + } +#else + str += QLatin1String("type=es1"); +#endif + + int red = value(EGL_RED_SIZE); + int green = value(EGL_GREEN_SIZE); + int blue = value(EGL_BLUE_SIZE); + int alpha = value(EGL_ALPHA_SIZE); + int bufferSize = value(EGL_BUFFER_SIZE); + if (bufferSize == (red + green + blue + alpha)) + bufferSize = EGL_DONT_CARE; + str += QLatin1String(" rgba="); + str += QString::number(red); + str += QLatin1Char(','); + str += QString::number(green); + str += QLatin1Char(','); + str += QString::number(blue); + str += QLatin1Char(','); + str += QString::number(alpha); + if (bufferSize != EGL_DONT_CARE) { + // Only report buffer size if different than r+g+b+a. + str += QLatin1String(" buffer-size="); + str += QString::number(bufferSize); + } + +#ifdef EGL_COLOR_BUFFER_TYPE + val = value(EGL_COLOR_BUFFER_TYPE); + if (val == EGL_LUMINANCE_BUFFER) { + addTag(str, QLatin1String(" color-buffer-type=luminance")); + } else if (val != EGL_DONT_CARE && val != EGL_RGB_BUFFER) { + addTag(str, QLatin1String(" color-buffer-type=")); + str += QString::number(val, 16); + } +#endif + + val = value(EGL_DEPTH_SIZE); + if (val != 0) { + addTag(str, QLatin1String(" depth=")); + str += QString::number(val); + } + + val = value(EGL_STENCIL_SIZE); + if (val != 0) { + addTag(str, QLatin1String(" stencil=")); + str += QString::number(val); + } + + val = value(EGL_SURFACE_TYPE); + if (val != EGL_DONT_CARE) { + addTag(str, QLatin1String(" surface-type=")); + QStringList types; + if ((val & EGL_WINDOW_BIT) != 0) + types += QLatin1String("window"); + if ((val & EGL_PIXMAP_BIT) != 0) + types += QLatin1String("pixmap"); + if ((val & EGL_PBUFFER_BIT) != 0) + types += QLatin1String("pbuffer"); +#ifdef EGL_VG_COLORSPACE_LINEAR_BIT + if ((val & EGL_VG_COLORSPACE_LINEAR_BIT) != 0) + types += QLatin1String("vg-colorspace-linear"); +#endif +#ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT + if ((val & EGL_VG_ALPHA_FORMAT_PRE_BIT) != 0) + types += QLatin1String("vg-alpha-format-pre"); +#endif + if ((val & ~(EGL_WINDOW_BIT | EGL_PIXMAP_BIT | EGL_PBUFFER_BIT +#ifdef EGL_VG_COLORSPACE_LINEAR_BIT + | EGL_VG_COLORSPACE_LINEAR_BIT +#endif +#ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT + | EGL_VG_ALPHA_FORMAT_PRE_BIT +#endif + )) != 0) { + types += QString::number(val); + } + str += types.join(QLatin1String(",")); + } + + val = value(EGL_CONFIG_CAVEAT); + if (val != EGL_DONT_CARE) { + addTag(str, QLatin1String(" caveat=")); + if (val == EGL_NONE) + str += QLatin1String("none"); + else if (val == EGL_SLOW_CONFIG) + str += QLatin1String("slow"); + else if (val == EGL_NON_CONFORMANT_CONFIG) + str += QLatin1String("non-conformant"); + else + str += QString::number(val, 16); + } + + val = value(EGL_LEVEL); + if (val != 0) { + addTag(str, QLatin1String(" level=")); + str += QString::number(val); + } + + int width, height, pixels; + width = value(EGL_MAX_PBUFFER_WIDTH); + height = value(EGL_MAX_PBUFFER_HEIGHT); + pixels = value(EGL_MAX_PBUFFER_PIXELS); + if (height != EGL_DONT_CARE || width != EGL_DONT_CARE) { + addTag(str, QLatin1String(" max-pbuffer-size=")); + str += QString::number(width); + str += QLatin1Char('x'); + str += QString::number(height); + if (pixels != (width * height)) { + addTag(str, QLatin1String(" max-pbuffer-pixels=")); + str += QString::number(pixels); + } + } + + val = value(EGL_NATIVE_RENDERABLE); + if (val != EGL_DONT_CARE) { + if (val) + addTag(str, QLatin1String(" native-renderable=true")); + else + addTag(str, QLatin1String(" native-renderable=false")); + } + + val = value(EGL_NATIVE_VISUAL_ID); + if (val != EGL_DONT_CARE) { + addTag(str, QLatin1String(" visual-id=")); + str += QString::number(val); + } + + val = value(EGL_NATIVE_VISUAL_TYPE); + if (val != EGL_DONT_CARE) { + addTag(str, QLatin1String(" visual-type=")); + str += QString::number(val); + } + +#ifdef EGL_PRESERVED_RESOURCES + val = value(EGL_PRESERVED_RESOURCES); + if (val != EGL_DONT_CARE) { + if (val) + addTag(str, QLatin1String(" preserved-resources=true")); + else + addTag(str, QLatin1String(" preserved-resources=false")); + } +#endif + + val = value(EGL_SAMPLES); + if (val != 0) { + addTag(str, QLatin1String(" samples=")); + str += QString::number(val); + } + + val = value(EGL_SAMPLE_BUFFERS); + if (val != 0) { + addTag(str, QLatin1String(" sample-buffers=")); + str += QString::number(val); + } + + val = value(EGL_TRANSPARENT_TYPE); + if (val == EGL_TRANSPARENT_RGB) { + addTag(str, QLatin1String(" transparent-rgb=")); + str += QString::number(value(EGL_TRANSPARENT_RED_VALUE)); + str += QLatin1Char(','); + str += QString::number(value(EGL_TRANSPARENT_GREEN_VALUE)); + str += QLatin1Char(','); + str += QString::number(value(EGL_TRANSPARENT_BLUE_VALUE)); + } + +#if defined(EGL_BIND_TO_TEXTURE_RGB) && defined(EGL_BIND_TO_TEXTURE_RGBA) + val = value(EGL_BIND_TO_TEXTURE_RGB); + int val2 = value(EGL_BIND_TO_TEXTURE_RGBA); + if (val != EGL_DONT_CARE || val2 != EGL_DONT_CARE) { + addTag(str, QLatin1String(" bind-texture=")); + if (val == EGL_TRUE) + str += QLatin1String("rgb"); + else + str += QLatin1String("no-rgb"); + if (val2 == EGL_TRUE) + str += QLatin1String(",rgba"); + else + str += QLatin1String(",no-rgba"); + } +#endif + +#ifdef EGL_MIN_SWAP_INTERVAL + val = value(EGL_MIN_SWAP_INTERVAL); + if (val != EGL_DONT_CARE) { + addTag(str, QLatin1String(" min-swap-interval=")); + str += QString::number(val); + } +#endif + +#ifdef EGL_MIN_SWAP_INTERVAL + val = value(EGL_MAX_SWAP_INTERVAL); + if (val != EGL_DONT_CARE) { + addTag(str, QLatin1String(" max-swap-interval=")); + str += QString::number(val); + } +#endif + +#ifdef EGL_LUMINANCE_SIZE + val = value(EGL_LUMINANCE_SIZE); + if (val != 0) { + addTag(str, QLatin1String(" luminance=")); + str += QString::number(val); + } +#endif + +#ifdef EGL_ALPHA_MASK_SIZE + val = value(EGL_ALPHA_MASK_SIZE); + if (val != 0) { + addTag(str, QLatin1String(" alpha-mask=")); + str += QString::number(val); + } +#endif + +#ifdef EGL_CONFORMANT + val = value(EGL_CONFORMANT); + if (val != 0) { + if (val) + addTag(str, QLatin1String(" conformant=true")); + else + addTag(str, QLatin1String(" conformant=false")); + } +#endif + + return str; +} + +QT_END_NAMESPACE + + diff --git a/src/gui/egl/qeglproperties_p.h b/src/gui/egl/qeglproperties_p.h new file mode 100644 index 0000000..3570f80 --- /dev/null +++ b/src/gui/egl/qeglproperties_p.h @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QEGLPROPERTIES_P_H +#define QEGLPROPERTIES_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the QGLWidget class. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_INCLUDE_NAMESPACE + +#if defined(QT_GLES_EGL) +#include +#else +#include +#endif + +#if defined(Q_WS_X11) +// If included , then the global namespace +// may have been polluted with X #define's. The following makes sure +// the X11 headers were included properly and then cleans things up. +#include +#include +#undef Bool +#undef Status +#undef None +#undef KeyPress +#undef KeyRelease +#undef FocusIn +#undef FocusOut +#undef Type +#undef FontChange +#undef CursorShape +#endif + +QT_END_INCLUDE_NAMESPACE + +QT_BEGIN_NAMESPACE + +namespace QEgl { + enum API + { + OpenGL, + OpenVG + }; + + enum PixelFormatMatch + { + ExactPixelFormat, + BestPixelFormat + }; +}; + +class QX11Info; +class QPaintDevice; + +class Q_GUI_EXPORT QEglProperties +{ +public: + QEglProperties(); + QEglProperties(const QEglProperties& other) : props(other.props) {} + ~QEglProperties() {} + + int value(int name) const; + void setValue(int name, int value); + bool removeValue(int name); + bool isEmpty() const { return props[0] == EGL_NONE; } + + const int *properties() const { return props.constData(); } + + void setPixelFormat(QImage::Format pixelFormat); +#ifdef Q_WS_X11 + void setVisualFormat(const QX11Info *xinfo); +#endif + void setRenderableType(QEgl::API api); + + void setPaintDeviceFormat(QPaintDevice *dev); + + bool reduceConfiguration(); + + QString toString() const; + +private: + QVarLengthArray props; +}; + +QT_END_NAMESPACE + +#endif // QEGLPROPERTIES_P_H diff --git a/src/gui/gui.pro b/src/gui/gui.pro index 329fb01..b77bfdc 100644 --- a/src/gui/gui.pro +++ b/src/gui/gui.pro @@ -35,6 +35,8 @@ include(util/util.pri) include(statemachine/statemachine.pri) include(math3d/math3d.pri) +contains(QT_CONFIG, egl): include(egl/egl.pri) + embedded: QT += network QMAKE_LIBS += $$QMAKE_LIBS_GUI diff --git a/src/opengl/opengl.pro b/src/opengl/opengl.pro index 73af174..c92b8cf 100644 --- a/src/opengl/opengl.pro +++ b/src/opengl/opengl.pro @@ -62,12 +62,9 @@ x11 { contains(QT_CONFIG, opengles1)|contains(QT_CONFIG, opengles1cl)|contains(QT_CONFIG, opengles2) { SOURCES += qgl_x11egl.cpp \ qglpixelbuffer_egl.cpp \ - qgl_egl.cpp \ - qegl.cpp \ - qegl_x11egl.cpp + qgl_egl.cpp - HEADERS += qegl_p.h \ - qgl_egl_p.h + HEADERS += qgl_egl_p.h } else { SOURCES += qgl_x11.cpp \ @@ -93,13 +90,10 @@ win32:!wince*: { wince*: { SOURCES += qgl_wince.cpp \ qglpixelbuffer_egl.cpp \ - qgl_egl.cpp \ - qegl.cpp \ - qegl_wince.cpp + qgl_egl.cpp HEADERS += qgl_cl_p.h \ qgl_egl_p.h \ - qegl_p.h } embedded { @@ -108,15 +102,12 @@ embedded { qglpixelbuffer_egl.cpp \ qglscreen_qws.cpp \ qglwindowsurface_qws.cpp \ - qegl.cpp \ - qegl_qws.cpp \ qgl_egl.cpp HEADERS += qglpaintdevice_qws_p.h \ qglscreen_qws.h \ qglwindowsurface_qws_p.h \ - qgl_egl_p.h \ - qegl_p.h + qgl_egl_p.h contains(QT_CONFIG, fontconfig) { include($$QT_SOURCE_TREE/config.tests/unix/freetype/freetype.pri) diff --git a/src/opengl/qegl.cpp b/src/opengl/qegl.cpp deleted file mode 100644 index 61c7427..0000000 --- a/src/opengl/qegl.cpp +++ /dev/null @@ -1,842 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtOpenGL module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://www.qtsoftware.com/contact. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include -#include -#include -#include "qegl_p.h" - -#if defined(QT_OPENGL_ES) || defined(QT_OPENVG) - -QT_BEGIN_NAMESPACE - -QEglContext::QEglContext() -{ - apiType = OpenGL; - dpy = EGL_NO_DISPLAY; - ctx = EGL_NO_CONTEXT; - surf = EGL_NO_SURFACE; - cfg = 0; - share = false; - reserved = 0; -} - -QEglContext::~QEglContext() -{ - destroy(); -} - -bool QEglContext::isValid() const -{ - return (ctx != EGL_NO_CONTEXT); -} - -bool QEglContext::isSharing() const -{ - return share; -} - -// Open the EGL display associated with "device". -bool QEglContext::openDisplay(QPaintDevice *device) -{ - if (dpy == EGL_NO_DISPLAY) - dpy = defaultDisplay(device); - return (dpy != EGL_NO_DISPLAY); -} - -// Choose a configuration that matches "properties". -bool QEglContext::chooseConfig - (const QEglProperties& properties, PixelFormatMatch match) -{ - QEglProperties props(properties); - EGLConfig *configs; - EGLint matching, size; - do { - // Get the number of matching configurations for this set of properties. - matching = 0; - if (!eglChooseConfig(dpy, props.properties(), 0, 256, &matching) || !matching) - continue; - - // If we want the best pixel format, then return the first - // matching configuration. - if (match == BestPixelFormat) { - eglChooseConfig(dpy, props.properties(), &cfg, 1, &matching); - if (matching < 1) - continue; - return true; - } - - // Fetch all of the matching configurations and find the - // first that matches the pixel format we wanted. - size = matching; - configs = new EGLConfig [size]; - eglChooseConfig(dpy, props.properties(), configs, size, &matching); - for (EGLint index = 0; index < size; ++index) { - EGLint red, green, blue, alpha; - eglGetConfigAttrib(dpy, configs[index], EGL_RED_SIZE, &red); - eglGetConfigAttrib(dpy, configs[index], EGL_GREEN_SIZE, &green); - eglGetConfigAttrib(dpy, configs[index], EGL_BLUE_SIZE, &blue); - eglGetConfigAttrib(dpy, configs[index], EGL_ALPHA_SIZE, &alpha); - if (red == props.value(EGL_RED_SIZE) && - green == props.value(EGL_GREEN_SIZE) && - blue == props.value(EGL_BLUE_SIZE) && - (props.value(EGL_ALPHA_SIZE) == 0 || - alpha == props.value(EGL_ALPHA_SIZE))) { - cfg = configs[index]; - delete [] configs; - return true; - } - } - delete [] configs; - } while (props.reduceConfiguration()); - -#ifdef EGL_BIND_TO_TEXTURE_RGBA - // Don't report an error just yet if we failed to get a pbuffer - // configuration with texture rendering. Only report failure if - // we cannot get any pbuffer configurations at all. - if (props.value(EGL_BIND_TO_TEXTURE_RGBA) == EGL_DONT_CARE && - props.value(EGL_BIND_TO_TEXTURE_RGB) == EGL_DONT_CARE) -#endif - { - qWarning() << "QEglContext::chooseConfig(): Could not find a suitable EGL configuration"; - qWarning() << "Requested:" << props.toString(); - qWarning() << "Available:"; - dumpAllConfigs(); - } - return false; -} - -// Create the EGLContext. -bool QEglContext::createContext(QEglContext *shareContext) -{ - // We need to select the correct API before calling eglCreateContext(). -#ifdef EGL_OPENGL_ES_API - if (apiType == OpenGL) - eglBindAPI(EGL_OPENGL_ES_API); -#endif -#ifdef EGL_OPENVG_API - if (apiType == OpenVG) - eglBindAPI(EGL_OPENVG_API); -#endif - - // Create a new context for the configuration. - QEglProperties contextProps; -#if defined(QT_OPENGL_ES_2) - if (apiType == OpenGL) - contextProps.setValue(EGL_CONTEXT_CLIENT_VERSION, 2); -#endif - if (shareContext && shareContext->ctx == EGL_NO_CONTEXT) - shareContext = 0; - if (shareContext) { - ctx = eglCreateContext(dpy, cfg, shareContext->ctx, contextProps.properties()); - if (ctx == EGL_NO_CONTEXT) { - qWarning() << "QEglContext::createContext(): Could not share context:" << errorString(eglGetError()); - shareContext = 0; - } - } - if (ctx == EGL_NO_CONTEXT) { - ctx = eglCreateContext(dpy, cfg, 0, contextProps.properties()); - if (ctx == EGL_NO_CONTEXT) { - qWarning() << "QEglContext::createContext(): Unable to create EGL context:" << errorString(eglGetError()); - return false; - } - } - share = (shareContext != 0); - return true; -} - -// Recreate the surface for a paint device because the native id has changed. -bool QEglContext::recreateSurface(QPaintDevice *device) -{ - // Bail out if the surface has not been created for the first time yet. - if (surf == EGL_NO_SURFACE) - return true; - - // Destroy the old surface. - eglDestroySurface(dpy, surf); - - // Create a new one. - return createSurface(device); -} - -void QEglContext::destroy() -{ - if (ctx != EGL_NO_CONTEXT) - eglDestroyContext(dpy, ctx); - dpy = EGL_NO_DISPLAY; - ctx = EGL_NO_CONTEXT; - surf = EGL_NO_SURFACE; - cfg = 0; - share = false; -} - -bool QEglContext::makeCurrent() -{ - if(ctx == EGL_NO_CONTEXT) { - qWarning() << "QEglContext::makeCurrent(): Cannot make invalid context current"; - return false; - } - - bool ok = eglMakeCurrent(dpy, surf, surf, ctx); - if (!ok) { - EGLint err = eglGetError(); - qWarning() << "QEglContext::makeCurrent():" << errorString(err); - } - return ok; -} - -bool QEglContext::doneCurrent() -{ - // If the context is invalid, we assume that an error was reported - // when makeCurrent() was called. - if (ctx == EGL_NO_CONTEXT) - return false; - - // We need to select the correct API before calling eglMakeCurrent() - // with EGL_NO_CONTEXT because threads can have both OpenGL and OpenVG - // contexts active at the same time. -#ifdef EGL_OPENGL_ES_API - if (apiType == OpenGL) - eglBindAPI(EGL_OPENGL_ES_API); -#endif -#ifdef EGL_OPENVG_API - if (apiType == OpenVG) - eglBindAPI(EGL_OPENVG_API); -#endif - - bool ok = eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - if (!ok) { - EGLint err = eglGetError(); - qWarning() << "QEglContext::doneCurrent():" << errorString(err); - } - return ok; -} - -bool QEglContext::swapBuffers() -{ - if(ctx == EGL_NO_CONTEXT) - return false; - - bool ok = eglSwapBuffers(dpy, surf); - if (!ok) { - EGLint err = eglGetError(); - qWarning() << "QEglContext::swapBuffers():" << errorString(err); - } - return ok; -} - -// Wait for native rendering operations to complete before starting -// to use OpenGL/OpenVG operations. -void QEglContext::waitNative() -{ -#ifdef EGL_CORE_NATIVE_ENGINE - eglWaitNative(EGL_CORE_NATIVE_ENGINE); -#endif -} - -// Wait for client OpenGL/OpenVG operations to complete before -// using native rendering operations. -void QEglContext::waitClient() -{ -#ifdef EGL_OPENGL_ES_API - if (apiType == OpenGL) { - eglBindAPI(EGL_OPENGL_ES_API); - eglWaitClient(); - } -#else - if (apiType == OpenGL) - eglWaitGL(); -#endif -#ifdef EGL_OPENVG_API - if (apiType == OpenVG) { - eglBindAPI(EGL_OPENVG_API); - eglWaitClient(); - } -#endif -} - -// Query the actual size of the EGL surface. -QSize QEglContext::surfaceSize() const -{ - int w, h; - eglQuerySurface(dpy, surf, EGL_WIDTH, &w); - eglQuerySurface(dpy, surf, EGL_HEIGHT, &h); - return QSize(w, h); -} - -// Query the value of a configuration attribute. -bool QEglContext::configAttrib(int name, EGLint *value) const -{ - return eglGetConfigAttrib(dpy, cfg, name, value); -} - -// Retrieve all of the properties on "cfg". If zero, return -// the context's configuration. -QEglProperties QEglContext::configProperties(EGLConfig cfg) const -{ - if (!cfg) - cfg = config(); - QEglProperties props; - for (int name = 0x3020; name <= 0x304F; ++name) { - EGLint value; - if (name != EGL_NONE && eglGetConfigAttrib(dpy, cfg, name, &value)) - props.setValue(name, value); - } - eglGetError(); // Clear the error state. - return props; -} - -// Initialize and return the default display. -EGLDisplay QEglContext::defaultDisplay(QPaintDevice *device) -{ - static EGLDisplay dpy = EGL_NO_DISPLAY; - if (dpy == EGL_NO_DISPLAY) { - dpy = getDisplay(device); - if (dpy == EGL_NO_DISPLAY) { - qWarning() << "QEglContext::defaultDisplay(): Cannot open EGL display"; - return EGL_NO_DISPLAY; - } - if (!eglInitialize(dpy, NULL, NULL)) { - EGLint err = eglGetError(); - qWarning() << "QEglContext::defaultDisplay(): Cannot initialize EGL display:" << errorString(err); - return EGL_NO_DISPLAY; - } -#ifdef EGL_OPENGL_ES_API - eglBindAPI(EGL_OPENGL_ES_API); -#endif - } - return dpy; -} - -// Return the error string associated with a specific code. -QString QEglContext::errorString(int code) -{ - static const char * const errors[] = { - "Success (0x3000)", // No tr - "Not initialized (0x3001)", // No tr - "Bad access (0x3002)", // No tr - "Bad alloc (0x3003)", // No tr - "Bad attribute (0x3004)", // No tr - "Bad config (0x3005)", // No tr - "Bad context (0x3006)", // No tr - "Bad current surface (0x3007)", // No tr - "Bad display (0x3008)", // No tr - "Bad match (0x3009)", // No tr - "Bad native pixmap (0x300A)", // No tr - "Bad native window (0x300B)", // No tr - "Bad parameter (0x300C)", // No tr - "Bad surface (0x300D)", // No tr - "Context lost (0x300E)" // No tr - }; - if (code >= 0x3000 && code <= 0x300E) { - return QString::fromLatin1(errors[code - 0x3000]); - } else { - return QLatin1String("0x") + QString::number(code, 16); - } -} - -// Dump all of the EGL configurations supported by the system. -void QEglContext::dumpAllConfigs() -{ - QEglProperties props; - EGLint count = 0; - if (!eglGetConfigs(dpy, 0, 0, &count)) - return; - if (count < 1) - return; - EGLConfig *configs = new EGLConfig [count]; - eglGetConfigs(dpy, configs, count, &count); - for (EGLint index = 0; index < count; ++index) { - props = configProperties(configs[index]); - qWarning() << props.toString(); - } - delete [] configs; -} - -// Initialize a property block. -QEglProperties::QEglProperties() -{ - props.append(EGL_NONE); -} - -// Fetch the current value associated with a property. -int QEglProperties::value(int name) const -{ - for (int index = 0; index < (props.size() - 1); index += 2) { - if (props[index] == name) - return props[index + 1]; - } - - // If the attribute has not been explicitly set, return the EGL default - // The following defaults were taken from the EGL 1.4 spec: - switch(name) { - case EGL_BUFFER_SIZE: return 0; - case EGL_RED_SIZE: return 0; - case EGL_GREEN_SIZE: return 0; - case EGL_BLUE_SIZE: return 0; - case EGL_ALPHA_SIZE: return 0; -#if defined(EGL_LUMINANCE_SIZE) - case EGL_LUMINANCE_SIZE: return 0; -#endif -#if defined(EGL_ALPHA_MASK_SIZE) - case EGL_ALPHA_MASK_SIZE: return 0; -#endif - case EGL_BIND_TO_TEXTURE_RGB: return EGL_DONT_CARE; - case EGL_BIND_TO_TEXTURE_RGBA: return EGL_DONT_CARE; -#if defined(EGL_COLOR_BUFFER_TYPE) - case EGL_COLOR_BUFFER_TYPE: return EGL_RGB_BUFFER; -#endif - case EGL_CONFIG_CAVEAT: return EGL_DONT_CARE; - case EGL_CONFIG_ID: return EGL_DONT_CARE; - case EGL_DEPTH_SIZE: return 0; - case EGL_LEVEL: return 0; - case EGL_NATIVE_RENDERABLE: return EGL_DONT_CARE; - case EGL_NATIVE_VISUAL_TYPE: return EGL_DONT_CARE; - case EGL_MAX_SWAP_INTERVAL: return EGL_DONT_CARE; - case EGL_MIN_SWAP_INTERVAL: return EGL_DONT_CARE; -#if defined(EGL_RENDERABLE_TYPE) - case EGL_RENDERABLE_TYPE: return EGL_OPENGL_ES_BIT; -#endif - case EGL_SAMPLE_BUFFERS: return 0; - case EGL_SAMPLES: return 0; - case EGL_STENCIL_SIZE: return 0; - case EGL_SURFACE_TYPE: return EGL_WINDOW_BIT; - case EGL_TRANSPARENT_TYPE: return EGL_NONE; - case EGL_TRANSPARENT_RED_VALUE: return EGL_DONT_CARE; - case EGL_TRANSPARENT_GREEN_VALUE: return EGL_DONT_CARE; - case EGL_TRANSPARENT_BLUE_VALUE: return EGL_DONT_CARE; - -#if defined(EGL_VERSION_1_3) - case EGL_CONFORMANT: return 0; - case EGL_MATCH_NATIVE_PIXMAP: return EGL_NONE; -#endif - - case EGL_MAX_PBUFFER_HEIGHT: - case EGL_MAX_PBUFFER_WIDTH: - case EGL_MAX_PBUFFER_PIXELS: - case EGL_NATIVE_VISUAL_ID: - case EGL_NONE: - qWarning("QEglProperties::value() - Attibute %d does not affect config selection", name); - return EGL_DONT_CARE; - default: - qWarning("QEglProperties::value() - Attibute %d is unknown in EGL <=1.4", name); - return EGL_DONT_CARE; - } -} - -// Set the value associated with a property, replacing an existing -// value if there is one. -void QEglProperties::setValue(int name, int value) -{ - for (int index = 0; index < (props.size() - 1); index += 2) { - if (props[index] == name) { - props[index + 1] = value; - return; - } - } - props[props.size() - 1] = name; - props.append(value); - props.append(EGL_NONE); -} - -// Remove a property value. Returns false if the property is not present. -bool QEglProperties::removeValue(int name) -{ - for (int index = 0; index < (props.size() - 1); index += 2) { - if (props[index] == name) { - while ((index + 2) < props.size()) { - props[index] = props[index + 2]; - ++index; - } - props.resize(props.size() - 2); - return true; - } - } - return false; -} - -// Sets the red, green, blue, and alpha sizes based on a pixel format. -// Normally used to match a configuration request to the screen format. -void QEglProperties::setPixelFormat(QImage::Format pixelFormat) -{ - int red, green, blue, alpha; - switch (pixelFormat) { - case QImage::Format_RGB32: - case QImage::Format_RGB888: - red = green = blue = 8; alpha = 0; break; - case QImage::Format_ARGB32: - case QImage::Format_ARGB32_Premultiplied: - red = green = blue = alpha = 8; break; - case QImage::Format_RGB16: - red = 5; green = 6; blue = 5; alpha = 0; break; - case QImage::Format_ARGB8565_Premultiplied: - red = 5; green = 6; blue = 5; alpha = 8; break; - case QImage::Format_RGB666: - red = green = blue = 6; alpha = 0; break; - case QImage::Format_ARGB6666_Premultiplied: - red = green = blue = alpha = 6; break; - case QImage::Format_RGB555: - red = green = blue = 5; alpha = 0; break; - case QImage::Format_ARGB8555_Premultiplied: - red = green = blue = 5; alpha = 8; break; - case QImage::Format_RGB444: - red = green = blue = 4; alpha = 0; break; - case QImage::Format_ARGB4444_Premultiplied: - red = green = blue = alpha = 4; break; - default: - qWarning() << "QEglProperties::setPixelFormat(): Unsupported pixel format"; - red = green = blue = alpha = 1; break; - } - setValue(EGL_RED_SIZE, red); - setValue(EGL_GREEN_SIZE, green); - setValue(EGL_BLUE_SIZE, blue); - setValue(EGL_ALPHA_SIZE, alpha); -} - -void QEglProperties::setRenderableType(int api) -{ -#if defined(EGL_RENDERABLE_TYPE) -#if defined(QT_OPENGL_ES_2) - if (api == QEglContext::OpenGL) - setValue(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT); -#elif defined(QT_OPENGL_ES) - if (api == QEglContext::OpenGL) - setValue(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT); -#endif -#if defined(EGL_OPENVG_BIT) - if (api == QEglContext::OpenVG) - setValue(EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT); -#endif -#else - Q_UNUSED(api); -#endif -} - -// Reduce the complexity of a configuration request to ask for less -// because the previous request did not result in success. Returns -// true if the complexity was reduced, or false if no further -// reductions in complexity are possible. -bool QEglProperties::reduceConfiguration() -{ - if (removeValue(EGL_SAMPLE_BUFFERS)) { - removeValue(EGL_SAMPLES); - return true; - } - if (removeValue(EGL_ALPHA_SIZE)) - return true; - if (removeValue(EGL_STENCIL_SIZE)) - return true; - if (removeValue(EGL_DEPTH_SIZE)) - return true; - return false; -} - -static void addTag(QString& str, const QString& tag) -{ - int lastnl = str.lastIndexOf(QLatin1String("\n")); - if (lastnl == -1) - lastnl = 0; - if ((str.length() - lastnl) >= 50) - str += QLatin1String("\n "); - str += tag; -} - -// Convert a property list to a string suitable for debug output. -QString QEglProperties::toString() const -{ - QString str; - int val; - - val = value(EGL_CONFIG_ID); - if (val != EGL_DONT_CARE) { - str += QLatin1String("id="); - str += QString::number(val); - str += QLatin1Char(' '); - } - -#ifdef EGL_RENDERABLE_TYPE - val = value(EGL_RENDERABLE_TYPE); - if (val != EGL_DONT_CARE) { - str += QLatin1String("type="); - QStringList types; - if ((val & EGL_OPENGL_ES_BIT) != 0) - types += QLatin1String("es1"); -#ifdef EGL_OPENGL_ES2_BIT - if ((val & EGL_OPENGL_ES2_BIT) != 0) - types += QLatin1String("es2"); -#endif - if ((val & EGL_OPENVG_BIT) != 0) - types += QLatin1String("vg"); - if ((val & ~7) != 0) - types += QString::number(val); - str += types.join(QLatin1String(",")); - } else { - str += QLatin1String("type=any"); - } -#else - str += QLatin1String("type=es1"); -#endif - - int red = value(EGL_RED_SIZE); - int green = value(EGL_GREEN_SIZE); - int blue = value(EGL_BLUE_SIZE); - int alpha = value(EGL_ALPHA_SIZE); - int bufferSize = value(EGL_BUFFER_SIZE); - if (bufferSize == (red + green + blue + alpha)) - bufferSize = EGL_DONT_CARE; - str += QLatin1String(" rgba="); - str += QString::number(red); - str += QLatin1Char(','); - str += QString::number(green); - str += QLatin1Char(','); - str += QString::number(blue); - str += QLatin1Char(','); - str += QString::number(alpha); - if (bufferSize != EGL_DONT_CARE) { - // Only report buffer size if different than r+g+b+a. - str += QLatin1String(" buffer-size="); - str += QString::number(bufferSize); - } - -#ifdef EGL_COLOR_BUFFER_TYPE - val = value(EGL_COLOR_BUFFER_TYPE); - if (val == EGL_LUMINANCE_BUFFER) { - addTag(str, QLatin1String(" color-buffer-type=luminance")); - } else if (val != EGL_DONT_CARE && val != EGL_RGB_BUFFER) { - addTag(str, QLatin1String(" color-buffer-type=")); - str += QString::number(val, 16); - } -#endif - - val = value(EGL_DEPTH_SIZE); - if (val != 0) { - addTag(str, QLatin1String(" depth=")); - str += QString::number(val); - } - - val = value(EGL_STENCIL_SIZE); - if (val != 0) { - addTag(str, QLatin1String(" stencil=")); - str += QString::number(val); - } - - val = value(EGL_SURFACE_TYPE); - if (val != EGL_DONT_CARE) { - addTag(str, QLatin1String(" surface-type=")); - QStringList types; - if ((val & EGL_WINDOW_BIT) != 0) - types += QLatin1String("window"); - if ((val & EGL_PIXMAP_BIT) != 0) - types += QLatin1String("pixmap"); - if ((val & EGL_PBUFFER_BIT) != 0) - types += QLatin1String("pbuffer"); -#ifdef EGL_VG_COLORSPACE_LINEAR_BIT - if ((val & EGL_VG_COLORSPACE_LINEAR_BIT) != 0) - types += QLatin1String("vg-colorspace-linear"); -#endif -#ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT - if ((val & EGL_VG_ALPHA_FORMAT_PRE_BIT) != 0) - types += QLatin1String("vg-alpha-format-pre"); -#endif - if ((val & ~(EGL_WINDOW_BIT | EGL_PIXMAP_BIT | EGL_PBUFFER_BIT -#ifdef EGL_VG_COLORSPACE_LINEAR_BIT - | EGL_VG_COLORSPACE_LINEAR_BIT -#endif -#ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT - | EGL_VG_ALPHA_FORMAT_PRE_BIT -#endif - )) != 0) { - types += QString::number(val); - } - str += types.join(QLatin1String(",")); - } - - val = value(EGL_CONFIG_CAVEAT); - if (val != EGL_DONT_CARE) { - addTag(str, QLatin1String(" caveat=")); - if (val == EGL_NONE) - str += QLatin1String("none"); - else if (val == EGL_SLOW_CONFIG) - str += QLatin1String("slow"); - else if (val == EGL_NON_CONFORMANT_CONFIG) - str += QLatin1String("non-conformant"); - else - str += QString::number(val, 16); - } - - val = value(EGL_LEVEL); - if (val != 0) { - addTag(str, QLatin1String(" level=")); - str += QString::number(val); - } - - int width, height, pixels; - width = value(EGL_MAX_PBUFFER_WIDTH); - height = value(EGL_MAX_PBUFFER_HEIGHT); - pixels = value(EGL_MAX_PBUFFER_PIXELS); - if (height != EGL_DONT_CARE || width != EGL_DONT_CARE) { - addTag(str, QLatin1String(" max-pbuffer-size=")); - str += QString::number(width); - str += QLatin1Char('x'); - str += QString::number(height); - if (pixels != (width * height)) { - addTag(str, QLatin1String(" max-pbuffer-pixels=")); - str += QString::number(pixels); - } - } - - val = value(EGL_NATIVE_RENDERABLE); - if (val != EGL_DONT_CARE) { - if (val) - addTag(str, QLatin1String(" native-renderable=true")); - else - addTag(str, QLatin1String(" native-renderable=false")); - } - - val = value(EGL_NATIVE_VISUAL_ID); - if (val != EGL_DONT_CARE) { - addTag(str, QLatin1String(" visual-id=")); - str += QString::number(val); - } - - val = value(EGL_NATIVE_VISUAL_TYPE); - if (val != EGL_DONT_CARE) { - addTag(str, QLatin1String(" visual-type=")); - str += QString::number(val); - } - -#ifdef EGL_PRESERVED_RESOURCES - val = value(EGL_PRESERVED_RESOURCES); - if (val != EGL_DONT_CARE) { - if (val) - addTag(str, QLatin1String(" preserved-resources=true")); - else - addTag(str, QLatin1String(" preserved-resources=false")); - } -#endif - - val = value(EGL_SAMPLES); - if (val != 0) { - addTag(str, QLatin1String(" samples=")); - str += QString::number(val); - } - - val = value(EGL_SAMPLE_BUFFERS); - if (val != 0) { - addTag(str, QLatin1String(" sample-buffers=")); - str += QString::number(val); - } - - val = value(EGL_TRANSPARENT_TYPE); - if (val == EGL_TRANSPARENT_RGB) { - addTag(str, QLatin1String(" transparent-rgb=")); - str += QString::number(value(EGL_TRANSPARENT_RED_VALUE)); - str += QLatin1Char(','); - str += QString::number(value(EGL_TRANSPARENT_GREEN_VALUE)); - str += QLatin1Char(','); - str += QString::number(value(EGL_TRANSPARENT_BLUE_VALUE)); - } - -#if defined(EGL_BIND_TO_TEXTURE_RGB) && defined(EGL_BIND_TO_TEXTURE_RGBA) - val = value(EGL_BIND_TO_TEXTURE_RGB); - int val2 = value(EGL_BIND_TO_TEXTURE_RGBA); - if (val != EGL_DONT_CARE || val2 != EGL_DONT_CARE) { - addTag(str, QLatin1String(" bind-texture=")); - if (val == EGL_TRUE) - str += QLatin1String("rgb"); - else - str += QLatin1String("no-rgb"); - if (val2 == EGL_TRUE) - str += QLatin1String(",rgba"); - else - str += QLatin1String(",no-rgba"); - } -#endif - -#ifdef EGL_MIN_SWAP_INTERVAL - val = value(EGL_MIN_SWAP_INTERVAL); - if (val != EGL_DONT_CARE) { - addTag(str, QLatin1String(" min-swap-interval=")); - str += QString::number(val); - } -#endif - -#ifdef EGL_MIN_SWAP_INTERVAL - val = value(EGL_MAX_SWAP_INTERVAL); - if (val != EGL_DONT_CARE) { - addTag(str, QLatin1String(" max-swap-interval=")); - str += QString::number(val); - } -#endif - -#ifdef EGL_LUMINANCE_SIZE - val = value(EGL_LUMINANCE_SIZE); - if (val != 0) { - addTag(str, QLatin1String(" luminance=")); - str += QString::number(val); - } -#endif - -#ifdef EGL_ALPHA_MASK_SIZE - val = value(EGL_ALPHA_MASK_SIZE); - if (val != 0) { - addTag(str, QLatin1String(" alpha-mask=")); - str += QString::number(val); - } -#endif - -#ifdef EGL_CONFORMANT - val = value(EGL_CONFORMANT); - if (val != 0) { - if (val) - addTag(str, QLatin1String(" conformant=true")); - else - addTag(str, QLatin1String(" conformant=false")); - } -#endif - - return str; -} - -QT_END_NAMESPACE - -#endif // QT_OPENGL_ES || QT_OPENVG diff --git a/src/opengl/qegl_p.h b/src/opengl/qegl_p.h deleted file mode 100644 index 4e46965..0000000 --- a/src/opengl/qegl_p.h +++ /dev/null @@ -1,188 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtOpenGL module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://www.qtsoftware.com/contact. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QEGL_P_H -#define QEGL_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of the QGLWidget class. This header file may change from -// version to version without notice, or even be removed. -// -// We mean it. -// - -#include "QtCore/qvarlengtharray.h" -#include "QtCore/qsize.h" -#include "QtGui/qimage.h" - -#if defined(QT_OPENGL_ES) || defined(QT_OPENVG) - -QT_BEGIN_INCLUDE_NAMESPACE -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENVG) -#include -#else -#include -#endif -#if !defined(EGL_VERSION_1_3) && !defined(QEGL_NATIVE_TYPES_DEFINED) -#undef EGLNativeWindowType -#undef EGLNativePixmapType -#undef EGLNativeDisplayType -typedef NativeWindowType EGLNativeWindowType; -typedef NativePixmapType EGLNativePixmapType; -typedef NativeDisplayType EGLNativeDisplayType; -#define QEGL_NATIVE_TYPES_DEFINED 1 -#endif -QT_END_INCLUDE_NAMESPACE - -class QX11Info; -class QPaintDevice; -class QImage; -class QPixmap; -class QWidget; - -QT_BEGIN_NAMESPACE - -class Q_OPENGL_EXPORT QEglProperties -{ -public: - QEglProperties(); - QEglProperties(const QEglProperties& other) : props(other.props) {} - ~QEglProperties() {} - - int value(int name) const; - void setValue(int name, int value); - bool removeValue(int name); - - const int *properties() const { return props.constData(); } - - void setPixelFormat(QImage::Format pixelFormat); -#ifdef Q_WS_X11 - void setVisualFormat(const QX11Info *xinfo); -#endif - void setRenderableType(int api); - - bool reduceConfiguration(); - - QString toString() const; - -private: - QVarLengthArray props; -}; - -class Q_OPENGL_EXPORT QEglContext -{ -public: - QEglContext(); - ~QEglContext(); - - enum API - { - OpenGL, - OpenVG - }; - - enum PixelFormatMatch - { - ExactPixelFormat, - BestPixelFormat - }; - - bool isValid() const; - bool isSharing() const; - - void setApi(QEglContext::API api) { apiType = api; } - bool openDisplay(QPaintDevice *device); - bool chooseConfig(const QEglProperties& properties, PixelFormatMatch match = ExactPixelFormat); - bool createContext(QEglContext *shareContext = 0); - bool createSurface(QPaintDevice *device); - bool recreateSurface(QPaintDevice *device); - void setSurface(EGLSurface surface) { surf = surface; } - - void destroy(); - - bool makeCurrent(); - bool doneCurrent(); - bool swapBuffers(); - - void waitNative(); - void waitClient(); - - QSize surfaceSize() const; - - bool configAttrib(int name, EGLint *value) const; - - void clearError() const { eglGetError(); } - - QEglContext::API api() const { return apiType; } - - EGLDisplay display() const { return dpy; } - EGLContext context() const { return ctx; } - EGLSurface surface() const { return surf; } - EGLConfig config() const { return cfg; } - - QEglProperties configProperties(EGLConfig cfg = 0) const; - - static EGLDisplay defaultDisplay(QPaintDevice *device); - static QString errorString(int code); - - void dumpAllConfigs(); - -private: - QEglContext::API apiType; - EGLDisplay dpy; - EGLContext ctx; - EGLSurface surf; - EGLConfig cfg; - bool share; - void *reserved; // For extension data in future versions. - - static EGLDisplay getDisplay(QPaintDevice *device); -}; - -QT_END_NAMESPACE - -#endif // QT_OPENGL_ES || QT_OPENVG - -#endif // QEGL_P_H diff --git a/src/opengl/qegl_qws.cpp b/src/opengl/qegl_qws.cpp deleted file mode 100644 index 89bee09..0000000 --- a/src/opengl/qegl_qws.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtOpenGL module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://www.qtsoftware.com/contact. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include -#include -#include "qegl_p.h" - -#if defined(QT_OPENGL_ES) || defined(QT_OPENVG) - -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -static QGLScreen *glScreenForDevice(QPaintDevice *device) -{ - QScreen *screen = qt_screen; - if (screen->classId() == QScreen::MultiClass) { - int screenNumber; - if (device && device->devType() == QInternal::Widget) - screenNumber = qApp->desktop()->screenNumber(static_cast(device)); - else - screenNumber = 0; - screen = screen->subScreens()[screenNumber]; - } - while (screen->classId() == QScreen::ProxyClass) { - screen = static_cast(screen)->screen(); - } - if (screen->classId() == QScreen::GLClass) - return static_cast(screen); - else - return 0; -} - -// Create the surface for a QPixmap, QImage, or QWidget. -bool QEglContext::createSurface(QPaintDevice *device) -{ - // Get the screen surface functions, which are used to create native ids. - QGLScreen *glScreen = glScreenForDevice(device); - if (!glScreen) - return false; - QGLScreenSurfaceFunctions *funcs = glScreen->surfaceFunctions(); - if (!funcs) - return false; - - // Create the native drawable for the paint device. - int devType = device->devType(); - EGLNativePixmapType pixmapDrawable = 0; - EGLNativeWindowType windowDrawable = 0; - bool ok; - if (devType == QInternal::Pixmap) { - ok = funcs->createNativePixmap(static_cast(device), &pixmapDrawable); - } else if (devType == QInternal::Image) { - ok = funcs->createNativeImage(static_cast(device), &pixmapDrawable); - } else { - ok = funcs->createNativeWindow(static_cast(device), &windowDrawable); - } - if (!ok) { - qWarning("QEglContext::createSurface(): Cannot create the native EGL drawable"); - return false; - } - - // Create the EGL surface to draw into, based on the native drawable. - if (devType == QInternal::Widget) - surf = eglCreateWindowSurface(dpy, cfg, windowDrawable, 0); - else - surf = eglCreatePixmapSurface(dpy, cfg, pixmapDrawable, 0); - if (surf == EGL_NO_SURFACE) { - qWarning("QEglContext::createSurface(): Unable to create EGL surface, error = 0x%x", eglGetError()); - return false; - } - return true; -} - -EGLDisplay QEglContext::getDisplay(QPaintDevice *device) -{ - Q_UNUSED(device); - return eglGetDisplay(EGLNativeDisplayType(EGL_DEFAULT_DISPLAY)); -} - -QT_END_NAMESPACE - -#endif // QT_OPENGL_ES || QT_OPENVG diff --git a/src/opengl/qegl_wince.cpp b/src/opengl/qegl_wince.cpp deleted file mode 100644 index b978bc6..0000000 --- a/src/opengl/qegl_wince.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtOpenGL module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://www.qtsoftware.com/contact. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include -#include -#include "qegl_p.h" - -#if defined(QT_OPENGL_ES) || defined(QT_OPENVG) - -#include - - -QT_BEGIN_NAMESPACE - -bool QEglContext::createSurface(QPaintDevice *device) -{ - // Create the native drawable for the paint device. - int devType = device->devType(); - EGLNativePixmapType pixmapDrawable = 0; - EGLNativeWindowType windowDrawable = 0; - bool ok; - if (devType == QInternal::Pixmap) { - pixmapDrawable = 0; - ok = (pixmapDrawable != 0); - } else if (devType == QInternal::Widget) { - windowDrawable = (EGLNativeWindowType)(static_cast(device))->winId(); - ok = (windowDrawable != 0); - } else { - ok = false; - } - if (!ok) { - qWarning("QEglContext::createSurface(): Cannot create the native EGL drawable"); - return false; - } - - // Create the EGL surface to draw into, based on the native drawable. - if (devType == QInternal::Widget) - surf = eglCreateWindowSurface(dpy, cfg, windowDrawable, 0); - else - surf = eglCreatePixmapSurface(dpy, cfg, pixmapDrawable, 0); - if (surf == EGL_NO_SURFACE) { - qWarning("QEglContext::createSurface(): Unable to create EGL surface, error = 0x%x", eglGetError()); - return false; - } - return true; -} - -EGLDisplay QEglContext::getDisplay(QPaintDevice *device) -{ - EGLDisplay dpy = 0; - HWND win = ((QWidget*)device)->winId(); - HDC myDc = GetDC(win); - if (!myDc) { - qWarning("QEglContext::defaultDisplay(): WinCE display is not open"); - } - dpy = eglGetDisplay(EGLNativeDisplayType(myDc)); - if (dpy == EGL_NO_DISPLAY) { - qWarning("QEglContext::defaultDisplay(): Falling back to EGL_DEFAULT_DISPLAY"); - dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); - } - return dpy; -} - -QT_END_NAMESPACE - -#endif // QT_OPENGL_ES || QT_OPENVG diff --git a/src/opengl/qegl_x11egl.cpp b/src/opengl/qegl_x11egl.cpp deleted file mode 100644 index 23d1ac6..0000000 --- a/src/opengl/qegl_x11egl.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtOpenGL module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://www.qtsoftware.com/contact. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include -#include -#include -#include "qegl_p.h" - -#if defined(QT_OPENGL_ES) || defined(QT_OPENVG) - -#if defined(Q_WS_X11) -#include -#include -#include -#endif - -QT_BEGIN_NAMESPACE - -bool QEglContext::createSurface(QPaintDevice *device) -{ - // Create the native drawable for the paint device. - int devType = device->devType(); - EGLNativePixmapType pixmapDrawable = 0; - EGLNativeWindowType windowDrawable = 0; - bool ok; - if (devType == QInternal::Pixmap) { - pixmapDrawable = (EGLNativePixmapType)(static_cast(device))->handle(); - ok = (pixmapDrawable != 0); - } else if (devType == QInternal::Widget) { - windowDrawable = (EGLNativeWindowType)(static_cast(device))->winId(); - ok = (windowDrawable != 0); - } else { - ok = false; - } - if (!ok) { - qWarning("QEglContext::createSurface(): Cannot create the native EGL drawable"); - return false; - } - - // Create the EGL surface to draw into, based on the native drawable. - if (devType == QInternal::Widget) - surf = eglCreateWindowSurface(dpy, cfg, windowDrawable, 0); - else - surf = eglCreatePixmapSurface(dpy, cfg, pixmapDrawable, 0); - - if (surf == EGL_NO_SURFACE) { - qWarning() << "QEglContext::createSurface(): Unable to create EGL surface:" - << errorString(eglGetError()); - return false; - } - return true; -} - -EGLDisplay QEglContext::getDisplay(QPaintDevice *device) -{ - Q_UNUSED(device); - Display *xdpy = QX11Info::display(); - if (!xdpy) { - qWarning("QEglContext::getDisplay(): X11 display is not open"); - return EGL_NO_DISPLAY; - } - return eglGetDisplay(EGLNativeDisplayType(xdpy)); -} - -static int countBits(unsigned long mask) -{ - int count = 0; - while (mask != 0) { - if (mask & 1) - ++count; - mask >>= 1; - } - return count; -} - -// Set the pixel format parameters from the visual in "xinfo". -void QEglProperties::setVisualFormat(const QX11Info *xinfo) -{ - if (!xinfo) - return; - Visual *visual = (Visual*)xinfo->visual(); - if (!visual) - return; - if (visual->c_class != TrueColor && visual->c_class != DirectColor) - return; - setValue(EGL_RED_SIZE, countBits(visual->red_mask)); - setValue(EGL_GREEN_SIZE, countBits(visual->green_mask)); - setValue(EGL_BLUE_SIZE, countBits(visual->blue_mask)); - setValue(EGL_ALPHA_SIZE, 0); // XXX -} - -QT_END_NAMESPACE - -#endif // QT_OPENGL_ES || QT_OPENVG diff --git a/src/opengl/qgl_egl_p.h b/src/opengl/qgl_egl_p.h index 2fb2e8f..d54036d 100644 --- a/src/opengl/qgl_egl_p.h +++ b/src/opengl/qgl_egl_p.h @@ -53,7 +53,7 @@ // We mean it. // -#include "qegl_p.h" +#include QT_BEGIN_NAMESPACE diff --git a/src/opengl/qgl_qws.cpp b/src/opengl/qgl_qws.cpp index 3b6ad63..a71a734 100644 --- a/src/opengl/qgl_qws.cpp +++ b/src/opengl/qgl_qws.cpp @@ -116,6 +116,57 @@ void qt_egl_add_platform_config(QEglProperties& props, QPaintDevice *device) props.setPixelFormat(glScreen->pixelFormat()); } +static bool qt_egl_create_surface + (QEglContext *context, QPaintDevice *device, + const QEglProperties *properties = 0) +{ + // Get the screen surface functions, which are used to create native ids. + QGLScreen *glScreen = glScreenForDevice(device); + if (!glScreen) + return false; + QGLScreenSurfaceFunctions *funcs = glScreen->surfaceFunctions(); + if (!funcs) + return false; + + // Create the native drawable for the paint device. + int devType = device->devType(); + EGLNativePixmapType pixmapDrawable = 0; + EGLNativeWindowType windowDrawable = 0; + bool ok; + if (devType == QInternal::Pixmap) { + ok = funcs->createNativePixmap(static_cast(device), &pixmapDrawable); + } else if (devType == QInternal::Image) { + ok = funcs->createNativeImage(static_cast(device), &pixmapDrawable); + } else { + ok = funcs->createNativeWindow(static_cast(device), &windowDrawable); + } + if (!ok) { + qWarning("QEglContext::createSurface(): Cannot create the native EGL drawable"); + return false; + } + + // Create the EGL surface to draw into, based on the native drawable. + const int *props; + if (properties) + props = properties->properties(); + else + props = 0; + EGLSurface surf; + if (devType == QInternal::Widget) { + surf = eglCreateWindowSurface + (context->display(), context->config(), windowDrawable, props); + } else { + surf = eglCreatePixmapSurface + (context->display(), context->config(), pixmapDrawable, props); + } + if (surf == EGL_NO_SURFACE) { + qWarning("QEglContext::createSurface(): Unable to create EGL surface, error = 0x%x", eglGetError()); + return false; + } + context->setSurface(surf); + return true; +} + bool QGLContext::chooseContext(const QGLContext* shareContext) { Q_D(QGLContext); @@ -131,7 +182,7 @@ bool QGLContext::chooseContext(const QGLContext* shareContext) // Get the display and initialize it. d->eglContext = new QEglContext(); - d->eglContext->setApi(QEglContext::OpenGL); + d->eglContext->setApi(QEgl::OpenGL); if (!d->eglContext->openDisplay(device())) { delete d->eglContext; d->eglContext = 0; @@ -142,7 +193,7 @@ bool QGLContext::chooseContext(const QGLContext* shareContext) QEglProperties configProps; qt_egl_add_platform_config(configProps, device()); qt_egl_set_format(configProps, devType, d->glFormat); - configProps.setRenderableType(QEglContext::OpenGL); + configProps.setRenderableType(QEgl::OpenGL); // Search for a matching configuration, reducing the complexity // each time until we get something that matches. @@ -168,8 +219,10 @@ bool QGLContext::chooseContext(const QGLContext* shareContext) eglSwapInterval(d->eglContext->display(), d->glFormat.swapInterval()); #endif - // Create the EGL surface to draw into. - if (!d->eglContext->createSurface(device())) { + // Create the EGL surface to draw into. We cannot use + // QEglContext::createSurface() because it does not have + // access to the QGLScreen. + if (!qt_egl_create_surface(d->eglContext, device())) { delete d->eglContext; d->eglContext = 0; return false; diff --git a/src/opengl/qgl_wince.cpp b/src/opengl/qgl_wince.cpp index 47dc2d4..afe26ab 100644 --- a/src/opengl/qgl_wince.cpp +++ b/src/opengl/qgl_wince.cpp @@ -140,7 +140,7 @@ bool QGLContext::chooseContext(const QGLContext* shareContext) // Get the display and initialize it. d->eglContext = new QEglContext(); - d->eglContext->setApi(QEglContext::OpenGL); + d->eglContext->setApi(QEgl::OpenGL); if (!d->eglContext->openDisplay(device())) { delete d->eglContext; d->eglContext = 0; @@ -151,7 +151,7 @@ bool QGLContext::chooseContext(const QGLContext* shareContext) QEglProperties configProps; qt_egl_add_platform_config(configProps, device()); qt_egl_set_format(configProps, devType, d->glFormat); - configProps.setRenderableType(QEglContext::OpenGL); + configProps.setRenderableType(QEgl::OpenGL); // Search for a matching configuration, reducing the complexity // each time until we get something that matches. diff --git a/src/opengl/qgl_x11egl.cpp b/src/opengl/qgl_x11egl.cpp index 7fdbfbd..9db3a30 100644 --- a/src/opengl/qgl_x11egl.cpp +++ b/src/opengl/qgl_x11egl.cpp @@ -77,7 +77,7 @@ bool QGLContext::chooseContext(const QGLContext* shareContext) // Get the display and initialize it. d->eglContext = new QEglContext(); - d->eglContext->setApi(QEglContext::OpenGL); + d->eglContext->setApi(QEgl::OpenGL); if (!d->eglContext->openDisplay(device())) { delete d->eglContext; d->eglContext = 0; @@ -88,11 +88,11 @@ bool QGLContext::chooseContext(const QGLContext* shareContext) QEglProperties configProps; qt_egl_set_format(configProps, devType, d->glFormat); qt_egl_add_platform_config(configProps, device()); - configProps.setRenderableType(QEglContext::OpenGL); + configProps.setRenderableType(QEgl::OpenGL); // Search for a matching configuration, reducing the complexity // each time until we get something that matches. - if (!d->eglContext->chooseConfig(configProps, QEglContext::BestPixelFormat)) { + if (!d->eglContext->chooseConfig(configProps, QEgl::BestPixelFormat)) { delete d->eglContext; d->eglContext = 0; return false; diff --git a/src/opengl/qglpixelbuffer_egl.cpp b/src/opengl/qglpixelbuffer_egl.cpp index fca1a31..38e4f74 100644 --- a/src/opengl/qglpixelbuffer_egl.cpp +++ b/src/opengl/qglpixelbuffer_egl.cpp @@ -63,7 +63,7 @@ bool QGLPixelBufferPrivate::init(const QSize &size, const QGLFormat &f, QGLWidge { // Create the EGL context. ctx = new QEglContext(); - ctx->setApi(QEglContext::OpenGL); + ctx->setApi(QEgl::OpenGL); // Open the EGL display. if (!ctx->openDisplay(0)) { @@ -82,13 +82,13 @@ bool QGLPixelBufferPrivate::init(const QSize &size, const QGLFormat &f, QGLWidge #if QGL_RENDER_TEXTURE textureFormat = EGL_TEXTURE_RGBA; configProps.setValue(EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE); - ok = ctx->chooseConfig(configProps, QEglContext::BestPixelFormat); + ok = ctx->chooseConfig(configProps, QEgl::BestPixelFormat); if (!ok) { // Try again with RGB texture rendering. textureFormat = EGL_TEXTURE_RGB; configProps.removeValue(EGL_BIND_TO_TEXTURE_RGBA); configProps.setValue(EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE); - ok = ctx->chooseConfig(configProps, QEglContext::BestPixelFormat); + ok = ctx->chooseConfig(configProps, QEgl::BestPixelFormat); if (!ok) { // One last try for a pbuffer with no texture rendering. configProps.removeValue(EGL_BIND_TO_TEXTURE_RGB); @@ -99,7 +99,7 @@ bool QGLPixelBufferPrivate::init(const QSize &size, const QGLFormat &f, QGLWidge textureFormat = EGL_NONE; #endif if (!ok) { - if (!ctx->chooseConfig(configProps, QEglContext::BestPixelFormat)) { + if (!ctx->chooseConfig(configProps, QEgl::BestPixelFormat)) { delete ctx; ctx = 0; return false; @@ -208,7 +208,7 @@ bool QGLPixelBuffer::hasOpenGLPbuffers() return false; QEglProperties configProps; qt_egl_set_format(configProps, QInternal::Pbuffer, QGLFormat::defaultFormat()); - configProps.setRenderableType(QEglContext::OpenGL); + configProps.setRenderableType(QEgl::OpenGL); return ctx.chooseConfig(configProps); } diff --git a/src/openvg/openvg.pro b/src/openvg/openvg.pro new file mode 100644 index 0000000..4d499ef --- /dev/null +++ b/src/openvg/openvg.pro @@ -0,0 +1,48 @@ +TARGET = QtOpenVG +QT += core \ + gui + +DEFINES+=QT_BUILD_OPENVG_LIB + +contains(QT_CONFIG, shivavg) { + DEFINES += QVG_NO_DRAW_GLYPHS + DEFINES += QVG_NO_RENDER_TO_MASK + DEFINES += QVG_SCISSOR_CLIP +} + +HEADERS += \ + qvg.h \ + qvg_p.h \ + qpaintengine_vg_p.h \ + qpixmapdata_vg_p.h \ + qpixmapfilter_vg_p.h \ + qvgcompositionhelper_p.h +SOURCES += \ + qpaintengine_vg.cpp \ + qpixmapdata_vg.cpp \ + qpixmapfilter_vg.cpp + +contains(QT_CONFIG, egl) { + HEADERS += \ + qwindowsurface_vgegl_p.h \ + qwindowsurface_vg_p.h + SOURCES += \ + qwindowsurface_vg.cpp \ + qwindowsurface_vgegl.cpp +} + +include(../qbase.pri) + +unix:QMAKE_PKGCONFIG_REQUIRES = QtCore QtGui + +!isEmpty(QMAKE_INCDIR_OPENVG): INCLUDEPATH += $$QMAKE_INCDIR_OPENVG +!isEmpty(QMAKE_LIBDIR_OPENVG): LIBS += -L$$QMAKE_LIBDIR_OPENVG +!isEmpty(QMAKE_LIBS_OPENVG): LIBS += $$QMAKE_LIBS_OPENVG + +contains(QT_CONFIG, egl) { + !isEmpty(QMAKE_INCDIR_EGL): INCLUDEPATH += $$QMAKE_INCDIR_EGL + !isEmpty(QMAKE_LIBDIR_EGL): LIBS += -L$$QMAKE_LIBDIR_EGL + !isEmpty(QMAKE_LIBS_EGL): LIBS += $$QMAKE_LIBS_EGL +} + +INCLUDEPATH += ../3rdparty/harfbuzz/src diff --git a/src/openvg/qpaintengine_vg.cpp b/src/openvg/qpaintengine_vg.cpp new file mode 100644 index 0000000..37945bf --- /dev/null +++ b/src/openvg/qpaintengine_vg.cpp @@ -0,0 +1,3231 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qpaintengine_vg_p.h" +#include "qpixmapdata_vg_p.h" +#include "qpixmapfilter_vg_p.h" +#include "qvgcompositionhelper_p.h" +#if !defined(QT_NO_EGL) +#include +#include "qwindowsurface_vgegl_p.h" +#endif +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +// vgDrawGlyphs() only exists in OpenVG 1.1 and higher. +#if !defined(OPENVG_VERSION_1_1) && !defined(QVG_NO_DRAW_GLYPHS) +#define QVG_NO_DRAW_GLYPHS 1 +#endif + +// vgRenderToMask() only exists in OpenVG 1.1 and higher. +// Also, disable masking completely if we are using the scissor to clip. +#if !defined(OPENVG_VERSION_1_1) && !defined(QVG_NO_RENDER_TO_MASK) +#define QVG_NO_RENDER_TO_MASK 1 +#endif +#if defined(QVG_SCISSOR_CLIP) && !defined(QVG_NO_RENDER_TO_MASK) +#define QVG_NO_RENDER_TO_MASK 1 +#endif + +#if !defined(QVG_NO_DRAW_GLYPHS) + +extern int qt_defaultDpiX(); +extern int qt_defaultDpiY(); + +class QVGPaintEnginePrivate; + +class QVGFontGlyphCache +{ +public: + QVGFontGlyphCache(); + ~QVGFontGlyphCache(); + + void cacheGlyphs(QVGPaintEnginePrivate *d, + const QTextItemInt &ti, + const QVarLengthArray &glyphs); + void setScaleFromText(const QTextItemInt &ti); + + VGFont font; + VGfloat scaleX; + VGfloat scaleY; + + uint cachedGlyphsMask[256 / 32]; + QSet cachedGlyphs; +}; + +typedef QHash QVGFontCache; + +#endif + +class QVGFontEngineCleaner : public QObject +{ + Q_OBJECT +public: + QVGFontEngineCleaner(QVGPaintEnginePrivate *d); + ~QVGFontEngineCleaner(); + +public slots: + void fontEngineDestroyed(); + +private: + QVGPaintEnginePrivate *d_ptr; +}; + +class QVGPaintEnginePrivate : public QPaintEngineExPrivate +{ +public: + QVGPaintEnginePrivate(); + ~QVGPaintEnginePrivate(); + + void init(); + void initObjects(); + void destroy(); + void setTransform(VGMatrixMode mode, const QTransform& transform); + void updateTransform(QPaintDevice *pdev); + void draw(VGPath path, const QPen& pen, const QBrush& brush, VGint rule = VG_EVEN_ODD); + void stroke(VGPath path, const QPen& pen); + void fill(VGPath path, const QBrush& brush, VGint rule = VG_EVEN_ODD); + VGPath vectorPathToVGPath(const QVectorPath& path); + VGPath painterPathToVGPath(const QPainterPath& path); + VGPaintType setBrush + (VGPaint paint, const QBrush& brush, VGMatrixMode mode, + VGPaintType prevPaintType); + void setPenParams(const QPen& pen); + void setBrushTransform(const QBrush& brush, VGMatrixMode mode); + void setupColorRamp(const QGradient *grad, VGPaint paint); + void setImageOptions(); +#if !defined(QVG_SCISSOR_CLIP) + void ensureMask(QVGPaintEngine *engine, int width, int height); + void modifyMask + (QVGPaintEngine *engine, VGMaskOperation op, const QRegion& region); +#endif + + VGint maxScissorRects; // Maximum scissor rectangles for clipping. + + VGPaint penPaint; // Paint for currently active pen. + VGPaint brushPaint; // Paint for currently active brush. + VGPaint opacityPaint; // Paint for drawing images with opacity. + VGPaint fillPaint; // Current fill paint that is active. + + QPen currentPen; // Current pen set in "penPaint". + QBrush currentBrush; // Current brush set in "brushPaint". + + bool forcePenChange; // Force a pen change, even if the same. + bool forceBrushChange; // Force a brush change, even if the same. + + VGPaintType penType; // Type of the last pen that was set. + VGPaintType brushType; // Type of the last brush that was set. + + QPointF brushOrigin; // Current brush origin. + + VGint fillRule; // Last fill rule that was set. + + qreal opacity; // Current drawing opacity. + qreal paintOpacity; // Opacity in opacityPaint. + +#if !defined(QVG_NO_MODIFY_PATH) + VGPath rectPath; // Cached path for quick drawing of rectangles. + VGPath linePath; // Cached path for quick drawing of lines. +#endif + + QTransform transform; // Currently active transform. + bool simpleTransform; // True if the transform is simple (non-projective). + qreal penScale; // Pen scaling factor from "transform". + + QTransform pathTransform; // Calculated VG path transformation. + QTransform imageTransform; // Calculated VG image transformation. + bool pathTransformSet; // True if path transform set in the VG context. + + bool maskValid; // True if vgMask() contains valid data. + bool maskIsSet; // True if mask would be fully set if it was valid. + bool rawVG; // True if processing a raw VG escape. + + QRect maskRect; // Rectangle version of mask if it is simple. + + QTransform penTransform; // Transform for the pen. + QTransform brushTransform; // Transform for the brush. + + VGMatrixMode matrixMode; // Last matrix mode that was set. + VGImageMode imageMode; // Last image mode that was set. + + QRegion scissorRegion; // Currently active scissor region. + bool scissorActive; // True if scissor region is active. + + QPaintEngine::DirtyFlags dirty; + + QColor clearColor; // Last clear color that was set. + VGfloat clearOpacity; // Opacity during the last clear. + + VGBlendMode blendMode; // Active blend mode. + VGRenderingQuality renderingQuality; // Active rendering quality. + VGImageQuality imageQuality; // Active image quality. + +#if !defined(QVG_NO_DRAW_GLYPHS) + QVGFontCache fontCache; + QVGFontEngineCleaner *fontEngineCleaner; +#endif + + // Ensure that the path transform is properly set in the VG context + // before we perform a vgDrawPath() operation. + inline void ensurePathTransform() + { + if (!pathTransformSet) { + setTransform(VG_MATRIX_PATH_USER_TO_SURFACE, pathTransform); + pathTransformSet = true; + } + } + + // Ensure that a specific pen has been set into penPaint. + inline void ensurePen(const QPen& pen) { + if (forcePenChange || pen != currentPen) { + currentPen = pen; + forcePenChange = false; + penType = setBrush + (penPaint, pen.brush(), + VG_MATRIX_STROKE_PAINT_TO_USER, penType); + setPenParams(pen); + } + } + + // Ensure that a specific brush has been set into brushPaint. + inline void ensureBrush(const QBrush& brush) { + if (forceBrushChange || brush != currentBrush) { + currentBrush = brush; + forceBrushChange = false; + brushType = setBrush + (brushPaint, brush, VG_MATRIX_FILL_PAINT_TO_USER, brushType); + } + if (fillPaint != brushPaint) { + vgSetPaint(brushPaint, VG_FILL_PATH); + fillPaint = brushPaint; + } + } + + // Set various modes, but only if different. + inline void setImageMode(VGImageMode mode); + inline void setRenderingQuality(VGRenderingQuality mode); + inline void setImageQuality(VGImageQuality mode); + inline void setBlendMode(VGBlendMode mode); + inline void setFillRule(VGint mode); + + // Clear all lazily-set modes. + void clearModes(); +}; + +inline void QVGPaintEnginePrivate::setImageMode(VGImageMode mode) +{ + if (imageMode != mode) { + imageMode = mode; + vgSeti(VG_IMAGE_MODE, mode); + } +} + +inline void QVGPaintEnginePrivate::setRenderingQuality(VGRenderingQuality mode) +{ + if (renderingQuality != mode) { + vgSeti(VG_RENDERING_QUALITY, mode); + renderingQuality = mode; + } +} + +inline void QVGPaintEnginePrivate::setImageQuality(VGImageQuality mode) +{ + if (imageQuality != mode) { + vgSeti(VG_IMAGE_QUALITY, mode); + imageQuality = mode; + } +} + +inline void QVGPaintEnginePrivate::setBlendMode(VGBlendMode mode) +{ + if (blendMode != mode) { + vgSeti(VG_BLEND_MODE, mode); + blendMode = mode; + } +} + +inline void QVGPaintEnginePrivate::setFillRule(VGint mode) +{ + if (fillRule != mode) { + fillRule = mode; + vgSeti(VG_FILL_RULE, mode); + } +} + +void QVGPaintEnginePrivate::clearModes() +{ + matrixMode = (VGMatrixMode)0; + imageMode = (VGImageMode)0; + blendMode = (VGBlendMode)0; + renderingQuality = (VGRenderingQuality)0; + imageQuality = (VGImageQuality)0; +} + +QVGPaintEnginePrivate::QVGPaintEnginePrivate() +{ + init(); +} + +void QVGPaintEnginePrivate::init() +{ + maxScissorRects = 0; + + penPaint = 0; + brushPaint = 0; + opacityPaint = 0; + fillPaint = 0; + + forcePenChange = true; + forceBrushChange = true; + penType = (VGPaintType)0; + brushType = (VGPaintType)0; + + brushOrigin = QPointF(0.0f, 0.0f); + + fillRule = 0; + + opacity = 1.0; + paintOpacity = 1.0f; + +#if !defined(QVG_NO_MODIFY_PATH) + rectPath = 0; + linePath = 0; +#endif + + simpleTransform = true; + pathTransformSet = false; + penScale = 1.0; + + maskValid = false; + maskIsSet = false; + rawVG = false; + + scissorActive = false; + + dirty = 0; + + clearOpacity = 1.0f; + +#if !defined(QVG_NO_DRAW_GLYPHS) + fontEngineCleaner = 0; +#endif + + clearModes(); +} + +QVGPaintEnginePrivate::~QVGPaintEnginePrivate() +{ + destroy(); +} + +void QVGPaintEnginePrivate::initObjects() +{ + maxScissorRects = vgGeti(VG_MAX_SCISSOR_RECTS); + + penPaint = vgCreatePaint(); + vgSetParameteri(penPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); + vgSetPaint(penPaint, VG_STROKE_PATH); + + vgSeti(VG_MATRIX_MODE, VG_MATRIX_STROKE_PAINT_TO_USER); + vgLoadIdentity(); + + brushPaint = vgCreatePaint(); + vgSetParameteri(brushPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); + vgSetPaint(brushPaint, VG_FILL_PATH); + fillPaint = brushPaint; + + vgSeti(VG_MATRIX_MODE, VG_MATRIX_FILL_PAINT_TO_USER); + vgLoadIdentity(); + matrixMode = VG_MATRIX_FILL_PAINT_TO_USER; + + opacityPaint = vgCreatePaint(); + vgSetParameteri(opacityPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); + VGfloat values[4]; + values[0] = 1.0f; + values[1] = 1.0f; + values[2] = 1.0f; + values[3] = paintOpacity; + vgSetParameterfv(opacityPaint, VG_PAINT_COLOR, 4, values); + +#if !defined(QVG_NO_MODIFY_PATH) + // Create a dummy path for rectangle drawing, which we can + // modify later with vgModifyPathCoords(). This should be + // faster than constantly creating and destroying paths. + rectPath = vgCreatePath(VG_PATH_FORMAT_STANDARD, + VG_PATH_DATATYPE_F, + 1.0f, // scale + 0.0f, // bias + 5, // segmentCapacityHint + 8, // coordCapacityHint + VG_PATH_CAPABILITY_ALL); + static VGubyte const segments[5] = { + VG_MOVE_TO_ABS, + VG_LINE_TO_ABS, + VG_LINE_TO_ABS, + VG_LINE_TO_ABS, + VG_CLOSE_PATH + }; + VGfloat coords[8]; + coords[0] = 0.0f; + coords[1] = 0.0f; + coords[2] = 100.0f; + coords[3] = coords[1]; + coords[4] = coords[2]; + coords[5] = 100.0f; + coords[6] = coords[0]; + coords[7] = coords[5]; + vgAppendPathData(rectPath, 5, segments, coords); + + // Create a dummy line drawing path as well. + linePath = vgCreatePath(VG_PATH_FORMAT_STANDARD, + VG_PATH_DATATYPE_F, + 1.0f, // scale + 0.0f, // bias + 2, // segmentCapacityHint + 4, // coordCapacityHint + VG_PATH_CAPABILITY_ALL); + vgAppendPathData(linePath, 2, segments, coords); +#endif +} + +void QVGPaintEnginePrivate::destroy() +{ + if (penPaint) + vgDestroyPaint(penPaint); + if (brushPaint) + vgDestroyPaint(brushPaint); + if (opacityPaint) + vgDestroyPaint(opacityPaint); + +#if !defined(QVG_NO_MODIFY_PATH) + if (rectPath) + vgDestroyPath(rectPath); + if (linePath) + vgDestroyPath(linePath); +#endif + +#if !defined(QVG_NO_DRAW_GLYPHS) + QVGFontCache::Iterator it; + for (it = fontCache.begin(); it != fontCache.end(); ++it) + delete it.value(); + fontCache.clear(); + delete fontEngineCleaner; +#endif +} + +// Set a specific VG transformation matrix in the current VG context. +void QVGPaintEnginePrivate::setTransform + (VGMatrixMode mode, const QTransform& transform) +{ + VGfloat mat[9]; + if (mode != matrixMode) { + vgSeti(VG_MATRIX_MODE, mode); + matrixMode = mode; + } + mat[0] = transform.m11(); + mat[1] = transform.m12(); + mat[2] = transform.m13(); + mat[3] = transform.m21(); + mat[4] = transform.m22(); + mat[5] = transform.m23(); + mat[6] = transform.m31(); + mat[7] = transform.m32(); + mat[8] = transform.m33(); + vgLoadMatrix(mat); +} + +extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); + +void QVGPaintEnginePrivate::updateTransform(QPaintDevice *pdev) +{ + VGfloat devh = pdev->height() - 1; + + // Construct the VG transform by combining the Qt transform with + // the following viewport transformation: + // | 1 0 0 | | 1 0 0.5 | | 1 0 0.5 | + // | 0 -1 devh | * | 0 1 -0.5 | = | 0 -1 (0.5 + devh) | + // | 0 0 1 | | 0 0 1 | | 0 0 1 | + // The full VG transform is effectively: + // 1. Apply the user's transformation matrix. + // 2. Translate by (0.5, -0.5) to correct for Qt and VG putting + // the centre of the pixel at different positions. + // 3. Flip the co-ordinate system upside down. + QTransform viewport(1.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, + 0.5f, devh + 0.5f, 1.0f); + + // The image transform is always the full transformation, + // because it can be projective. + imageTransform = transform * viewport; + + // Determine if the transformation is projective. + bool projective = (imageTransform.m13() != 0.0f || + imageTransform.m23() != 0.0f || + imageTransform.m33() != 1.0f); + if (projective) { + // The engine cannot do projective path transforms for us, + // so we will have to convert the co-ordinates ourselves. + // Change the matrix to just the viewport transformation. + pathTransform = viewport; + simpleTransform = false; + } else { + pathTransform = imageTransform; + simpleTransform = true; + } + pathTransformSet = false; + + // Calculate the scaling factor to use for turning cosmetic pens + // into ordinary non-cosmetic pens. + qt_scaleForTransform(transform, &penScale); +} + +VGPath QVGPaintEnginePrivate::vectorPathToVGPath(const QVectorPath& path) +{ + int count = path.elementCount(); + const qreal *points = path.points(); + const QPainterPath::ElementType *elements = path.elements(); + + 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); + + // Size is sufficient segments for drawRoundedRect() paths. + QVarLengthArray segments; + + if (sizeof(qreal) == sizeof(VGfloat) && elements && simpleTransform) { + // If Qt was compiled with qreal the same size as VGfloat, + // then convert the segment types and use the incoming + // points array directly. + for (int i = 0; i < count; ++i) { + switch (elements[i]) { + + case QPainterPath::MoveToElement: + segments.append(VG_MOVE_TO_ABS); break; + + case QPainterPath::LineToElement: + segments.append(VG_LINE_TO_ABS); break; + + case QPainterPath::CurveToElement: break; + + case QPainterPath::CurveToDataElement: + segments.append(VG_CUBIC_TO_ABS); break; + + } + } + if (path.hasImplicitClose()) + segments.append(VG_CLOSE_PATH); + + vgAppendPathData(vgpath, segments.count(), segments.constData(), + reinterpret_cast(points)); + + return vgpath; + } + + // Sizes chosen so that drawRoundedRect() paths fit in these arrays. + QVarLengthArray coords; + + int curvePos = 0; + QPointF temp; + + if (elements && simpleTransform) { + // Convert the members of the element array. + for (int i = 0; i < count; ++i) { + switch (elements[i]) { + + case QPainterPath::MoveToElement: + { + coords.append(points[0]); + coords.append(points[1]); + segments.append(VG_MOVE_TO_ABS); + } + break; + + case QPainterPath::LineToElement: + { + coords.append(points[0]); + coords.append(points[1]); + segments.append(VG_LINE_TO_ABS); + } + break; + + case QPainterPath::CurveToElement: + { + coords.append(points[0]); + coords.append(points[1]); + curvePos = 2; + } + break; + + case QPainterPath::CurveToDataElement: + { + coords.append(points[0]); + coords.append(points[1]); + curvePos += 2; + if (curvePos == 6) { + curvePos = 0; + segments.append(VG_CUBIC_TO_ABS); + } + } + break; + + } + points += 2; + } + } else if (elements && !simpleTransform) { + // Convert the members of the element array after applying the + // current transform to the path locally. + for (int i = 0; i < count; ++i) { + switch (elements[i]) { + + case QPainterPath::MoveToElement: + { + temp = transform.map(QPointF(points[0], points[1])); + coords.append(temp.x()); + coords.append(temp.y()); + segments.append(VG_MOVE_TO_ABS); + } + break; + + case QPainterPath::LineToElement: + { + temp = transform.map(QPointF(points[0], points[1])); + coords.append(temp.x()); + coords.append(temp.y()); + segments.append(VG_LINE_TO_ABS); + } + break; + + case QPainterPath::CurveToElement: + { + temp = transform.map(QPointF(points[0], points[1])); + coords.append(temp.x()); + coords.append(temp.y()); + curvePos = 2; + } + break; + + case QPainterPath::CurveToDataElement: + { + temp = transform.map(QPointF(points[0], points[1])); + coords.append(temp.x()); + coords.append(temp.y()); + curvePos += 2; + if (curvePos == 6) { + curvePos = 0; + segments.append(VG_CUBIC_TO_ABS); + } + } + break; + + } + points += 2; + } + } else if (count > 0 && simpleTransform) { + // If there is no element array, then the path is assumed + // to be a MoveTo followed by several LineTo's. + coords.append(points[0]); + coords.append(points[1]); + segments.append(VG_MOVE_TO_ABS); + while (count > 1) { + points += 2; + coords.append(points[0]); + coords.append(points[1]); + segments.append(VG_LINE_TO_ABS); + --count; + } + } else if (count > 0 && !simpleTransform) { + // Convert a simple path, and apply the transform locally. + temp = transform.map(QPointF(points[0], points[1])); + coords.append(temp.x()); + coords.append(temp.y()); + segments.append(VG_MOVE_TO_ABS); + while (count > 1) { + points += 2; + temp = transform.map(QPointF(points[0], points[1])); + coords.append(temp.x()); + coords.append(temp.y()); + segments.append(VG_LINE_TO_ABS); + --count; + } + } + + // Close the path if specified. + if (path.hasImplicitClose()) + segments.append(VG_CLOSE_PATH); + + vgAppendPathData(vgpath, segments.count(), + segments.constData(), coords.constData()); + + return vgpath; +} + +VGPath QVGPaintEnginePrivate::painterPathToVGPath(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; + + const QPainterPath::Element *elements = &(path.elementAt(0)); + + // Sizes chosen so that drawRoundedRect() paths fit in these arrays. + QVarLengthArray coords; + QVarLengthArray 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; + + if (simpleTransform) { + // Convert the members of the element array. + for (int i = 0; i < count; ++i) { + switch (elements[i].type) { + + case QPainterPath::MoveToElement: + { + if (haveStart && haveEnd && startx == endx && starty == endy) { + // Implicitly close the previous sub-path. + segments.append(VG_CLOSE_PATH); + } + startx = elements[i].x; + starty = elements[i].y; + coords.append(startx); + coords.append(starty); + haveStart = true; + haveEnd = false; + segments.append(VG_MOVE_TO_ABS); + } + break; + + case QPainterPath::LineToElement: + { + endx = elements[i].x; + endy = elements[i].y; + coords.append(endx); + coords.append(endy); + haveEnd = true; + segments.append(VG_LINE_TO_ABS); + } + break; + + case QPainterPath::CurveToElement: + { + coords.append(elements[i].x); + coords.append(elements[i].y); + haveEnd = false; + curvePos = 2; + } + break; + + case QPainterPath::CurveToDataElement: + { + coords.append(elements[i].x); + coords.append(elements[i].y); + haveEnd = false; + curvePos += 2; + if (curvePos == 6) { + curvePos = 0; + segments.append(VG_CUBIC_TO_ABS); + } + } + break; + + } + } + } else { + // Convert the members of the element array after applying the + // current transform to the path locally. + for (int i = 0; i < count; ++i) { + switch (elements[i].type) { + + case QPainterPath::MoveToElement: + { + if (haveStart && haveEnd && startx == endx && starty == endy) { + // Implicitly close the previous sub-path. + segments.append(VG_CLOSE_PATH); + } + temp = transform.map(QPointF(elements[i].x, elements[i].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 = transform.map(QPointF(elements[i].x, elements[i].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 = transform.map(QPointF(elements[i].x, elements[i].y)); + coords.append(temp.x()); + coords.append(temp.y()); + haveEnd = false; + curvePos = 2; + } + break; + + case QPainterPath::CurveToDataElement: + { + temp = transform.map(QPointF(elements[i].x, elements[i].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; +} + +extern QImage qt_imageForBrush(int style, bool invert); + +static QImage colorizeBitmap(const QImage &image, const QColor &color) +{ + QImage sourceImage = image.convertToFormat(QImage::Format_MonoLSB); + QImage dest = QImage(sourceImage.size(), QImage::Format_ARGB32_Premultiplied); + + QRgb fg = PREMUL(color.rgba()); + QRgb bg = 0; + + int height = sourceImage.height(); + int width = sourceImage.width(); + for (int y=0; y(dest.scanLine(y)); + for (int x=0; x < width; ++x) + target[x] = (source[x>>3] >> (x&7)) & 1 ? fg : bg; + } + return dest; +} + +static VGImage toVGImage + (const QImage & image, Qt::ImageConversionFlags flags = Qt::AutoColor) +{ + QImage img(image); + + VGImageFormat format; + switch (img.format()) { + case QImage::Format_Mono: + img = image.convertToFormat(QImage::Format_MonoLSB, flags); + format = VG_BW_1; + break; + case QImage::Format_MonoLSB: + format = VG_BW_1; + break; + case QImage::Format_RGB32: + format = VG_sXRGB_8888; + break; + case QImage::Format_ARGB32: + format = VG_sARGB_8888; + break; + case QImage::Format_ARGB32_Premultiplied: + format = VG_sARGB_8888_PRE; + break; + case QImage::Format_RGB16: + format = VG_sRGB_565; + break; + default: + // Convert everything else into ARGB32_Premultiplied. + img = image.convertToFormat(QImage::Format_ARGB32_Premultiplied, flags); + format = VG_sARGB_8888_PRE; + break; + } + + const uchar *pixels = img.bits(); + + VGImage vgImg = vgCreateImage + (format, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER); + vgImageSubData + (vgImg, pixels, img.bytesPerLine(), format, 0, 0, + img.width(), img.height()); + + return vgImg; +} + +static VGImage toVGImageSubRect + (const QImage & image, const QRect& sr, + Qt::ImageConversionFlags flags = Qt::AutoColor) +{ + QImage img(image); + + VGImageFormat format; + int bpp = 4; + + switch (img.format()) { + case QImage::Format_Mono: + case QImage::Format_MonoLSB: + return VG_INVALID_HANDLE; + case QImage::Format_RGB32: + format = VG_sXRGB_8888; + break; + case QImage::Format_ARGB32: + format = VG_sARGB_8888; + break; + case QImage::Format_ARGB32_Premultiplied: + format = VG_sARGB_8888_PRE; + break; + case QImage::Format_RGB16: + format = VG_sRGB_565; + bpp = 2; + break; + default: + // Convert everything else into ARGB32_Premultiplied. + img = image.convertToFormat(QImage::Format_ARGB32_Premultiplied, flags); + format = VG_sARGB_8888_PRE; + break; + } + + const uchar *pixels = img.bits() + bpp * sr.x() + + img.bytesPerLine() * sr.y(); + + VGImage vgImg = vgCreateImage + (format, sr.width(), sr.height(), VG_IMAGE_QUALITY_FASTER); + vgImageSubData + (vgImg, pixels, img.bytesPerLine(), format, 0, 0, + sr.width(), sr.height()); + + return vgImg; +} + +static VGImage toVGImageWithOpacity(const QImage & image, qreal opacity) +{ + QImage img(image.size(), QImage::Format_ARGB32_Premultiplied); + img.fill(0); + QPainter painter; + painter.begin(&img); + painter.setOpacity(opacity); + painter.drawImage(0, 0, image); + painter.end(); + + const uchar *pixels = img.bits(); + + VGImage vgImg = vgCreateImage + (VG_sARGB_8888_PRE, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER); + vgImageSubData + (vgImg, pixels, img.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0, + img.width(), img.height()); + + return vgImg; +} + +static VGImage toVGImageWithOpacitySubRect + (const QImage & image, qreal opacity, const QRect& sr) +{ + QImage img(sr.size(), QImage::Format_ARGB32_Premultiplied); + img.fill(0); + QPainter painter; + painter.begin(&img); + painter.setOpacity(opacity); + painter.drawImage(QPoint(0, 0), image, sr); + painter.end(); + + const uchar *pixels = img.bits(); + + VGImage vgImg = vgCreateImage + (VG_sARGB_8888_PRE, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER); + vgImageSubData + (vgImg, pixels, img.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0, + img.width(), img.height()); + + return vgImg; +} + +VGPaintType QVGPaintEnginePrivate::setBrush + (VGPaint paint, const QBrush& brush, VGMatrixMode mode, + VGPaintType prevType) +{ + VGfloat values[5]; + setBrushTransform(brush, mode); + + // Reset the paint pattern on the brush, which will discard + // the previous VGImage if one was set. + if (prevType == VG_PAINT_TYPE_PATTERN || prevType == (VGPaintType)0) + vgPaintPattern(paint, VG_INVALID_HANDLE); + + switch (brush.style()) { + + case Qt::SolidPattern: { + // The brush is a solid color. + QColor color(brush.color()); + values[0] = color.redF(); + values[1] = color.greenF(); + values[2] = color.blueF(); + values[3] = color.alphaF() * opacity; + if (prevType != VG_PAINT_TYPE_COLOR) + vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); + vgSetParameterfv(paint, VG_PAINT_COLOR, 4, values); + return VG_PAINT_TYPE_COLOR; + } + + case Qt::LinearGradientPattern: { + // The brush is a linear gradient. + Q_ASSERT(brush.gradient()->type() == QGradient::LinearGradient); + const QLinearGradient *grad = + static_cast(brush.gradient()); + values[0] = grad->start().x(); + values[1] = grad->start().y(); + values[2] = grad->finalStop().x(); + values[3] = grad->finalStop().y(); + if (prevType != VG_PAINT_TYPE_LINEAR_GRADIENT) + vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_LINEAR_GRADIENT); + vgSetParameterfv(paint, VG_PAINT_LINEAR_GRADIENT, 4, values); + setupColorRamp(grad, paint); + return VG_PAINT_TYPE_LINEAR_GRADIENT; + } + + case Qt::RadialGradientPattern: { + // The brush is a radial gradient. + Q_ASSERT(brush.gradient()->type() == QGradient::RadialGradient); + const QRadialGradient *grad = + static_cast(brush.gradient()); + values[0] = grad->center().x(); + values[1] = grad->center().y(); + values[2] = grad->focalPoint().x(); + values[3] = grad->focalPoint().y(); + values[4] = grad->radius(); + if (prevType != VG_PAINT_TYPE_RADIAL_GRADIENT) + vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_RADIAL_GRADIENT); + vgSetParameterfv(paint, VG_PAINT_RADIAL_GRADIENT, 5, values); + setupColorRamp(grad, paint); + return VG_PAINT_TYPE_RADIAL_GRADIENT; + } + + case Qt::TexturePattern: { + // The brush is a texture specified by a QPixmap/QImage. + QPixmapData *pd = brush.texture().pixmapData(); + VGImage vgImg; + if (pd->pixelType() == QPixmapData::BitmapType) { + // Colorize bitmaps using the brush color and opacity. + QColor color = brush.color(); + if (opacity != 1.0) + color.setAlphaF(color.alphaF() * opacity); + QImage image = colorizeBitmap(*(pd->buffer()), color); + vgImg = toVGImage(image); + } else if (opacity == 1.0) { + if (pd->classId() == QPixmapData::OpenVGClass) { + QVGPixmapData *vgpd = static_cast(pd); + vgImg = vgpd->toVGImage(); + } else { + vgImg = toVGImage(*(pd->buffer())); + } + } else { + vgImg = toVGImageWithOpacity(*(pd->buffer()), opacity); + } + if (vgImg == VG_INVALID_HANDLE) + break; + if (prevType != VG_PAINT_TYPE_PATTERN) + vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_PATTERN); + vgSetParameteri(paint, VG_PAINT_PATTERN_TILING_MODE, VG_TILE_REPEAT); + vgPaintPattern(paint, vgImg); + vgDestroyImage(vgImg); // Will stay valid until pattern is destroyed. + return VG_PAINT_TYPE_PATTERN; + } + + case Qt::ConicalGradientPattern: { + // Convert conical gradients into the first stop color. + qWarning() << "QVGPaintEnginePrivate::setBrush: conical gradients are not supported by OpenVG"; + Q_ASSERT(brush.gradient()->type() == QGradient::ConicalGradient); + const QConicalGradient *grad = + static_cast(brush.gradient()); + const QGradientStops stops = grad->stops(); + QColor color; + if (stops.size() > 0) + color = stops[0].second; + values[0] = color.redF(); + values[1] = color.greenF(); + values[2] = color.blueF(); + values[3] = color.alphaF() * opacity; + if (prevType != VG_PAINT_TYPE_COLOR) + vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); + vgSetParameterfv(paint, VG_PAINT_COLOR, 4, values); + return VG_PAINT_TYPE_COLOR; + } + + case Qt::Dense1Pattern: + case Qt::Dense2Pattern: + case Qt::Dense3Pattern: + case Qt::Dense4Pattern: + case Qt::Dense5Pattern: + case Qt::Dense6Pattern: + case Qt::Dense7Pattern: + case Qt::HorPattern: + case Qt::VerPattern: + case Qt::CrossPattern: + case Qt::BDiagPattern: + case Qt::FDiagPattern: + case Qt::DiagCrossPattern: { + // The brush is a traditional dotted or cross-hatched pattern brush. + QColor color = brush.color(); + if (opacity != 1.0) + color.setAlphaF(color.alphaF() * opacity); + QImage image = colorizeBitmap + (qt_imageForBrush(brush.style(), true), color); + VGImage vgImg = toVGImage(image); + if (prevType != VG_PAINT_TYPE_PATTERN) + vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_PATTERN); + vgSetParameteri(paint, VG_PAINT_PATTERN_TILING_MODE, VG_TILE_REPEAT); + vgPaintPattern(paint, vgImg); + vgDestroyImage(vgImg); // Will stay valid until pattern is destroyed. + return VG_PAINT_TYPE_PATTERN; + } + + default: break; + } + return (VGPaintType)0; +} + +void QVGPaintEnginePrivate::setPenParams(const QPen& pen) +{ + // Note: OpenVG does not support zero-width or cosmetic pens, + // so we have to simulate cosmetic pens by reversing the scale. + VGfloat width = pen.widthF(); + if (width <= 0.0f) + width = 1.0f; + if (pen.isCosmetic()) { + if (penScale != 1.0 && penScale != 0.0) + width /= penScale; + } + vgSetf(VG_STROKE_LINE_WIDTH, width); + + if (pen.capStyle() == Qt::FlatCap) + vgSetf(VG_STROKE_CAP_STYLE, VG_CAP_BUTT); + else if (pen.capStyle() == Qt::SquareCap) + vgSetf(VG_STROKE_CAP_STYLE, VG_CAP_SQUARE); + else + vgSetf(VG_STROKE_CAP_STYLE, VG_CAP_ROUND); + + if (pen.joinStyle() == Qt::MiterJoin) { + vgSetf(VG_STROKE_JOIN_STYLE, VG_JOIN_MITER); + vgSetf(VG_STROKE_MITER_LIMIT, pen.miterLimit()); + } else if (pen.joinStyle() == Qt::BevelJoin) { + vgSetf(VG_STROKE_JOIN_STYLE, VG_JOIN_BEVEL); + } else { + vgSetf(VG_STROKE_JOIN_STYLE, VG_JOIN_ROUND); + } + + if (pen.style() == Qt::SolidLine) { + vgSetfv(VG_STROKE_DASH_PATTERN, 0, NULL); + } else { + const QVector dashPattern = pen.dashPattern(); + QVector currentDashPattern(dashPattern.count()); + for (int i = 0; i < dashPattern.count(); ++i) + currentDashPattern[i] = dashPattern[i] * width; + vgSetfv(VG_STROKE_DASH_PATTERN, currentDashPattern.count(), currentDashPattern.data()); + vgSetf(VG_STROKE_DASH_PHASE, pen.dashOffset()); + vgSetf(VG_STROKE_DASH_PHASE_RESET, VG_FALSE); + } +} + +void QVGPaintEnginePrivate::setBrushTransform + (const QBrush& brush, VGMatrixMode mode) +{ + // Compute the new brush transformation matrix. + QTransform transform(brush.transform()); + if (brushOrigin.x() != 0.0f || brushOrigin.y() != 0.0f) + transform.translate(brushOrigin.x(), brushOrigin.y()); + + // Bail out if the matrix is the same as last time, to avoid + // updating the VG context state unless absolutely necessary. + // Most applications won't have a brush transformation set, + // which will leave the VG setting at its default of identity. + // Always change the transform if coming out of raw VG mode. + if (mode == VG_MATRIX_FILL_PAINT_TO_USER) { + if (!rawVG && transform == brushTransform) + return; + brushTransform = transform; + } else { + if (!rawVG && transform == penTransform) + return; + penTransform = transform; + } + + // Set the brush transformation matrix. + if (mode != matrixMode) { + vgSeti(VG_MATRIX_MODE, mode); + matrixMode = mode; + } + if (transform.isIdentity()) { + vgLoadIdentity(); + } else { + VGfloat mat[9]; + mat[0] = transform.m11(); + mat[1] = transform.m12(); + mat[2] = transform.m13(); + mat[3] = transform.m21(); + mat[4] = transform.m22(); + mat[5] = transform.m23(); + mat[6] = transform.m31(); + mat[7] = transform.m32(); + mat[8] = transform.m33(); + vgLoadMatrix(mat); + } +} + +void QVGPaintEnginePrivate::setupColorRamp(const QGradient *grad, VGPaint paint) +{ + QGradient::Spread spread = grad->spread(); + VGColorRampSpreadMode spreadMode; + if (spread == QGradient::ReflectSpread) + spreadMode = VG_COLOR_RAMP_SPREAD_REFLECT; + else if (spread == QGradient::RepeatSpread) + spreadMode = VG_COLOR_RAMP_SPREAD_REPEAT; + else + spreadMode = VG_COLOR_RAMP_SPREAD_PAD; + + const QGradientStops stops = grad->stops(); + int n = 5*stops.size(); + QVector fill_stops(n); + + for (int i = 0; i < stops.size(); ++i ) { + QColor col = stops[i].second; + fill_stops[i*5] = stops[i].first; + fill_stops[i*5 + 1] = col.redF(); + fill_stops[i*5 + 2] = col.greenF(); + fill_stops[i*5 + 3] = col.blueF(); + fill_stops[i*5 + 4] = col.alphaF() * opacity; + } + + vgSetParameteri(paint, VG_PAINT_COLOR_RAMP_SPREAD_MODE, spreadMode); + vgSetParameteri(paint, VG_PAINT_COLOR_RAMP_PREMULTIPLIED, VG_FALSE); + vgSetParameterfv(paint, VG_PAINT_COLOR_RAMP_STOPS, n, fill_stops.data()); +} + +QVGPainterState::QVGPainterState(QVGPainterState& other) + : QPainterState(other), + isNew(true), clipRegion(other.clipRegion), + savedDirty(0) +{ +} + +QVGPainterState::QVGPainterState() + : isNew(true), savedDirty(0) +{ +} + +QVGPainterState::~QVGPainterState() +{ +} + +QVGPaintEngine::QVGPaintEngine() + : QPaintEngineEx(*new QVGPaintEnginePrivate) +{ +} + +QVGPaintEngine::QVGPaintEngine(QVGPaintEnginePrivate &data) + : QPaintEngineEx(data) +{ +} + +QVGPaintEngine::~QVGPaintEngine() +{ +} + +QPainterState *QVGPaintEngine::createState(QPainterState *orig) const +{ + if (!orig) { + return new QVGPainterState(); + } else { + QVGPaintEnginePrivate *d = + static_cast(d_ptr); + QVGPainterState *origState = static_cast(orig); + origState->savedDirty = d->dirty; + d->dirty = 0; + return new QVGPainterState(*origState); + } +} + +void QVGPaintEnginePrivate::draw + (VGPath path, const QPen& pen, const QBrush& brush, VGint rule) +{ + VGbitfield mode = 0; + if (pen.style() != Qt::NoPen) { + ensurePen(pen); + mode |= VG_STROKE_PATH; + } + if (brush.style() != Qt::NoBrush) { + ensureBrush(brush); + setFillRule(rule); + mode |= VG_FILL_PATH; + } + if (mode != 0) { + ensurePathTransform(); + vgDrawPath(path, mode); + } +} + +void QVGPaintEnginePrivate::stroke(VGPath path, const QPen& pen) +{ + if (pen.style() == Qt::NoPen) + return; + ensurePen(pen); + ensurePathTransform(); + vgDrawPath(path, VG_STROKE_PATH); +} + +void QVGPaintEnginePrivate::fill(VGPath path, const QBrush& brush, VGint rule) +{ + if (brush.style() == Qt::NoBrush) + return; + ensureBrush(brush); + setFillRule(rule); + ensurePathTransform(); + vgDrawPath(path, VG_FILL_PATH); +} + +bool QVGPaintEngine::begin(QPaintDevice *pdev) +{ + Q_UNUSED(pdev); + Q_D(QVGPaintEngine); + + // Initialize the VG painting objects if we haven't done it yet. + if (!d->penPaint) + d->initObjects(); + + // The initial clip region is the entire device area. + QVGPainterState *s = state(); + s->clipRegion = defaultClipRegion(); + + // Initialize the VG state for this paint operation. + restoreState(QPaintEngine::AllDirty); + d->dirty = 0; + d->rawVG = false; + return true; +} + +bool QVGPaintEngine::end() +{ + return true; +} + +void QVGPaintEngine::draw(const QVectorPath &path) +{ + Q_D(QVGPaintEngine); + QVGPainterState *s = state(); + VGPath vgpath = d->vectorPathToVGPath(path); + if (!path.hasWindingFill()) + d->draw(vgpath, s->pen, s->brush, VG_EVEN_ODD); + else + d->draw(vgpath, s->pen, s->brush, VG_NON_ZERO); + vgDestroyPath(vgpath); +} + +void QVGPaintEngine::fill(const QVectorPath &path, const QBrush &brush) +{ + Q_D(QVGPaintEngine); + VGPath vgpath = d->vectorPathToVGPath(path); + if (!path.hasWindingFill()) + d->fill(vgpath, brush, VG_EVEN_ODD); + else + d->fill(vgpath, brush, VG_NON_ZERO); + vgDestroyPath(vgpath); +} + +void QVGPaintEngine::stroke(const QVectorPath &path, const QPen &pen) +{ + Q_D(QVGPaintEngine); + VGPath vgpath = d->vectorPathToVGPath(path); + d->stroke(vgpath, pen); + vgDestroyPath(vgpath); +} + +// Determine if a co-ordinate transform is simple enough to allow +// rectangle-based clipping with vgMask(). Simple transforms most +// often result from origin translations. +static inline bool clipTransformIsSimple(const QTransform& transform) +{ + QTransform::TransformationType type = transform.type(); + return (type == QTransform::TxNone || type == QTransform::TxTranslate); +} + +#if defined(QVG_SCISSOR_CLIP) + +void QVGPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op) +{ + Q_D(QVGPaintEngine); + QVGPainterState *s = state(); + + d->dirty |= QPaintEngine::DirtyClipRegion; + + if (op == Qt::NoClip) { + s->clipRegion = defaultClipRegion(); + updateScissor(); + return; + } + + // We aren't using masking, so handle simple QRectF's only. + if (path.shape() == QVectorPath::RectangleHint && + path.elementCount() == 4 && clipTransformIsSimple(d->transform)) { + // Clipping region that resulted from QPainter::setClipRect(QRectF). + // Convert it into a QRect and apply. + const qreal *points = path.points(); + QRectF rect(points[0], points[1], points[2] - points[0], + points[5] - points[1]); + clip(rect.toRect(), op); + } +} + +void QVGPaintEngine::clip(const QRect &rect, Qt::ClipOperation op) +{ + Q_D(QVGPaintEngine); + QVGPainterState *s = state(); + + d->dirty |= QPaintEngine::DirtyClipRegion; + + // If we have a non-simple transform, then use path-based clipping. + if (op != Qt::NoClip && !clipTransformIsSimple(d->transform)) { + QPaintEngineEx::clip(rect, op); + return; + } + + switch (op) { + case Qt::NoClip: + { + s->clipRegion = defaultClipRegion(); + } + break; + + case Qt::ReplaceClip: + { + s->clipRegion = d->transform.map(QRegion(rect)); + } + break; + + case Qt::IntersectClip: + { + s->clipRegion = s->clipRegion.intersect(d->transform.map(QRegion(rect))); + } + break; + + case Qt::UniteClip: + { + s->clipRegion = s->clipRegion.unite(d->transform.map(QRegion(rect))); + } + break; + } + + updateScissor(); +} + +void QVGPaintEngine::clip(const QRegion ®ion, Qt::ClipOperation op) +{ + Q_D(QVGPaintEngine); + QVGPainterState *s = state(); + + d->dirty |= QPaintEngine::DirtyClipRegion; + + // If we have a non-simple transform, then use path-based clipping. + if (op != Qt::NoClip && !clipTransformIsSimple(d->transform)) { + QPaintEngineEx::clip(region, op); + return; + } + + switch (op) { + case Qt::NoClip: + { + s->clipRegion = defaultClipRegion(); + } + break; + + case Qt::ReplaceClip: + { + s->clipRegion = d->transform.map(region); + } + break; + + case Qt::IntersectClip: + { + s->clipRegion = s->clipRegion.intersect(d->transform.map(region)); + } + break; + + case Qt::UniteClip: + { + s->clipRegion = s->clipRegion.unite(d->transform.map(region)); + } + break; + } + + updateScissor(); +} + +void QVGPaintEngine::clip(const QPainterPath &path, Qt::ClipOperation op) +{ + QPaintEngineEx::clip(path, op); +} + +#else // !QVG_SCISSOR_CLIP + +void QVGPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op) +{ + Q_D(QVGPaintEngine); + + d->dirty |= QPaintEngine::DirtyClipRegion; + + if (op == Qt::NoClip) { + d->maskValid = false; + d->maskIsSet = true; + d->maskRect = QRect(); + vgSeti(VG_MASKING, VG_FALSE); + return; + } + +#if defined(QVG_NO_RENDER_TO_MASK) + // We don't have vgRenderToMask(), so handle simple QRectF's only. + if (path.shape() == QVectorPath::RectangleHint && + path.elementCount() == 4 && clipTransformIsSimple(d->transform)) { + // Clipping region that resulted from QPainter::setClipRect(QRectF). + // Convert it into a QRect and apply. + const qreal *points = path.points(); + QRectF rect(points[0], points[1], points[2] - points[0], + points[5] - points[1]); + clip(rect.toRect(), op); + } +#else + QPaintDevice *pdev = paintDevice(); + int width = pdev->width(); + int height = pdev->height(); + + if (op == Qt::ReplaceClip) { + vgMask(VG_INVALID_HANDLE, VG_CLEAR_MASK, 0, 0, width, height); + d->maskRect = QRect(); + } else if (!d->maskValid) { + d->ensureMask(this, width, height); + } + + d->ensurePathTransform(); + VGPath vgpath = d->vectorPathToVGPath(path); + switch (op) { + case Qt::ReplaceClip: + case Qt::UniteClip: + vgRenderToMask(vgpath, VG_FILL_PATH, VG_UNION_MASK); + break; + + case Qt::IntersectClip: + vgRenderToMask(vgpath, VG_FILL_PATH, VG_INTERSECT_MASK); + break; + + default: break; + } + vgDestroyPath(vgpath); + + vgSeti(VG_MASKING, VG_TRUE); + d->maskValid = true; + d->maskIsSet = false; +#endif +} + +void QVGPaintEngine::clip(const QRect &rect, Qt::ClipOperation op) +{ + clip(QRegion(rect), op); +} + +void QVGPaintEngine::clip(const QRegion ®ion, Qt::ClipOperation op) +{ + Q_D(QVGPaintEngine); + + d->dirty |= QPaintEngine::DirtyClipRegion; + + // If we have a non-simple transform, then use path-based clipping. + if (op != Qt::NoClip && !clipTransformIsSimple(d->transform)) { + QPaintEngineEx::clip(region, op); + return; + } + + switch (op) { + case Qt::NoClip: + { + d->maskValid = false; + d->maskIsSet = true; + d->maskRect = QRect(); + vgSeti(VG_MASKING, VG_FALSE); + } + break; + + case Qt::ReplaceClip: + { + QRegion r = d->transform.map(region); + if (isDefaultClipRegion(r)) { + // Replacing the clip with a full-window region is the + // same as turning off clipping. + if (d->maskValid) + vgSeti(VG_MASKING, VG_FALSE); + d->maskValid = false; + d->maskIsSet = true; + d->maskRect = QRect(); + } else { + // Special case: if the intersection of the system + // clip and the region is a single rectangle, then + // use the scissor for clipping. + QRegion clip = d->systemClip; + if (clip.isEmpty()) + clip = r; + else + clip = clip.intersect(r); + if (r.numRects() == 1) { + d->maskValid = false; + d->maskIsSet = false; + d->maskRect = r.boundingRect(); + vgSeti(VG_MASKING, VG_FALSE); + updateScissor(); + } else { + d->maskValid = false; + d->maskIsSet = false; + d->maskRect = QRect(); + d->modifyMask(this, VG_FILL_MASK, r); + } + } + } + break; + + case Qt::IntersectClip: + { + if (region.numRects() != 1) { + // If there is more than one rectangle, then intersecting + // the rectangles one by one in modifyMask() will not give + // the desired result. So fall back to path-based clipping. + QPaintEngineEx::clip(region, op); + return; + } + QRegion r = d->transform.map(region); + if (d->maskIsSet && isDefaultClipRegion(r)) { + // Intersecting a full-window clip with a full-window + // region is the same as turning off clipping. + if (d->maskValid) + vgSeti(VG_MASKING, VG_FALSE); + d->maskValid = false; + d->maskIsSet = true; + d->maskRect = QRect(); + } else { + d->modifyMask(this, VG_INTERSECT_MASK, r); + } + } + break; + + case Qt::UniteClip: + { + // If we already have a full-window clip, then uniting a + // region with it will do nothing. Otherwise union. + if (!(d->maskIsSet)) + d->modifyMask(this, VG_UNION_MASK, d->transform.map(region)); + } + break; + } +} + +void QVGPaintEngine::clip(const QPainterPath &path, Qt::ClipOperation op) +{ +#if !defined(QVG_NO_RENDER_TO_MASK) + Q_D(QVGPaintEngine); + + d->dirty |= QPaintEngine::DirtyClipRegion; + + if (op == Qt::NoClip) { + d->maskValid = false; + d->maskIsSet = true; + d->maskRect = QRect(); + vgSeti(VG_MASKING, VG_FALSE); + return; + } + + QPaintDevice *pdev = paintDevice(); + int width = pdev->width(); + int height = pdev->height(); + + if (op == Qt::ReplaceClip) { + vgMask(VG_INVALID_HANDLE, VG_CLEAR_MASK, 0, 0, width, height); + d->maskRect = QRect(); + } else if (!d->maskValid) { + d->ensureMask(this, width, height); + } + + d->ensurePathTransform(); + VGPath vgpath = d->painterPathToVGPath(path); + switch (op) { + case Qt::ReplaceClip: + case Qt::UniteClip: + vgRenderToMask(vgpath, VG_FILL_PATH, VG_UNION_MASK); + break; + + case Qt::IntersectClip: + vgRenderToMask(vgpath, VG_FILL_PATH, VG_INTERSECT_MASK); + break; + + default: break; + } + vgDestroyPath(vgpath); + + vgSeti(VG_MASKING, VG_TRUE); + d->maskValid = true; + d->maskIsSet = false; +#else + QPaintEngineEx::clip(path, op); +#endif +} + +void QVGPaintEnginePrivate::ensureMask + (QVGPaintEngine *engine, int width, int height) +{ + if (maskIsSet) { + vgMask(VG_INVALID_HANDLE, VG_FILL_MASK, 0, 0, width, height); + maskRect = QRect(); + } else { + vgMask(VG_INVALID_HANDLE, VG_CLEAR_MASK, 0, 0, width, height); + if (!maskRect.isNull()) { + vgMask(VG_INVALID_HANDLE, VG_FILL_MASK, + maskRect.x(), height - maskRect.y() - maskRect.height(), + maskRect.width(), maskRect.height()); + maskRect = QRect(); + engine->updateScissor(); + } + } +} + +void QVGPaintEnginePrivate::modifyMask + (QVGPaintEngine *engine, VGMaskOperation op, const QRegion& region) +{ + QPaintDevice *pdev = engine->paintDevice(); + int width = pdev->width(); + int height = pdev->height(); + + if (!maskValid) + ensureMask(engine, width, height); + + QVector rects = region.rects(); + for (int i = 0; i < rects.size(); ++i) { + vgMask(VG_INVALID_HANDLE, op, + rects[i].x(), height - rects[i].y() - rects[i].height(), + rects[i].width(), rects[i].height()); + } + + vgSeti(VG_MASKING, VG_TRUE); + maskValid = true; + maskIsSet = false; +} + +#endif // !QVG_SCISSOR_CLIP + +void QVGPaintEngine::updateScissor() +{ + Q_D(QVGPaintEngine); + + QRegion region = d->systemClip; + +#if defined(QVG_SCISSOR_CLIP) + // Using the scissor to do clipping, so combine the systemClip + // with the current painting clipRegion. + QVGPainterState *s = state(); + if (s->clipEnabled) { + if (region.isEmpty()) + region = s->clipRegion; + else + region = region.intersect(s->clipRegion); + if (isDefaultClipRegion(region)) { + // The scissor region is the entire drawing surface, + // so there is no point doing any scissoring. + vgSeti(VG_SCISSORING, VG_FALSE); + d->scissorActive = false; + return; + } + } else +#endif + { +#if !defined(QVG_SCISSOR_CLIP) + // Combine the system clip with the simple mask rectangle. + if (!d->maskRect.isNull()) { + if (region.isEmpty()) + region = d->maskRect; + else + region.intersect(d->maskRect); + if (isDefaultClipRegion(region)) { + // The scissor region is the entire drawing surface, + // so there is no point doing any scissoring. + vgSeti(VG_SCISSORING, VG_FALSE); + d->scissorActive = false; + return; + } + } else +#endif + + // Disable the scissor completely if the system clip is empty. + if (region.isEmpty()) { + vgSeti(VG_SCISSORING, VG_FALSE); + d->scissorActive = false; + return; + } + } + + if (d->scissorActive && region == d->scissorRegion) + return; + + QVector rects = region.rects(); + int count = rects.count(); + if (count > d->maxScissorRects) + count = d->maxScissorRects; + QVarLengthArray params(count * 4); + int height = paintDevice()->height(); + for (int i = 0; i < count; ++i) { + params[i * 4 + 0] = rects[i].x(); + params[i * 4 + 1] = height - rects[i].y() - rects[i].height(); + params[i * 4 + 2] = rects[i].width(); + params[i * 4 + 3] = rects[i].height(); + } + + vgSetiv(VG_SCISSOR_RECTS, count * 4, params.data()); + vgSeti(VG_SCISSORING, VG_TRUE); + d->scissorActive = true; + d->scissorRegion = region; +} + +QRegion QVGPaintEngine::defaultClipRegion() +{ + // The default clip region for a paint device is the whole drawing area. + QPaintDevice *pdev = paintDevice(); + return QRegion(0, 0, pdev->width(), pdev->height()); +} + +bool QVGPaintEngine::isDefaultClipRegion(const QRegion& region) +{ + if (region.numRects() != 1) + return false; + + QPaintDevice *pdev = paintDevice(); + int width = pdev->width(); + int height = pdev->height(); + + QRect rect = region.boundingRect(); + return (rect.x() == 0 && rect.y() == 0 && + rect.width() == width && rect.height() == height); +} + +void QVGPaintEngine::clipEnabledChanged() +{ +#if defined(QVG_SCISSOR_CLIP) + updateScissor(); +#else + Q_D(QVGPaintEngine); + QVGPainterState *s = state(); + d->dirty |= QPaintEngine::DirtyClipEnabled; + if (s->clipEnabled && s->clipOperation != Qt::NoClip) { + // Replay the entire clip stack to put the mask into the right state. + d->maskValid = false; + d->maskIsSet = true; + d->maskRect = QRect(); + s->clipRegion = defaultClipRegion(); + d->replayClipOperations(); + d->transform = s->transform(); + d->updateTransform(paintDevice()); + } else { + vgSeti(VG_MASKING, VG_FALSE); + d->maskValid = false; + d->maskIsSet = false; + d->maskRect = QRect(); + } +#endif +} + +void QVGPaintEngine::penChanged() +{ + Q_D(QVGPaintEngine); + d->dirty |= QPaintEngine::DirtyPen; +} + +void QVGPaintEngine::brushChanged() +{ + Q_D(QVGPaintEngine); + d->dirty |= QPaintEngine::DirtyBrush; +} + +void QVGPaintEngine::brushOriginChanged() +{ + Q_D(QVGPaintEngine); + d->dirty |= QPaintEngine::DirtyBrushOrigin; + d->brushOrigin = state()->brushOrigin; + d->forcePenChange = true; + d->forceBrushChange = true; +} + +void QVGPaintEngine::opacityChanged() +{ + Q_D(QVGPaintEngine); + d->dirty |= QPaintEngine::DirtyOpacity; + d->opacity = state()->opacity; + d->forcePenChange = true; + d->forceBrushChange = true; +} + +void QVGPaintEngine::compositionModeChanged() +{ + Q_D(QVGPaintEngine); + d->dirty |= QPaintEngine::DirtyCompositionMode; + + VGBlendMode vgMode = VG_BLEND_SRC_OVER; + + switch (state()->composition_mode) { + case QPainter::CompositionMode_SourceOver: + vgMode = VG_BLEND_SRC_OVER; + break; + case QPainter::CompositionMode_DestinationOver: + vgMode = VG_BLEND_DST_OVER; + break; + case QPainter::CompositionMode_Source: + vgMode = VG_BLEND_SRC; + break; + case QPainter::CompositionMode_SourceIn: + vgMode = VG_BLEND_SRC_IN; + break; + case QPainter::CompositionMode_DestinationIn: + vgMode = VG_BLEND_DST_IN; + break; + case QPainter::CompositionMode_Plus: + vgMode = VG_BLEND_ADDITIVE; + break; + case QPainter::CompositionMode_Multiply: + vgMode = VG_BLEND_MULTIPLY; + break; + case QPainter::CompositionMode_Screen: + vgMode = VG_BLEND_SCREEN; + break; + case QPainter::CompositionMode_Darken: + vgMode = VG_BLEND_DARKEN; + break; + case QPainter::CompositionMode_Lighten: + vgMode = VG_BLEND_LIGHTEN; + break; + default: + qWarning() << "QVGPaintEngine::compositionModeChanged unsupported mode" << state()->composition_mode; + break; // Fall back to VG_BLEND_SRC_OVER. + } + + d->setBlendMode(vgMode); +} + +void QVGPaintEngine::renderHintsChanged() +{ + Q_D(QVGPaintEngine); + d->dirty |= QPaintEngine::DirtyHints; + + QPainter::RenderHints hints = state()->renderHints; + + VGRenderingQuality rq = + (hints & QPainter::Antialiasing) + ? VG_RENDERING_QUALITY_BETTER + : VG_RENDERING_QUALITY_NONANTIALIASED; + VGImageQuality iq = + (hints & QPainter::SmoothPixmapTransform) + ? VG_IMAGE_QUALITY_BETTER + : VG_IMAGE_QUALITY_NONANTIALIASED; + + d->setRenderingQuality(rq); + d->setImageQuality(iq); +} + +void QVGPaintEngine::transformChanged() +{ + Q_D(QVGPaintEngine); + QVGPainterState *s = state(); + d->dirty |= QPaintEngine::DirtyTransform; + d->transform = s->transform(); + qreal oldPenScale = d->penScale; + d->updateTransform(paintDevice()); + if (d->penScale != oldPenScale) + d->forcePenChange = true; +} + +bool QVGPaintEngine::clearRect(const QRectF &rect, const QColor &color) +{ + Q_D(QVGPaintEngine); + QVGPainterState *s = state(); + if (!s->clipEnabled || s->clipOperation == Qt::NoClip) { + // The transform will either be identity or a simple translation, + // so do a simpler version of "r = d->transform.map(rect).toRect()". + QRect r = QRect(qRound(rect.x() + d->transform.dx()), + qRound(rect.y() + d->transform.dy()), + qRound(rect.width()), + qRound(rect.height())); + int height = paintDevice()->height(); + if (d->clearColor != color || d->clearOpacity != s->opacity) { + VGfloat values[4]; + values[0] = color.redF(); + values[1] = color.greenF(); + values[2] = color.blueF(); + values[3] = color.alphaF() * s->opacity; + vgSetfv(VG_CLEAR_COLOR, 4, values); + d->clearColor = color; + d->clearOpacity = s->opacity; + } + vgClear(r.x(), height - r.y() - r.height(), + r.width(), r.height()); + return true; + } + return false; +} + +void QVGPaintEngine::fillRect(const QRectF &rect, const QBrush &brush) +{ + Q_D(QVGPaintEngine); + + if (brush.style() == Qt::NoBrush) + return; + + // Check to see if we can use vgClear() for faster filling. + if (brush.style() == Qt::SolidPattern && + clipTransformIsSimple(d->transform) && d->opacity == 1.0f && + clearRect(rect, brush.color())) { + return; + } + +#if !defined(QVG_NO_MODIFY_PATH) + VGfloat coords[8]; + if (d->simpleTransform) { + coords[0] = rect.x(); + coords[1] = rect.y(); + coords[2] = rect.x() + rect.width(); + coords[3] = coords[1]; + coords[4] = coords[2]; + coords[5] = rect.y() + rect.height(); + coords[6] = coords[0]; + coords[7] = coords[5]; + } else { + QPointF tl = d->transform.map(rect.topLeft()); + QPointF tr = d->transform.map(rect.topRight()); + QPointF bl = d->transform.map(rect.bottomLeft()); + QPointF br = d->transform.map(rect.bottomRight()); + coords[0] = tl.x(); + coords[1] = tl.y(); + coords[2] = tr.x(); + coords[3] = tr.y(); + coords[4] = br.x(); + coords[5] = br.y(); + coords[6] = bl.x(); + coords[7] = bl.y(); + } + vgModifyPathCoords(d->rectPath, 0, 4, coords); + d->fill(d->rectPath, brush); +#else + QPaintEngineEx::fillRect(rect, brush); +#endif +} + +void QVGPaintEngine::fillRect(const QRectF &rect, const QColor &color) +{ + Q_D(QVGPaintEngine); + + // Check to see if we can use vgClear() for faster filling. + if (clipTransformIsSimple(d->transform) && d->opacity == 1.0f && + clearRect(rect, color)) { + return; + } + +#if !defined(QVG_NO_MODIFY_PATH) + VGfloat coords[8]; + if (d->simpleTransform) { + coords[0] = rect.x(); + coords[1] = rect.y(); + coords[2] = rect.x() + rect.width(); + coords[3] = coords[1]; + coords[4] = coords[2]; + coords[5] = rect.y() + rect.height(); + coords[6] = coords[0]; + coords[7] = coords[5]; + } else { + QPointF tl = d->transform.map(rect.topLeft()); + QPointF tr = d->transform.map(rect.topRight()); + QPointF bl = d->transform.map(rect.bottomLeft()); + QPointF br = d->transform.map(rect.bottomRight()); + coords[0] = tl.x(); + coords[1] = tl.y(); + coords[2] = tr.x(); + coords[3] = tr.y(); + coords[4] = br.x(); + coords[5] = br.y(); + coords[6] = bl.x(); + coords[7] = bl.y(); + } + vgModifyPathCoords(d->rectPath, 0, 4, coords); + d->fill(d->rectPath, QBrush(color)); +#else + QPaintEngineEx::fillRect(rect, QBrush(color)); +#endif +} + +void QVGPaintEngine::drawRects(const QRect *rects, int rectCount) +{ +#if !defined(QVG_NO_MODIFY_PATH) + Q_D(QVGPaintEngine); + QVGPainterState *s = state(); + for (int i = 0; i < rectCount; ++i, ++rects) { + VGfloat coords[8]; + if (d->simpleTransform) { + coords[0] = rects->x(); + coords[1] = rects->y(); + coords[2] = rects->x() + rects->width(); + coords[3] = coords[1]; + coords[4] = coords[2]; + coords[5] = rects->y() + rects->height(); + coords[6] = coords[0]; + coords[7] = coords[5]; + } else { + QPointF tl = d->transform.map(QPointF(rects->x(), rects->y())); + QPointF tr = d->transform.map(QPointF(rects->x() + rects->width(), + rects->y())); + QPointF bl = d->transform.map(QPointF(rects->x(), + rects->y() + rects->height())); + QPointF br = d->transform.map(QPointF(rects->x() + rects->width(), + rects->y() + rects->height())); + coords[0] = tl.x(); + coords[1] = tl.y(); + coords[2] = tr.x(); + coords[3] = tr.y(); + coords[4] = br.x(); + coords[5] = br.y(); + coords[6] = bl.x(); + coords[7] = bl.y(); + } + vgModifyPathCoords(d->rectPath, 0, 4, coords); + d->draw(d->rectPath, s->pen, s->brush); + } +#else + QPaintEngineEx::drawRects(rects, rectCount); +#endif +} + +void QVGPaintEngine::drawRects(const QRectF *rects, int rectCount) +{ +#if !defined(QVG_NO_MODIFY_PATH) + Q_D(QVGPaintEngine); + QVGPainterState *s = state(); + for (int i = 0; i < rectCount; ++i, ++rects) { + VGfloat coords[8]; + if (d->simpleTransform) { + coords[0] = rects->x(); + coords[1] = rects->y(); + coords[2] = rects->x() + rects->width(); + coords[3] = coords[1]; + coords[4] = coords[2]; + coords[5] = rects->y() + rects->height(); + coords[6] = coords[0]; + coords[7] = coords[5]; + } else { + QPointF tl = d->transform.map(rects->topLeft()); + QPointF tr = d->transform.map(rects->topRight()); + QPointF bl = d->transform.map(rects->bottomLeft()); + QPointF br = d->transform.map(rects->bottomRight()); + coords[0] = tl.x(); + coords[1] = tl.y(); + coords[2] = tr.x(); + coords[3] = tr.y(); + coords[4] = br.x(); + coords[5] = br.y(); + coords[6] = bl.x(); + coords[7] = bl.y(); + } + vgModifyPathCoords(d->rectPath, 0, 4, coords); + d->draw(d->rectPath, s->pen, s->brush); + } +#else + QPaintEngineEx::drawRects(rects, rectCount); +#endif +} + +void QVGPaintEngine::drawLines(const QLine *lines, int lineCount) +{ +#if !defined(QVG_NO_MODIFY_PATH) + Q_D(QVGPaintEngine); + QVGPainterState *s = state(); + for (int i = 0; i < lineCount; ++i, ++lines) { + VGfloat coords[4]; + if (d->simpleTransform) { + coords[0] = lines->x1(); + coords[1] = lines->y1(); + coords[2] = lines->x2(); + coords[3] = lines->y2(); + } else { + QPointF p1 = d->transform.map(QPointF(lines->x1(), lines->y1())); + QPointF p2 = d->transform.map(QPointF(lines->x2(), lines->y2())); + coords[0] = p1.x(); + coords[1] = p1.y(); + coords[2] = p2.x(); + coords[3] = p2.y(); + } + vgModifyPathCoords(d->linePath, 0, 2, coords); + d->stroke(d->linePath, s->pen); + } +#else + QPaintEngineEx::drawLines(lines, lineCount); +#endif +} + +void QVGPaintEngine::drawLines(const QLineF *lines, int lineCount) +{ +#if !defined(QVG_NO_MODIFY_PATH) + Q_D(QVGPaintEngine); + QVGPainterState *s = state(); + for (int i = 0; i < lineCount; ++i, ++lines) { + VGfloat coords[4]; + if (d->simpleTransform) { + coords[0] = lines->x1(); + coords[1] = lines->y1(); + coords[2] = lines->x2(); + coords[3] = lines->y2(); + } else { + QPointF p1 = d->transform.map(lines->p1()); + QPointF p2 = d->transform.map(lines->p2()); + coords[0] = p1.x(); + coords[1] = p1.y(); + coords[2] = p2.x(); + coords[3] = p2.y(); + } + vgModifyPathCoords(d->linePath, 0, 2, coords); + d->stroke(d->linePath, s->pen); + } +#else + QPaintEngineEx::drawLines(lines, lineCount); +#endif +} + +void QVGPaintEngine::drawEllipse(const QRectF &r) +{ + // Based on the description of vguEllipse() in the OpenVG specification. + // We don't use vguEllipse(), to avoid unnecessary library dependencies. + Q_D(QVGPaintEngine); + if (d->simpleTransform) { + QVGPainterState *s = state(); + VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD, + VG_PATH_DATATYPE_F, + 1.0f, // scale + 0.0f, // bias + 4, // segmentCapacityHint + 12, // coordCapacityHint + VG_PATH_CAPABILITY_ALL); + static VGubyte segments[4] = { + VG_MOVE_TO_ABS, + VG_SCCWARC_TO_REL, + VG_SCCWARC_TO_REL, + VG_CLOSE_PATH + }; + VGfloat coords[12]; + VGfloat halfwid = r.width() / 2; + VGfloat halfht = r.height() / 2; + coords[0] = r.x() + r.width(); + coords[1] = r.y() + halfht; + coords[2] = halfwid; + coords[3] = halfht; + coords[4] = 0.0f; + coords[5] = -r.width(); + coords[6] = 0.0f; + coords[7] = halfwid; + coords[8] = halfht; + coords[9] = 0.0f; + coords[10] = r.width(); + coords[11] = 0.0f; + vgAppendPathData(path, 4, segments, coords); + d->draw(path, s->pen, s->brush); + vgDestroyPath(path); + } else { + // The projective transform version of an ellipse is difficult. + // Generate a QVectorPath containing cubic curves and transform that. + QPaintEngineEx::drawEllipse(r); + } +} + +void QVGPaintEngine::drawEllipse(const QRect &r) +{ + drawEllipse(QRectF(r)); +} + +void QVGPaintEngine::drawPath(const QPainterPath &path) +{ + // Shortcut past the QPainterPath -> QVectorPath conversion, + // converting the QPainterPath directly into a VGPath. + Q_D(QVGPaintEngine); + QVGPainterState *s = state(); + VGPath vgpath = d->painterPathToVGPath(path); + if (path.fillRule() == Qt::OddEvenFill) + d->draw(vgpath, s->pen, s->brush, VG_EVEN_ODD); + else + d->draw(vgpath, s->pen, s->brush, VG_NON_ZERO); + vgDestroyPath(vgpath); +} + +void QVGPaintEngine::drawPoints(const QPointF *points, int pointCount) +{ +#if !defined(QVG_NO_MODIFY_PATH) + Q_D(QVGPaintEngine); + + // Set up a new pen if necessary. + QPen pen = state()->pen; + if (pen.style() == Qt::NoPen) + return; + if (pen.capStyle() == Qt::FlatCap) + pen.setCapStyle(Qt::SquareCap); + + for (int i = 0; i < pointCount; ++i, ++points) { + VGfloat coords[4]; + if (d->simpleTransform) { + coords[0] = points->x(); + coords[1] = points->y(); + coords[2] = coords[0]; + coords[3] = coords[1]; + } else { + QPointF p = d->transform.map(*points); + coords[0] = p.x(); + coords[1] = p.y(); + coords[2] = coords[0]; + coords[3] = coords[1]; + } + vgModifyPathCoords(d->linePath, 0, 2, coords); + d->stroke(d->linePath, pen); + } +#else + QPaintEngineEx::drawPoints(points, pointCount); +#endif +} + +void QVGPaintEngine::drawPoints(const QPoint *points, int pointCount) +{ +#if !defined(QVG_NO_MODIFY_PATH) + Q_D(QVGPaintEngine); + + // Set up a new pen if necessary. + QPen pen = state()->pen; + if (pen.style() == Qt::NoPen) + return; + if (pen.capStyle() == Qt::FlatCap) + pen.setCapStyle(Qt::SquareCap); + + for (int i = 0; i < pointCount; ++i, ++points) { + VGfloat coords[4]; + if (d->simpleTransform) { + coords[0] = points->x(); + coords[1] = points->y(); + coords[2] = coords[0]; + coords[3] = coords[1]; + } else { + QPointF p = d->transform.map(QPointF(*points)); + coords[0] = p.x(); + coords[1] = p.y(); + coords[2] = coords[0]; + coords[3] = coords[1]; + } + vgModifyPathCoords(d->linePath, 0, 2, coords); + d->stroke(d->linePath, pen); + } +#else + QPaintEngineEx::drawPoints(points, pointCount); +#endif +} + +void QVGPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode) +{ + Q_D(QVGPaintEngine); + QVGPainterState *s = state(); + VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD, + VG_PATH_DATATYPE_F, + 1.0f, // scale + 0.0f, // bias + pointCount + 1, // segmentCapacityHint + pointCount * 2, // coordCapacityHint + VG_PATH_CAPABILITY_ALL); + QVarLengthArray coords; + QVarLengthArray segments; + for (int i = 0; i < pointCount; ++i, ++points) { + if (d->simpleTransform) { + coords.append(points->x()); + coords.append(points->y()); + } else { + QPointF temp = d->transform.map(*points); + coords.append(temp.x()); + coords.append(temp.y()); + } + if (i == 0) + segments.append(VG_MOVE_TO_ABS); + else + segments.append(VG_LINE_TO_ABS); + } + if (mode != QPaintEngine::PolylineMode) + segments.append(VG_CLOSE_PATH); + vgAppendPathData(path, segments.count(), + segments.constData(), coords.constData()); + switch (mode) { + case QPaintEngine::WindingMode: + d->draw(path, s->pen, s->brush, VG_NON_ZERO); + break; + + case QPaintEngine::PolylineMode: + d->stroke(path, s->pen); + break; + + default: + d->draw(path, s->pen, s->brush, VG_EVEN_ODD); + break; + } + vgDestroyPath(path); +} + +void QVGPaintEngine::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode) +{ + Q_D(QVGPaintEngine); + QVGPainterState *s = state(); + VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD, + VG_PATH_DATATYPE_F, + 1.0f, // scale + 0.0f, // bias + pointCount + 1, // segmentCapacityHint + pointCount * 2, // coordCapacityHint + VG_PATH_CAPABILITY_ALL); + QVarLengthArray coords; + QVarLengthArray segments; + for (int i = 0; i < pointCount; ++i, ++points) { + if (d->simpleTransform) { + coords.append(points->x()); + coords.append(points->y()); + } else { + QPointF temp = d->transform.map(QPointF(*points)); + coords.append(temp.x()); + coords.append(temp.y()); + } + if (i == 0) + segments.append(VG_MOVE_TO_ABS); + else + segments.append(VG_LINE_TO_ABS); + } + if (mode != QPaintEngine::PolylineMode) + segments.append(VG_CLOSE_PATH); + vgAppendPathData(path, segments.count(), + segments.constData(), coords.constData()); + switch (mode) { + case QPaintEngine::WindingMode: + d->draw(path, s->pen, s->brush, VG_NON_ZERO); + break; + + case QPaintEngine::PolylineMode: + d->stroke(path, s->pen); + break; + + default: + d->draw(path, s->pen, s->brush, VG_EVEN_ODD); + break; + } + vgDestroyPath(path); +} + +void QVGPaintEnginePrivate::setImageOptions() +{ + if (opacity != 1.0f && simpleTransform) { + if (opacity != paintOpacity) { + VGfloat values[4]; + values[0] = 1.0f; + values[1] = 1.0f; + values[2] = 1.0f; + values[3] = opacity; + vgSetParameterfv(opacityPaint, VG_PAINT_COLOR, 4, values); + paintOpacity = opacity; + } + if (fillPaint != opacityPaint) { + vgSetPaint(opacityPaint, VG_FILL_PATH); + fillPaint = opacityPaint; + } + setImageMode(VG_DRAW_IMAGE_MULTIPLY); + } else { + setImageMode(VG_DRAW_IMAGE_NORMAL); + } +} + +static void drawVGImage(QVGPaintEnginePrivate *d, + const QRectF& r, VGImage vgImg, + const QSize& imageSize, const QRectF& sr) +{ + if (vgImg == VG_INVALID_HANDLE) + return; + VGImage child = VG_INVALID_HANDLE; + + if (sr.topLeft().isNull() && sr.size() == imageSize) { + child = vgImg; + } else { + QRect src = sr.toRect(); +#if !defined(QT_SHIVAVG) + child = vgChildImage(vgImg, src.x(), src.y(), src.width(), src.height()); +#else + child = vgImg; // XXX: ShivaVG doesn't have vgChildImage(). +#endif + } + + QTransform transform(d->imageTransform); + VGfloat scaleX = sr.width() == 0.0f ? 0.0f : r.width() / sr.width(); + VGfloat scaleY = sr.height() == 0.0f ? 0.0f : r.height() / sr.height(); + transform.translate(r.x(), r.y()); + transform.scale(scaleX, scaleY); + d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform); + + d->setImageOptions(); + vgDrawImage(child); + + if(child != vgImg) + vgDestroyImage(child); +} + +static void drawVGImage(QVGPaintEnginePrivate *d, + const QPointF& pos, VGImage vgImg) +{ + if (vgImg == VG_INVALID_HANDLE) + return; + + QTransform transform(d->imageTransform); + transform.translate(pos.x(), pos.y()); + d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform); + + d->setImageOptions(); + vgDrawImage(vgImg); +} + +// Used by qpixmapfilter_vg.cpp to draw filtered VGImage's. +void qt_vg_drawVGImage(QPainter *painter, const QPointF& pos, VGImage vgImg) +{ + QVGPaintEngine *engine = + static_cast(painter->paintEngine()); + drawVGImage(engine->vgPrivate(), pos, vgImg); +} + +void QVGPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) +{ + QPixmapData *pd = pm.pixmapData(); + if (pd->classId() == QPixmapData::OpenVGClass) { + Q_D(QVGPaintEngine); + QVGPixmapData *vgpd = static_cast(pd); + if (!vgpd->isValid()) + return; + if (d->simpleTransform) + drawVGImage(d, r, vgpd->toVGImage(), vgpd->size(), sr); + else + drawVGImage(d, r, vgpd->toVGImage(d->opacity), vgpd->size(), sr); + } else { + drawImage(r, *(pd->buffer()), sr, Qt::AutoColor); + } +} + +void QVGPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pm) +{ + QPixmapData *pd = pm.pixmapData(); + if (pd->classId() == QPixmapData::OpenVGClass) { + Q_D(QVGPaintEngine); + QVGPixmapData *vgpd = static_cast(pd); + if (!vgpd->isValid()) + return; + if (d->simpleTransform) + drawVGImage(d, pos, vgpd->toVGImage()); + else + drawVGImage(d, pos, vgpd->toVGImage(d->opacity)); + } else { + drawImage(pos, *(pd->buffer())); + } +} + +void QVGPaintEngine::drawImage + (const QRectF &r, const QImage &image, const QRectF &sr, + Qt::ImageConversionFlags flags) +{ + Q_D(QVGPaintEngine); + VGImage vgImg; + if (d->simpleTransform || d->opacity == 1.0f) + vgImg = toVGImageSubRect(image, sr.toRect(), flags); + else + vgImg = toVGImageWithOpacitySubRect(image, d->opacity, sr.toRect()); + if (vgImg != VG_INVALID_HANDLE) { + if (r.size() == sr.size()) { + drawVGImage(d, r.topLeft(), vgImg); + } else { + drawVGImage(d, r, vgImg, sr.size().toSize(), + QRectF(QPointF(0, 0), sr.size())); + } + } else { + // Monochrome images need to use the vgChildImage() path. + vgImg = toVGImage(image, flags); + drawVGImage(d, r, vgImg, image.size(), sr); + } + vgDestroyImage(vgImg); +} + +void QVGPaintEngine::drawImage(const QPointF &pos, const QImage &image) +{ + Q_D(QVGPaintEngine); + VGImage vgImg; + if (d->simpleTransform || d->opacity == 1.0f) + vgImg = toVGImage(image); + else + vgImg = toVGImageWithOpacity(image, d->opacity); + drawVGImage(d, pos, vgImg); + vgDestroyImage(vgImg); +} + +void QVGPaintEngine::drawTiledPixmap + (const QRectF &r, const QPixmap &pixmap, const QPointF &s) +{ + QBrush brush(state()->pen.color(), pixmap); + QTransform xform; + xform.translate(-s.x(), -s.y()); + brush.setTransform(xform); + fillRect(r, brush); +} + +QVGFontEngineCleaner::QVGFontEngineCleaner(QVGPaintEnginePrivate *d) + : QObject(), d_ptr(d) +{ +} + +QVGFontEngineCleaner::~QVGFontEngineCleaner() +{ +} + +void QVGFontEngineCleaner::fontEngineDestroyed() +{ +#if !defined(QVG_NO_DRAW_GLYPHS) + QFontEngine *engine = static_cast(sender()); + QVGFontCache::Iterator it = d_ptr->fontCache.find(engine); + if (it != d_ptr->fontCache.end()) { + delete it.value(); + d_ptr->fontCache.erase(it); + } +#endif +} + +#if !defined(QVG_NO_DRAW_GLYPHS) + +QVGFontGlyphCache::QVGFontGlyphCache() +{ + font = vgCreateFont(0); + scaleX = scaleY = 0.0; + memset(cachedGlyphsMask, 0, sizeof(cachedGlyphsMask)); +} + +QVGFontGlyphCache::~QVGFontGlyphCache() +{ + if (font != VG_INVALID_HANDLE) + vgDestroyFont(font); +} + +void QVGFontGlyphCache::setScaleFromText(const QTextItemInt &ti) +{ + QFontInfo fi(ti.font()); + qreal pixelSize = fi.pixelSize(); + qreal emSquare = ti.fontEngine->properties().emSquare.toReal(); + scaleX = scaleY = static_cast(pixelSize / emSquare); +} + +void QVGFontGlyphCache::cacheGlyphs + (QVGPaintEnginePrivate *d, const QTextItemInt &ti, + const QVarLengthArray &glyphs) +{ + VGfloat origin[2]; + VGfloat escapement[2]; + const glyph_t *g = glyphs.constData(); + int count = glyphs.size(); + glyph_metrics_t metrics; + // Some Qt font engines don't set yoff in getUnscaledGlyph(). + // Zero the metric structure so that everything has a default value. + memset(&metrics, 0, sizeof(metrics)); + while (count-- > 0) { + // Skip this glyph if we have already cached it before. + glyph_t glyph = *g++; + if (glyph < 256) { + if ((cachedGlyphsMask[glyph / 32] & (1 << (glyph % 32))) != 0) + continue; + cachedGlyphsMask[glyph / 32] |= (1 << (glyph % 32)); + } else if (cachedGlyphs.contains(glyph)) { + continue; + } else { + cachedGlyphs.insert(glyph); + } +#if !defined(QVG_NO_IMAGE_GLYPHS) + Q_UNUSED(d); + QImage scaledImage = ti.fontEngine->alphaMapForGlyph(glyph); + VGImage vgImage = VG_INVALID_HANDLE; + metrics = ti.fontEngine->boundingBox(glyph); + if (!scaledImage.isNull()) { // Not a space character + // The QPF implementation of alphaMapForGlyph() uses the color + // RGBA = (value, value, value, 255) instead of the color + // RGBA = (0, 0, 0, value) that the other font engines use. + // We modify the image colors to rectify this situation. + QFontEngine::Type type = ti.fontEngine->type(); + if (type == QFontEngine::QPF1 || type == QFontEngine::QPF2) { + if (scaledImage.format() == QImage::Format_Indexed8) { + for (int i = 0; i < 256; ++i) + scaledImage.setColor(i, qRgba(0, 0, 0, i)); + } else if (scaledImage.format() == QImage::Format_Mono) { + scaledImage.setColor(0, qRgba(0, 0, 0, 0)); + scaledImage.setColor(1, qRgba(0, 0, 0, 255)); + } + } + if (scaledImage.format() == QImage::Format_Indexed8) { + vgImage = vgCreateImage(VG_A_8, scaledImage.width(), scaledImage.height(), VG_IMAGE_QUALITY_FASTER); + vgImageSubData(vgImage, scaledImage.bits(), scaledImage.bytesPerLine(), VG_A_8, 0, 0, scaledImage.width(), scaledImage.height()); + } else if (scaledImage.format() == QImage::Format_Mono) { + QImage img = scaledImage.convertToFormat(QImage::Format_Indexed8); + vgImage = vgCreateImage(VG_A_8, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER); + vgImageSubData(vgImage, img.bits(), img.bytesPerLine(), VG_A_8, 0, 0, img.width(), img.height()); + } else { + QImage img = scaledImage.convertToFormat(QImage::Format_ARGB32_Premultiplied); + vgImage = vgCreateImage(VG_sARGB_8888_PRE, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER); + vgImageSubData(vgImage, img.bits(), img.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0, img.width(), img.height()); + } + } + origin[0] = -metrics.x.toReal() + 0.5f; + origin[1] = -metrics.y.toReal() + 0.5f; + escapement[0] = metrics.xoff.toReal(); + escapement[1] = metrics.yoff.toReal(); + vgSetGlyphToImage(font, glyph, vgImage, origin, escapement); + vgDestroyImage(vgImage); // Reduce reference count. +#else + // Calculate the path for the glyph and cache it. + QPainterPath path; + ti.fontEngine->getUnscaledGlyph(glyph, &path, &metrics); + VGPath vgPath; + if (!path.isEmpty()) { + vgPath = d->painterPathToVGPath(path); + } else { + // Probably a "space" character with no visible outline. + vgPath = VG_INVALID_HANDLE; + } + origin[0] = 0; + origin[1] = 0; + escapement[0] = metrics.xoff.toReal(); + escapement[1] = metrics.yoff.toReal(); + vgSetGlyphToPath(font, glyph, vgPath, VG_FALSE, origin, escapement); + vgDestroyPath(vgPath); // Reduce reference count. +#endif // !defined(QVG_NO_IMAGE_GLYPHS) + } +} + +#endif // !defined(QVG_NO_DRAW_GLYPHS) + +void QVGPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem) +{ +#if !defined(QVG_NO_DRAW_GLYPHS) + Q_D(QVGPaintEngine); + const QTextItemInt &ti = static_cast(textItem); + + // If we are not using a simple transform, then fall back + // to the default Qt path stroking algorithm. + if (!d->simpleTransform) { + QPaintEngineEx::drawTextItem(p, textItem); + return; + } + + // Get the glyphs and positions associated with the text item. + QVarLengthArray positions; + QVarLengthArray glyphs; + QTransform matrix = d->transform; + matrix.translate(p.x(), p.y()); + ti.fontEngine->getGlyphPositions + (ti.glyphs, matrix, ti.flags, glyphs, positions); + + // Find the glyph cache for this font. + QVGFontCache::ConstIterator it = d->fontCache.constFind(ti.fontEngine); + QVGFontGlyphCache *glyphCache; + if (it != d->fontCache.constEnd()) { + glyphCache = it.value(); + } else { + glyphCache = new QVGFontGlyphCache(); + if (glyphCache->font == VG_INVALID_HANDLE) { + qWarning("QVGPaintEngine::drawTextItem: OpenVG fonts are not supported by the OpenVG engine"); + delete glyphCache; + QPaintEngineEx::drawTextItem(p, textItem); + return; + } + glyphCache->setScaleFromText(ti); + d->fontCache.insert(ti.fontEngine, glyphCache); + if (!d->fontEngineCleaner) + d->fontEngineCleaner = new QVGFontEngineCleaner(d); + QObject::connect(ti.fontEngine, SIGNAL(destroyed()), + d->fontEngineCleaner, SLOT(fontEngineDestroyed())); + } + + // Set the transformation to use for drawing the current glyphs. + QTransform glyphTransform(d->pathTransform); + glyphTransform.translate(p.x(), p.y()); +#if defined(QVG_NO_IMAGE_GLYPHS) + glyphTransform.scale(glyphCache->scaleX, glyphCache->scaleY); +#endif + d->setTransform(VG_MATRIX_GLYPH_USER_TO_SURFACE, glyphTransform); + + // Add the glyphs from the text item into the glyph cache. + glyphCache->cacheGlyphs(d, ti, glyphs); + + // Set the glyph drawing origin. + VGfloat origin[2]; + origin[0] = 0; + origin[1] = 0; + vgSetfv(VG_GLYPH_ORIGIN, 2, origin); + + // Fast anti-aliasing for paths, better for images. +#if !defined(QVG_NO_IMAGE_GLYPHS) + d->setImageQuality(VG_IMAGE_QUALITY_BETTER); + d->setImageMode(VG_DRAW_IMAGE_STENCIL); +#else + d->setRenderingQuality(VG_RENDERING_QUALITY_FASTER); +#endif + + // Draw the glyphs. We need to fill with the brush associated with + // the Qt pen, not the Qt brush. + d->ensureBrush(state()->pen.brush()); + vgDrawGlyphs(glyphCache->font, glyphs.size(), (VGuint*)glyphs.data(), + NULL, NULL, VG_FILL_PATH, VG_TRUE); +#else + // OpenGL 1.0 does not have support for VGFont and glyphs, + // so fall back to the default Qt path stroking algorithm. + QPaintEngineEx::drawTextItem(p, textItem); +#endif +} + +void QVGPaintEngine::setState(QPainterState *s) +{ + Q_D(QVGPaintEngine); + QPaintEngineEx::setState(s); + QVGPainterState *ps = static_cast(s); + if (ps->isNew) { + // Newly created state object. The call to setState() + // will either be followed by a call to begin(), or we are + // setting the state as part of a save(). + ps->isNew = false; + } else { + // This state object was set as part of a restore(). + restoreState(d->dirty); + d->dirty = ps->savedDirty; + } +} + +// Called from QPaintEngine::syncState() to force a state flush. +// This should be called before and after raw VG operations. +void QVGPaintEngine::updateState(const QPaintEngineState &state) +{ + Q_UNUSED(state); + Q_D(QVGPaintEngine); + + if (!(d->rawVG)) { + // About to enter raw VG mode: flush pending changes and make + // sure that all matrices are set to the current transformation. + QVGPainterState *s = this->state(); + d->ensurePen(s->pen); + d->ensureBrush(s->brush); + d->ensurePathTransform(); + d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, d->imageTransform); +#if !defined(QVG_NO_DRAW_GLYPHS) + d->setTransform(VG_MATRIX_GLYPH_USER_TO_SURFACE, d->pathTransform); +#endif + d->rawVG = true; + } else { + // Exiting raw VG mode: force all state values to be + // explicitly set on the VG engine to undo any changes + // that were made by the raw VG function calls. + QPaintEngine::DirtyFlags dirty = d->dirty; + d->clearModes(); + d->forcePenChange = true; + d->forceBrushChange = true; + d->penType = (VGPaintType)0; + d->brushType = (VGPaintType)0; + d->clearColor = QColor(); + d->fillPaint = d->brushPaint; + restoreState(QPaintEngine::AllDirty); + d->dirty = dirty; + d->rawVG = false; + vgSetPaint(d->penPaint, VG_STROKE_PATH); + vgSetPaint(d->brushPaint, VG_FILL_PATH); + } +} + +QPixmapFilter *QVGPaintEngine::createPixmapFilter(int type) const +{ +#if !defined(QT_SHIVAVG) + if (type == QPixmapFilter::ConvolutionFilter) + return new QVGPixmapConvolutionFilter; + else if (type == QPixmapFilter::ColorizeFilter) + return new QVGPixmapColorizeFilter; + else if (type == QPixmapFilter::DropShadowFilter) + return new QVGPixmapDropShadowFilter; + else +#endif + return QPaintEngineEx::createPixmapFilter(type); +} + +void QVGPaintEngine::restoreState(QPaintEngine::DirtyFlags dirty) +{ + Q_D(QVGPaintEngine); + + // Restore the pen, brush, and other settings. + if ((dirty & QPaintEngine::DirtyBrushOrigin) != 0) + brushOriginChanged(); + d->fillRule = 0; + if ((dirty & QPaintEngine::DirtyOpacity) != 0) + opacityChanged(); + if ((dirty & QPaintEngine::DirtyTransform) != 0) + transformChanged(); + if ((dirty & QPaintEngine::DirtyCompositionMode) != 0) + compositionModeChanged(); + if ((dirty & QPaintEngine::DirtyHints) != 0) + renderHintsChanged(); + if ((dirty & (QPaintEngine::DirtyClipRegion | + QPaintEngine::DirtyClipPath | + QPaintEngine::DirtyClipEnabled)) != 0) { + d->maskValid = false; + d->maskIsSet = false; + d->maskRect = QRect(); + clipEnabledChanged(); + } + +#if defined(QVG_SCISSOR_CLIP) + if ((dirty & (QPaintEngine::DirtyClipRegion | + QPaintEngine::DirtyClipPath | + QPaintEngine::DirtyClipEnabled)) == 0) { + updateScissor(); + } +#else + updateScissor(); +#endif +} + +#if !defined(QVG_NO_SINGLE_CONTEXT) && !defined(QT_NO_EGL) + +QVGCompositionHelper::QVGCompositionHelper() +{ + d = qt_vg_create_paint_engine()->vgPrivate(); +} + +QVGCompositionHelper::~QVGCompositionHelper() +{ +} + +void QVGCompositionHelper::startCompositing(const QSize& screenSize) +{ + this->screenSize = screenSize; + clearScissor(); + d->setBlendMode(VG_BLEND_SRC_OVER); +} + +void QVGCompositionHelper::endCompositing() +{ + clearScissor(); +} + +void QVGCompositionHelper::blitWindow + (QVGEGLWindowSurfacePrivate *surface, const QRect& rect, + const QPoint& topLeft, int opacity) +{ + // Get the VGImage that is acting as a back buffer for the window. + VGImage image = surface->surfaceImage(); + if (image == VG_INVALID_HANDLE) + return; + QSize imageSize = surface->surfaceSize(); + + // Determine which sub rectangle of the window to draw. + QRect sr = rect.translated(-topLeft); + + if (opacity >= 255) { + // Fully opaque: use vgSetPixels() to directly copy the sub-region. + int y = screenSize.height() - (rect.bottom() + 1); + vgSetPixels(rect.x(), y, image, sr.x(), + imageSize.height() - (sr.y() + sr.height()), + sr.width(), sr.height()); + } else { + // Extract the child image that we want to draw. + VGImage child; + if (sr.topLeft().isNull() && sr.size() == imageSize) + child = image; + else { + child = vgChildImage + (image, sr.x(), imageSize.height() - (sr.y() + sr.height()), + sr.width(), sr.height()); + } + + // Set the image transform. + QTransform transform; + int y = screenSize.height() - (rect.bottom() + 1); + transform.translate(rect.x() + 0.5f, y + 0.5f); + d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform); + + // Enable opacity for image drawing if necessary. + if (opacity < 255) { + if (opacity != d->paintOpacity) { + VGfloat values[4]; + values[0] = 1.0f; + values[1] = 1.0f; + values[2] = 1.0f; + values[3] = ((VGfloat)opacity) / 255.0f; + vgSetParameterfv(d->opacityPaint, VG_PAINT_COLOR, 4, values); + d->paintOpacity = values[3]; + } + if (d->fillPaint != d->opacityPaint) { + vgSetPaint(d->opacityPaint, VG_FILL_PATH); + d->fillPaint = d->opacityPaint; + } + d->setImageMode(VG_DRAW_IMAGE_MULTIPLY); + } else { + d->setImageMode(VG_DRAW_IMAGE_NORMAL); + } + + // Draw the child image. + vgDrawImage(child); + + // Destroy the child image. + if(child != image) + vgDestroyImage(child); + } +} + +static void fillBackgroundRect(const QRect& rect, QVGPaintEnginePrivate *d) +{ + VGfloat coords[8]; + coords[0] = rect.x(); + coords[1] = rect.y(); + coords[2] = rect.x() + rect.width(); + coords[3] = coords[1]; + coords[4] = coords[2]; + coords[5] = rect.y() + rect.height(); + coords[6] = coords[0]; + coords[7] = coords[5]; +#if !defined(QVG_NO_MODIFY_PATH) + vgModifyPathCoords(d->rectPath, 0, 4, coords); + vgDrawPath(d->rectPath, VG_FILL_PATH); +#else + Q_UNUSED(d); + VGPath rectPath = vgCreatePath + (VG_PATH_FORMAT_STANDARD, + VG_PATH_DATATYPE_F, + 1.0f, // scale + 0.0f, // bias + 5, // segmentCapacityHint + 8, // coordCapacityHint + VG_PATH_CAPABILITY_ALL); + static VGubyte const segments[5] = { + VG_MOVE_TO_ABS, + VG_LINE_TO_ABS, + VG_LINE_TO_ABS, + VG_LINE_TO_ABS, + VG_CLOSE_PATH + }; + vgAppendPathData(rectPath, 5, segments, coords); + vgDrawPath(rectPath, VG_FILL_PATH); + vgDestroyPath(rectPath); +#endif +} + +void QVGCompositionHelper::fillBackground + (const QRegion& region, const QBrush& brush) +{ + // Set the path transform to the default viewport transformation. + VGfloat devh = screenSize.height() - 1; + QTransform viewport(1.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, + 0.5f, devh + 0.5f, 1.0f); + d->setTransform(VG_MATRIX_PATH_USER_TO_SURFACE, viewport); + + // Set the brush to use to fill the background. + d->ensureBrush(brush); + d->setFillRule(VG_EVEN_ODD); + + if (region.numRects() == 1) { + fillBackgroundRect(region.boundingRect(), d); + } else { + const QVector rects = region.rects(); + for (int i = 0; i < rects.size(); ++i) + fillBackgroundRect(rects.at(i), d); + } + + // We will need to reset the path transform during the next paint. + d->pathTransformSet = false; +} + +void QVGCompositionHelper::drawCursorImage + (const QImage& image, const QPoint& offset) +{ + QImage img = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); + + VGImage vgImg = vgCreateImage + (VG_sARGB_8888_PRE, img.width(), img.height(), + VG_IMAGE_QUALITY_FASTER); + vgImageSubData + (vgImg, img.bits() + img.bytesPerLine() * (img.height() - 1), + -(img.bytesPerLine()), VG_sARGB_8888_PRE, 0, 0, + img.width(), img.height()); + + QTransform transform; + int y = screenSize.height() - (offset.y() + img.height()); + transform.translate(offset.x() + 0.5f, y + 0.5f); + d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform); + + d->setImageMode(VG_DRAW_IMAGE_NORMAL); + vgDrawImage(vgImg); + + vgDestroyImage(vgImg); +} + +void QVGCompositionHelper::drawCursorPixmap + (const QPixmap& pixmap, const QPoint& offset) +{ + QPixmapData *pd = pixmap.pixmapData(); + if (pd->classId() == QPixmapData::OpenVGClass) { + QVGPixmapData *vgpd = static_cast(pd); + if (vgpd->isValid()) { + VGfloat devh = screenSize.height() - 1; + QTransform transform(1.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, + 0.5f, devh + 0.5f, 1.0f); + transform.translate(offset.x(), offset.y()); + d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform); + + d->setImageMode(VG_DRAW_IMAGE_NORMAL); + vgDrawImage(vgpd->toVGImage()); + return; + } + } + + drawCursorImage(pixmap.toImage(), offset); +} + +void QVGCompositionHelper::setScissor(const QRegion& region) +{ + QVector rects = region.rects(); + int count = rects.count(); + if (count > d->maxScissorRects) + count = d->maxScissorRects; + QVarLengthArray params(count * 4); + int height = screenSize.height(); + for (int i = 0; i < count; ++i) { + params[i * 4 + 0] = rects[i].x(); + params[i * 4 + 1] = height - rects[i].y() - rects[i].height(); + params[i * 4 + 2] = rects[i].width(); + params[i * 4 + 3] = rects[i].height(); + } + + vgSetiv(VG_SCISSOR_RECTS, count * 4, params.data()); + vgSeti(VG_SCISSORING, VG_TRUE); + d->scissorActive = true; + d->scissorRegion = region; +} + +void QVGCompositionHelper::clearScissor() +{ + if (d->scissorActive) { + vgSeti(VG_SCISSORING, VG_FALSE); + d->scissorActive = false; + } +} + +#endif // !QVG_NO_SINGLE_CONTEXT && !QT_NO_EGL + +VGImageFormat qt_vg_image_to_vg_format(QImage::Format format) +{ + switch (format) { + case QImage::Format_MonoLSB: + return VG_BW_1; + case QImage::Format_ARGB32_Premultiplied: + return VG_sARGB_8888_PRE; + case QImage::Format_RGB32: + return VG_sXRGB_8888; + case QImage::Format_ARGB32: + return VG_sARGB_8888; + case QImage::Format_RGB16: + return VG_sRGB_565; + case QImage::Format_ARGB4444_Premultiplied: + return VG_sARGB_4444; + default: break; + } + return VG_sARGB_8888; // XXX +} + +QT_END_NAMESPACE + +#include "qpaintengine_vg.moc" diff --git a/src/openvg/qpaintengine_vg_p.h b/src/openvg/qpaintengine_vg_p.h new file mode 100644 index 0000000..a390c80 --- /dev/null +++ b/src/openvg/qpaintengine_vg_p.h @@ -0,0 +1,163 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPAINTENGINE_VG_P_H +#define QPAINTENGINE_VG_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QVGPaintEnginePrivate; +class QPixmapData; +class QVGEGLWindowSurfacePrivate; + +class Q_OPENVG_EXPORT QVGPainterState : public QPainterState +{ +public: + QVGPainterState(QVGPainterState& other); + QVGPainterState(); + ~QVGPainterState(); + + bool isNew; + QRegion clipRegion; + QPaintEngine::DirtyFlags savedDirty; +}; + +class Q_OPENVG_EXPORT QVGPaintEngine : public QPaintEngineEx +{ + Q_DECLARE_PRIVATE(QVGPaintEngine) +public: + QVGPaintEngine(); + ~QVGPaintEngine(); + + Type type() const { return OpenVG; } + + QPainterState *createState(QPainterState *orig) const; + + bool begin(QPaintDevice *pdev); + bool end(); + + void draw(const QVectorPath &path); + void fill(const QVectorPath &path, const QBrush &brush); + void stroke(const QVectorPath &path, const QPen &pen); + + void clip(const QVectorPath &path, Qt::ClipOperation op); + void clip(const QRect &rect, Qt::ClipOperation op); + void clip(const QRegion ®ion, Qt::ClipOperation op); + void clip(const QPainterPath &path, Qt::ClipOperation op); + + void clipEnabledChanged(); + void penChanged(); + void brushChanged(); + void brushOriginChanged(); + void opacityChanged(); + void compositionModeChanged(); + void renderHintsChanged(); + void transformChanged(); + + void fillRect(const QRectF &rect, const QBrush &brush); + void fillRect(const QRectF &rect, const QColor &color); + + void drawRects(const QRect *rects, int rectCount); + void drawRects(const QRectF *rects, int rectCount); + + void drawLines(const QLine *lines, int lineCount); + void drawLines(const QLineF *lines, int lineCount); + + void drawEllipse(const QRectF &r); + void drawEllipse(const QRect &r); + + void drawPath(const QPainterPath &path); + + void drawPoints(const QPointF *points, int pointCount); + void drawPoints(const QPoint *points, int pointCount); + + void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode); + void drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode); + + void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr); + void drawPixmap(const QPointF &pos, const QPixmap &pm); + + void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, + Qt::ImageConversionFlags flags = Qt::AutoColor); + void drawImage(const QPointF &pos, const QImage &image); + + void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s); + + void drawTextItem(const QPointF &p, const QTextItem &textItem); + + void setState(QPainterState *s); + QVGPainterState *state() { return static_cast(QPaintEngineEx::state()); } + const QVGPainterState *state() const { return static_cast(QPaintEngineEx::state()); } + + void updateState(const QPaintEngineState &state); + + QPixmapFilter *createPixmapFilter(int type) const; + + QVGPaintEnginePrivate *vgPrivate() { Q_D(QVGPaintEngine); return d; } + +protected: + QVGPaintEngine(QVGPaintEnginePrivate &data); + +private: + void restoreState(QPaintEngine::DirtyFlags dirty); + void updateScissor(); + QRegion defaultClipRegion(); + bool isDefaultClipRegion(const QRegion& region); + bool clearRect(const QRectF &rect, const QColor &color); +}; + + +QT_END_NAMESPACE + +#endif diff --git a/src/openvg/qpixmapdata_vg.cpp b/src/openvg/qpixmapdata_vg.cpp new file mode 100644 index 0000000..90fd9a5 --- /dev/null +++ b/src/openvg/qpixmapdata_vg.cpp @@ -0,0 +1,344 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qpixmapdata_vg_p.h" +#include "qpaintengine_vg_p.h" +#include +#include "qvg_p.h" + +QT_BEGIN_NAMESPACE + +static int qt_vg_pixmap_serial = 0; + +QVGPixmapData::QVGPixmapData(PixelType type) + : QPixmapData(type, OpenVGClass) +{ + Q_ASSERT(type == QPixmapData::PixmapType); + vgImage = VG_INVALID_HANDLE; + vgImageOpacity = VG_INVALID_HANDLE; + cachedOpacity = 1.0f; + recreate = true; +#if !defined(QT_NO_EGL) + context = 0; +#endif + setSerialNumber(++qt_vg_pixmap_serial); +} + +QVGPixmapData::~QVGPixmapData() +{ + if (vgImage != VG_INVALID_HANDLE) { + // We need to have a context current to destroy the image. +#if !defined(QT_NO_EGL) + if (context->isCurrent()) { + vgDestroyImage(vgImage); + if (vgImageOpacity != VG_INVALID_HANDLE) + vgDestroyImage(vgImageOpacity); + } else { + // We don't currently have a widget surface active, but we + // need a surface to make the context current. So use the + // shared pbuffer surface instead. + qt_vg_make_current(context, qt_vg_shared_surface()); + vgDestroyImage(vgImage); + if (vgImageOpacity != VG_INVALID_HANDLE) + vgDestroyImage(vgImageOpacity); + qt_vg_done_current(context); + context->setSurface(EGL_NO_SURFACE); + } +#else + vgDestroyImage(vgImage); + if (vgImageOpacity != VG_INVALID_HANDLE) + vgDestroyImage(vgImageOpacity); + } else { +#endif + } +#if !defined(QT_NO_EGL) + if (context) + qt_vg_destroy_context(context); +#endif +} + +bool QVGPixmapData::isValid() const +{ + return (w > 0 && h > 0); +} + +void QVGPixmapData::resize(int wid, int ht) +{ + if (w == wid && h == ht) + return; + + w = wid; + h = ht; + d = 32; // We always use ARGB_Premultiplied for VG pixmaps. + is_null = (w <= 0 || h <= 0); + source = QImage(); + recreate = true; + + setSerialNumber(++qt_vg_pixmap_serial); +} + +void QVGPixmapData::fromImage + (const QImage &image, Qt::ImageConversionFlags flags) +{ + if (image.size() == QSize(w, h)) + setSerialNumber(++qt_vg_pixmap_serial); + else + resize(image.width(), image.height()); + source = image.convertToFormat(sourceFormat(), flags); + recreate = true; +} + +void QVGPixmapData::fill(const QColor &color) +{ + if (!isValid()) + return; + + if (source.isNull()) + source = QImage(w, h, sourceFormat()); + + if (source.depth() == 1) { + // Pick the best approximate color in the image's colortable. + int gray = qGray(color.rgba()); + if (qAbs(qGray(source.color(0)) - gray) < qAbs(qGray(source.color(1)) - gray)) + source.fill(0); + else + source.fill(1); + } else { + source.fill(PREMUL(color.rgba())); + } + + // Re-upload the image to VG the next time toVGImage() is called. + recreate = true; +} + +bool QVGPixmapData::hasAlphaChannel() const +{ + if (!source.isNull()) + return source.hasAlphaChannel(); + else + return isValid(); +} + +void QVGPixmapData::setAlphaChannel(const QPixmap &alphaChannel) +{ + forceToImage(); + source.setAlphaChannel(alphaChannel.toImage()); +} + +QImage QVGPixmapData::toImage() const +{ + if (!isValid()) + return QImage(); + + if (source.isNull()) { + source = QImage(w, h, sourceFormat()); + recreate = true; + } + + return source; +} + +QImage *QVGPixmapData::buffer() +{ + forceToImage(); + return &source; +} + +QPaintEngine* QVGPixmapData::paintEngine() const +{ + // If the application wants to paint into the QPixmap, we first + // force it to QImage format and then paint into that. + // This is simpler than juggling multiple VG contexts. + const_cast(this)->forceToImage(); + return source.paintEngine(); +} + +VGImage QVGPixmapData::toVGImage() +{ + if (!isValid()) + return VG_INVALID_HANDLE; + +#if !defined(QT_NO_EGL) + // Increase the reference count on the shared context. + if (!context) + context = qt_vg_create_context(0); +#endif + + if (recreate) { + if (vgImage != VG_INVALID_HANDLE) { + vgDestroyImage(vgImage); + vgImage = VG_INVALID_HANDLE; + } + if (vgImageOpacity != VG_INVALID_HANDLE) { + vgDestroyImage(vgImageOpacity); + vgImageOpacity = VG_INVALID_HANDLE; + } + } + + if (vgImage == VG_INVALID_HANDLE) { + vgImage = vgCreateImage + (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER); + } + + if (!source.isNull() && recreate) { + vgImageSubData + (vgImage, + source.bits(), source.bytesPerLine(), + VG_sARGB_8888_PRE, 0, 0, w, h); + } + + recreate = false; + + return vgImage; +} + +VGImage QVGPixmapData::toVGImage(qreal opacity) +{ +#if !defined(QT_SHIVAVG) + if (!isValid()) + return VG_INVALID_HANDLE; + +#if !defined(QT_NO_EGL) + // Increase the reference count on the shared context. + if (!context) + context = qt_vg_create_context(0); +#endif + + if (recreate) { + if (vgImage != VG_INVALID_HANDLE) { + vgDestroyImage(vgImage); + vgImage = VG_INVALID_HANDLE; + } + if (vgImageOpacity != VG_INVALID_HANDLE) { + vgDestroyImage(vgImageOpacity); + vgImageOpacity = VG_INVALID_HANDLE; + } + } + + if (vgImage == VG_INVALID_HANDLE) { + vgImage = vgCreateImage + (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER); + } + + if (!source.isNull() && recreate) { + vgImageSubData + (vgImage, + source.bits(), source.bytesPerLine(), + VG_sARGB_8888_PRE, 0, 0, w, h); + } + + recreate = false; + + if (opacity == 1.0f) + return vgImage; + + if (vgImageOpacity == VG_INVALID_HANDLE || cachedOpacity != opacity) { + if (vgImageOpacity == VG_INVALID_HANDLE) { + vgImageOpacity = vgCreateImage + (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER); + } + VGfloat matrix[20] = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, opacity, + 0.0f, 0.0f, 0.0f, 0.0f + }; + vgColorMatrix(vgImageOpacity, vgImage, matrix); + cachedOpacity = opacity; + } + + return vgImageOpacity; +#else + // vgColorMatrix() doesn't work with ShivaVG, so ignore the opacity. + Q_UNUSED(opacity); + return toVGImage(); +#endif +} + +extern int qt_defaultDpiX(); +extern int qt_defaultDpiY(); + +int QVGPixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const +{ + switch (metric) { + case QPaintDevice::PdmWidth: + return w; + case QPaintDevice::PdmHeight: + return h; + case QPaintDevice::PdmNumColors: + return 0; + case QPaintDevice::PdmDepth: + return d; + case QPaintDevice::PdmWidthMM: + return qRound(w * 25.4 / qt_defaultDpiX()); + case QPaintDevice::PdmHeightMM: + return qRound(h * 25.4 / qt_defaultDpiY()); + case QPaintDevice::PdmDpiX: + case QPaintDevice::PdmPhysicalDpiX: + return qt_defaultDpiX(); + case QPaintDevice::PdmDpiY: + case QPaintDevice::PdmPhysicalDpiY: + return qt_defaultDpiY(); + default: + qWarning("QVGPixmapData::metric(): Invalid metric"); + return 0; + } +} + +// Force the pixmap data to be in QImage format. +void QVGPixmapData::forceToImage() +{ + if (!isValid()) + return; + + if (source.isNull()) + source = QImage(w, h, sourceFormat()); + + recreate = true; +} + +QImage::Format QVGPixmapData::sourceFormat() const +{ + return QImage::Format_ARGB32_Premultiplied; +} + +QT_END_NAMESPACE diff --git a/src/openvg/qpixmapdata_vg_p.h b/src/openvg/qpixmapdata_vg_p.h new file mode 100644 index 0000000..bb019be --- /dev/null +++ b/src/openvg/qpixmapdata_vg_p.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPIXMAPDATA_VG_P_H +#define QPIXMAPDATA_VG_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include "qvg_p.h" +#if !defined(QT_NO_EGL) +#include +#endif + +QT_BEGIN_NAMESPACE + +class QEglContext; + +class Q_OPENVG_EXPORT QVGPixmapData : public QPixmapData +{ +public: + QVGPixmapData(PixelType type); + ~QVGPixmapData(); + + // Is this pixmap valid (i.e. non-zero in size)? + bool isValid() const; + + void resize(int width, int height); + void fromImage(const QImage &image, Qt::ImageConversionFlags flags); + + void fill(const QColor &color); + bool hasAlphaChannel() const; + void setAlphaChannel(const QPixmap &alphaChannel); + QImage toImage() const; + QImage *buffer(); + QPaintEngine* paintEngine() const; + + // Return the VGImage form of this pixmap, creating it if necessary. + // This assumes that there is a VG context current. + VGImage toVGImage(); + + // Return the VGImage form for a specific opacity setting. + VGImage toVGImage(qreal opacity); + + QSize size() const { return QSize(w, h); } + +protected: + int metric(QPaintDevice::PaintDeviceMetric metric) const; + +private: + VGImage vgImage; + VGImage vgImageOpacity; + qreal cachedOpacity; + mutable QImage source; + mutable bool recreate; +#if !defined(QT_NO_EGL) + mutable QEglContext *context; +#endif + + void forceToImage(); + QImage::Format sourceFormat() const; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/openvg/qpixmapfilter_vg.cpp b/src/openvg/qpixmapfilter_vg.cpp new file mode 100644 index 0000000..ff8604b --- /dev/null +++ b/src/openvg/qpixmapfilter_vg.cpp @@ -0,0 +1,340 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qpixmapfilter_vg_p.h" +#include +#include + +QT_BEGIN_NAMESPACE + +#if !defined(QT_SHIVAVG) + +QVGPixmapConvolutionFilter::QVGPixmapConvolutionFilter() + : QPixmapConvolutionFilter() +{ +} + +QVGPixmapConvolutionFilter::~QVGPixmapConvolutionFilter() +{ +} + +extern void qt_vg_drawVGImage + (QPainter *painter, const QPointF& pos, VGImage vgImg); + +void QVGPixmapConvolutionFilter::draw + (QPainter *painter, const QPointF &dest, + const QPixmap &src, const QRectF &srcRect) const +{ + if (src.pixmapData()->classId() != QPixmapData::OpenVGClass) { + // The pixmap data is not an instance of QVGPixmapData, so fall + // back to the default convolution filter implementation. + QPixmapConvolutionFilter::draw(painter, dest, src, srcRect); + return; + } + + QVGPixmapData *pd = static_cast(src.pixmapData()); + + VGImage srcImage = pd->toVGImage(); + if (srcImage == VG_INVALID_HANDLE) + return; + + QSize size = pd->size(); + VGImage dstImage = vgCreateImage + (VG_sARGB_8888_PRE, size.width(), size.height(), + VG_IMAGE_QUALITY_FASTER); + if (dstImage == VG_INVALID_HANDLE) + return; + + int kernelWidth = rows(); + int kernelHeight = columns(); + const qreal *kern = convolutionKernel(); + QVarLengthArray kernel; + for (int i = 0; i < kernelWidth; ++i) { + for (int j = 0; j < kernelHeight; ++j) { + kernel.append((VGshort)(kern[j * kernelWidth + i] * 1024.0f)); + } + } + + VGfloat values[4]; + values[0] = 0.0f; + values[1] = 0.0f; + values[2] = 0.0f; + values[3] = 0.0f; + vgSetfv(VG_TILE_FILL_COLOR, 4, values); + + vgConvolve(dstImage, srcImage, + kernelWidth, kernelHeight, 0, 0, + kernel.constData(), 1.0f / 1024.0f, 0.0f, + VG_TILE_FILL); + + VGImage child = VG_INVALID_HANDLE; + + if (srcRect.isNull() || + (srcRect.topLeft().isNull() && srcRect.size() == size)) { + child = dstImage; + } else { + QRect src = srcRect.toRect(); + child = vgChildImage(dstImage, src.x(), src.y(), src.width(), src.height()); + } + + qt_vg_drawVGImage(painter, dest, child); + + if(child != dstImage) + vgDestroyImage(child); + vgDestroyImage(dstImage); +} + +QVGPixmapColorizeFilter::QVGPixmapColorizeFilter() + : QPixmapColorizeFilter(), + firstTime(true) +{ +} + +QVGPixmapColorizeFilter::~QVGPixmapColorizeFilter() +{ +} + +void QVGPixmapColorizeFilter::draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const +{ + if (src.pixmapData()->classId() != QPixmapData::OpenVGClass) { + // The pixmap data is not an instance of QVGPixmapData, so fall + // back to the default convolution filter implementation. + QPixmapColorizeFilter::draw(painter, dest, src, srcRect); + return; + } + + QVGPixmapData *pd = static_cast(src.pixmapData()); + + VGImage srcImage = pd->toVGImage(); + if (srcImage == VG_INVALID_HANDLE) + return; + + QSize size = pd->size(); + VGImage dstImage = vgCreateImage + (VG_sARGB_8888_PRE, size.width(), size.height(), + VG_IMAGE_QUALITY_FASTER); + if (dstImage == VG_INVALID_HANDLE) + return; + + // Recompute the color matrix if the color has changed. + QColor c = color(); + if (c != prevColor || firstTime) { + prevColor = c; + + // Determine the weights for the matrix from the color. + VGfloat weights[3]; + VGfloat invweights[3]; + VGfloat alpha = c.alphaF(); + weights[0] = c.redF() * alpha; + weights[1] = c.greenF() * alpha; + weights[2] = c.blueF() * alpha; + invweights[0] = 1.0f - weights[0]; + invweights[1] = 1.0f - weights[1]; + invweights[2] = 1.0f - weights[2]; + + // Grayscale weights. + static const VGfloat redGray = 11.0f / 32.0f; + static const VGfloat greenGray = 16.0f / 32.0f; + static const VGfloat blueGray = 1.0f - (redGray + greenGray); + + matrix[0][0] = redGray * invweights[0]; + matrix[0][1] = redGray * invweights[1]; + matrix[0][2] = redGray * invweights[2]; + matrix[0][3] = 0.0f; + matrix[1][0] = greenGray * invweights[0]; + matrix[1][1] = greenGray * invweights[1]; + matrix[1][2] = greenGray * invweights[2]; + matrix[1][3] = 0.0f; + matrix[2][0] = blueGray * invweights[0]; + matrix[2][1] = blueGray * invweights[1]; + matrix[2][2] = blueGray * invweights[2]; + matrix[2][3] = 0.0f; + matrix[3][0] = 0.0f; + matrix[3][1] = 0.0f; + matrix[3][2] = 0.0f; + matrix[3][3] = 1.0f; + matrix[4][0] = weights[0]; + matrix[4][1] = weights[1]; + matrix[4][2] = weights[2]; + matrix[4][3] = 0.0f; + } + + firstTime = false; + + vgColorMatrix(dstImage, srcImage, matrix[0]); + + VGImage child = VG_INVALID_HANDLE; + + if (srcRect.isNull() || + (srcRect.topLeft().isNull() && srcRect.size() == size)) { + child = dstImage; + } else { + QRect src = srcRect.toRect(); + child = vgChildImage(dstImage, src.x(), src.y(), src.width(), src.height()); + } + + qt_vg_drawVGImage(painter, dest, child); + + if(child != dstImage) + vgDestroyImage(child); + vgDestroyImage(dstImage); +} + +QVGPixmapDropShadowFilter::QVGPixmapDropShadowFilter() + : QPixmapDropShadowFilter(), + prevRadius(0.0f), + kernelSize(0), + firstTime(true) +{ +} + +QVGPixmapDropShadowFilter::~QVGPixmapDropShadowFilter() +{ +} + +void QVGPixmapDropShadowFilter::draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const +{ + if (src.pixmapData()->classId() != QPixmapData::OpenVGClass) { + // The pixmap data is not an instance of QVGPixmapData, so fall + // back to the default drop shadow filter implementation. + QPixmapDropShadowFilter::draw(painter, dest, src, srcRect); + return; + } + + QVGPixmapData *pd = static_cast(src.pixmapData()); + + VGImage srcImage = pd->toVGImage(); + if (srcImage == VG_INVALID_HANDLE) + return; + + QSize size = pd->size(); + VGImage tmpImage = vgCreateImage + (VG_sARGB_8888_PRE, size.width(), size.height(), + VG_IMAGE_QUALITY_FASTER); + if (tmpImage == VG_INVALID_HANDLE) + return; + + VGImage dstImage = vgCreateImage + (VG_sARGB_8888_PRE, size.width(), size.height(), + VG_IMAGE_QUALITY_FASTER); + if (dstImage == VG_INVALID_HANDLE) { + vgDestroyImage(tmpImage); + return; + } + + // Recompute the color matrix if the color has changed. + QColor c = color(); + if (c != prevColor || firstTime) { + prevColor = c; + + matrix[0][0] = 0.0f; + matrix[0][1] = 0.0f; + matrix[0][2] = 0.0f; + matrix[0][3] = 0.0f; + matrix[1][0] = 0.0f; + matrix[1][1] = 0.0f; + matrix[1][2] = 0.0f; + matrix[1][3] = 0.0f; + matrix[2][0] = 0.0f; + matrix[2][1] = 0.0f; + matrix[2][2] = 0.0f; + matrix[2][3] = 0.0f; + matrix[3][0] = c.redF(); + matrix[3][1] = c.greenF(); + matrix[3][2] = c.blueF(); + matrix[3][3] = c.alphaF(); + matrix[4][0] = 0.0f; + matrix[4][1] = 0.0f; + matrix[4][2] = 0.0f; + matrix[4][3] = 0.0f; + } + + // Blacken the source image. + vgColorMatrix(tmpImage, srcImage, matrix[0]); + + // Recompute the convolution kernel if the blur radius has changed. + qreal radius = blurRadius(); + if (radius != prevRadius || firstTime) { + prevRadius = radius; + int dim = 2 * qRound(radius) + 1; + int size = dim * dim; + VGshort f = VGshort(1024.0f / size); + kernel.resize(size); + for (int i = 0; i < size; ++i) + kernel[i] = f; + kernelSize = dim; + } + + // Apply the convolution filter using the kernel. + VGfloat values[4]; + values[0] = 0.0f; + values[1] = 0.0f; + values[2] = 0.0f; + values[3] = 0.0f; + vgSetfv(VG_TILE_FILL_COLOR, 4, values); + vgConvolve(dstImage, tmpImage, + kernelSize, kernelSize, 0, 0, + kernel.constData(), 1.0f / 1024.0f, 0.0f, + VG_TILE_FILL); + + firstTime = false; + + VGImage child = VG_INVALID_HANDLE; + + if (srcRect.isNull() || + (srcRect.topLeft().isNull() && srcRect.size() == size)) { + child = dstImage; + } else { + QRect src = srcRect.toRect(); + child = vgChildImage(dstImage, src.x(), src.y(), src.width(), src.height()); + } + + qt_vg_drawVGImage(painter, dest + offset(), child); + + if(child != dstImage) + vgDestroyImage(child); + vgDestroyImage(tmpImage); + vgDestroyImage(dstImage); +} + +#endif + +QT_END_NAMESPACE diff --git a/src/openvg/qpixmapfilter_vg_p.h b/src/openvg/qpixmapfilter_vg_p.h new file mode 100644 index 0000000..412fb55 --- /dev/null +++ b/src/openvg/qpixmapfilter_vg_p.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPIXMAPFILTER_VG_P_H +#define QPIXMAPFILTER_VG_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qpixmapdata_vg_p.h" +#include +#include + +QT_BEGIN_NAMESPACE + +#if !defined(QT_SHIVAVG) + +class Q_OPENVG_EXPORT QVGPixmapConvolutionFilter : public QPixmapConvolutionFilter +{ +public: + QVGPixmapConvolutionFilter(); + ~QVGPixmapConvolutionFilter(); + + void draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const; +}; + +class Q_OPENVG_EXPORT QVGPixmapColorizeFilter : public QPixmapColorizeFilter +{ +public: + QVGPixmapColorizeFilter(); + ~QVGPixmapColorizeFilter(); + + void draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const; + +private: + mutable VGfloat matrix[5][4]; + mutable QColor prevColor; + mutable bool firstTime; +}; + +class Q_OPENVG_EXPORT QVGPixmapDropShadowFilter : public QPixmapDropShadowFilter +{ +public: + QVGPixmapDropShadowFilter(); + ~QVGPixmapDropShadowFilter(); + + void draw(QPainter *p, const QPointF &pos, const QPixmap &px, const QRectF &src) const; + +private: + mutable VGfloat matrix[5][4]; + mutable QColor prevColor; + mutable qreal prevRadius; + mutable int kernelSize; + mutable bool firstTime; + mutable QVarLengthArray kernel; +}; + +#endif + +QT_END_NAMESPACE + +#endif diff --git a/src/openvg/qvg.h b/src/openvg/qvg.h new file mode 100644 index 0000000..8da6159 --- /dev/null +++ b/src/openvg/qvg.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVG_H +#define QVG_H + +#include + +// Include the OpenVG headers for use in applications that +// issue raw OpenVG function calls. +#if defined(QT_LOWER_CASE_VG_INCLUDES) +#include +#else +#include +#endif + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(OpenVG) + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/openvg/qvg_p.h b/src/openvg/qvg_p.h new file mode 100644 index 0000000..7ac2430 --- /dev/null +++ b/src/openvg/qvg_p.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVG_P_H +#define QVG_P_H + +#include "qvg.h" + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +#if !defined(QT_NO_EGL) +#include +#endif + +QT_BEGIN_NAMESPACE + +class QVGPaintEngine; + +#if !defined(QT_NO_EGL) + +class QEglContext; + +// Create an EGL context, but don't bind it to a surface. If single-context +// mode is enabled, this will return the previously-created context. +Q_OPENVG_EXPORT QEglContext *qt_vg_create_context(QPaintDevice *device); + +// Destroy an EGL context that was created by qt_vg_create_context(). +// If single-context mode is enabled, this will decrease the reference count. +Q_OPENVG_EXPORT void qt_vg_destroy_context(QEglContext *context); + +// Return the shared pbuffer surface that can be made current to +// destroy VGImage objects when there is no other surface available. +Q_OPENVG_EXPORT EGLSurface qt_vg_shared_surface(void); + +// Make a context current with a specific surface. +Q_OPENVG_EXPORT void qt_vg_make_current(QEglContext *context, EGLSurface surface); + +// Make a context uncurrent. +Q_OPENVG_EXPORT void qt_vg_done_current(QEglContext *context, bool force = false); + +// Destroy a surface that was previously associated with a context. +Q_OPENVG_EXPORT void qt_vg_destroy_surface(QEglContext *context, EGLSurface surface); + +// Convert the configuration format in a context to a VG or QImage format. +Q_OPENVG_EXPORT VGImageFormat qt_vg_config_to_vg_format(QEglContext *context); +Q_OPENVG_EXPORT QImage::Format qt_vg_config_to_image_format(QEglContext *context); + +#endif + +// Create a paint engine. Returns the common engine in single-context mode. +Q_OPENVG_EXPORT QVGPaintEngine *qt_vg_create_paint_engine(void); + +// Destroy a paint engine. Does nothing in single-context mode. +Q_OPENVG_EXPORT void qt_vg_destroy_paint_engine(QVGPaintEngine *engine); + +// Convert between QImage and VGImage format values. +Q_OPENVG_EXPORT VGImageFormat qt_vg_image_to_vg_format(QImage::Format format); + +QT_END_NAMESPACE + +#endif diff --git a/src/openvg/qvgcompositionhelper_p.h b/src/openvg/qvgcompositionhelper_p.h new file mode 100644 index 0000000..cdf1be9 --- /dev/null +++ b/src/openvg/qvgcompositionhelper_p.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVGCOMPOSITIONHELPER_H +#define QVGCOMPOSITIONHELPER_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qwindowsurface_vgegl_p.h" + +QT_BEGIN_NAMESPACE + +#if !defined(QVG_NO_SINGLE_CONTEXT) && !defined(QT_NO_EGL) + +class QVGPaintEnginePrivate; +class QVGEGLWindowSurfacePrivate; + +class Q_OPENVG_EXPORT QVGCompositionHelper +{ +public: + QVGCompositionHelper(); + virtual ~QVGCompositionHelper(); + + void startCompositing(const QSize& screenSize); + void endCompositing(); + + void blitWindow(QVGEGLWindowSurfacePrivate *surface, const QRect& rect, + const QPoint& topLeft, int opacity); + void fillBackground(const QRegion& region, const QBrush& brush); + void drawCursorImage(const QImage& image, const QPoint& offset); + void drawCursorPixmap(const QPixmap& pixmap, const QPoint& offset); + void setScissor(const QRegion& region); + void clearScissor(); + +private: + QVGPaintEnginePrivate *d; + QSize screenSize; +}; + +#endif + +QT_END_NAMESPACE + +#endif diff --git a/src/openvg/qwindowsurface_vg.cpp b/src/openvg/qwindowsurface_vg.cpp new file mode 100644 index 0000000..c77aa93 --- /dev/null +++ b/src/openvg/qwindowsurface_vg.cpp @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowsurface_vg_p.h" +#include "qwindowsurface_vgegl_p.h" +#include "qpaintengine_vg_p.h" +#include "qpixmapdata_vg_p.h" +#include "qvg_p.h" + +#if !defined(QT_NO_EGL) + +#include + +QT_BEGIN_NAMESPACE + +QVGWindowSurface::QVGWindowSurface(QWidget *window) + : QWindowSurface(window) +{ + d_ptr = QVGEGLWindowSurfacePrivate::create + (QVGEGLWindowSurfacePrivate::WindowSurface, this); +} + +QVGWindowSurface::QVGWindowSurface + (QWidget *window, QVGEGLWindowSurfacePrivate *d) + : QWindowSurface(window), d_ptr(d) +{ +} + +QVGWindowSurface::~QVGWindowSurface() +{ + delete d_ptr; +} + +QPaintDevice *QVGWindowSurface::paintDevice() +{ + d_ptr->beginPaint(window()); + return this; +} + +void QVGWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) +{ + Q_UNUSED(offset); + QWidget *parent = widget->internalWinId() ? widget : widget->nativeParentWidget(); + d_ptr->endPaint(parent, region); +} + +void QVGWindowSurface::setGeometry(const QRect &rect) +{ + QWindowSurface::setGeometry(rect); + d_ptr->ensureContext(window()); +} + +bool QVGWindowSurface::scroll(const QRegion &area, int dx, int dy) +{ + return QWindowSurface::scroll(area, dx, dy); +} + +void QVGWindowSurface::beginPaint(const QRegion ®ion) +{ + // Nothing to do here. + Q_UNUSED(region); +} + +void QVGWindowSurface::endPaint(const QRegion ®ion) +{ + // Nothing to do here. + Q_UNUSED(region); +} + +QPaintEngine *QVGWindowSurface::paintEngine() const +{ + return d_ptr->paintEngine(); +} + +int QVGWindowSurface::metric(PaintDeviceMetric met) const +{ + return window()->metric(met); +} + +QT_END_NAMESPACE + +#endif diff --git a/src/openvg/qwindowsurface_vg_p.h b/src/openvg/qwindowsurface_vg_p.h new file mode 100644 index 0000000..e2ee583 --- /dev/null +++ b/src/openvg/qwindowsurface_vg_p.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSURFACE_VG_P_H +#define QWINDOWSURFACE_VG_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +#if !defined(QT_NO_EGL) + +class QVGEGLWindowSurfacePrivate; + +class Q_OPENVG_EXPORT QVGWindowSurface : public QWindowSurface, public QPaintDevice +{ +public: + QVGWindowSurface(QWidget *window); + QVGWindowSurface(QWidget *window, QVGEGLWindowSurfacePrivate *d); + ~QVGWindowSurface(); + + QPaintDevice *paintDevice(); + void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); + void setGeometry(const QRect &rect); + bool scroll(const QRegion &area, int dx, int dy); + + void beginPaint(const QRegion ®ion); + void endPaint(const QRegion ®ion); + + QPaintEngine *paintEngine() const; + +protected: + int metric(PaintDeviceMetric metric) const; + +private: + QVGEGLWindowSurfacePrivate *d_ptr; +}; + +#endif + +QT_END_NAMESPACE + +#endif // QWINDOWSURFACE_VG_P_H diff --git a/src/openvg/qwindowsurface_vgegl.cpp b/src/openvg/qwindowsurface_vgegl.cpp new file mode 100644 index 0000000..11c7021 --- /dev/null +++ b/src/openvg/qwindowsurface_vgegl.cpp @@ -0,0 +1,751 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowsurface_vgegl_p.h" +#include "qpaintengine_vg_p.h" +#include "qpixmapdata_vg_p.h" +#include "qvg_p.h" + +#if !defined(QT_NO_EGL) + +QT_BEGIN_NAMESPACE + +// Turn off "direct to window" rendering if EGL cannot support it. +#if !defined(EGL_RENDER_BUFFER) || !defined(EGL_SINGLE_BUFFER) +#if defined(QVG_DIRECT_TO_WINDOW) +#undef QVG_DIRECT_TO_WINDOW +#endif +#endif + +// Determine if preserved window contents should be used. +#if !defined(EGL_SWAP_BEHAVIOR) || !defined(EGL_BUFFER_PRESERVED) +#if !defined(QVG_NO_PRESERVED_SWAP) +#define QVG_NO_PRESERVED_SWAP 1 +#endif +#endif + +VGImageFormat qt_vg_config_to_vg_format(QEglContext *context) +{ + return qt_vg_image_to_vg_format + (qt_vg_config_to_image_format(context)); +} + +QImage::Format qt_vg_config_to_image_format(QEglContext *context) +{ + EGLint red = 0; + EGLint green = 0; + EGLint blue = 0; + EGLint alpha = 0; + context->configAttrib(EGL_RED_SIZE, &red); + context->configAttrib(EGL_GREEN_SIZE, &green); + context->configAttrib(EGL_BLUE_SIZE, &blue); + context->configAttrib(EGL_ALPHA_SIZE, &alpha); + QImage::Format argbFormat; +#ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT + EGLint type = 0; + context->configAttrib(EGL_SURFACE_TYPE, &type); + if ((type & EGL_VG_ALPHA_FORMAT_PRE_BIT) != 0) + argbFormat = QImage::Format_ARGB32_Premultiplied; + else + argbFormat = QImage::Format_ARGB32; +#else + argbFormat = QImage::Format_ARGB32; +#endif + if (red == 8 && green == 8 && blue == 8 && alpha == 8) + return argbFormat; + else if (red == 8 && green == 8 && blue == 8 && alpha == 0) + return QImage::Format_RGB32; + else if (red == 5 && green == 6 && blue == 5 && alpha == 0) + return QImage::Format_RGB16; + else if (red == 4 && green == 4 && blue == 4 && alpha == 4) + return QImage::Format_ARGB4444_Premultiplied; + else + return argbFormat; // XXX +} + +static void copySubImage(QImage *image, VGImage vgImage, const QRect& rect) +{ + vgGetImageSubData + (vgImage, + image->bits() + rect.bottom() * image->bytesPerLine() + + rect.x() * (image->depth() / 8), + -(image->bytesPerLine()), + qt_vg_image_to_vg_format(image->format()), + rect.x(), (image->height() - 1) - rect.bottom(), + rect.width(), rect.height()); +} + +#if !defined(QVG_NO_SINGLE_CONTEXT) + +class QVGSharedContext +{ +public: + QVGSharedContext(); + ~QVGSharedContext(); + + QEglContext *context; + int refCount; + QVGPaintEngine *engine; + EGLSurface surface; + EGLSurface lastSurface; +}; + +QVGSharedContext::QVGSharedContext() + : context(0) + , refCount(0) + , engine(0) + , surface(EGL_NO_SURFACE) + , lastSurface(EGL_NO_SURFACE) +{ +} + +QVGSharedContext::~QVGSharedContext() +{ + if (context) + qt_vg_make_current(context, qt_vg_shared_surface()); + delete engine; + if (context) + qt_vg_done_current(context, true); + if (surface != EGL_NO_SURFACE) + qt_vg_destroy_surface(context, surface); + delete context; +} + +Q_GLOBAL_STATIC(QVGSharedContext, sharedContext); + +QVGPaintEngine *qt_vg_create_paint_engine(void) +{ + QVGSharedContext *shared = sharedContext(); + if (!shared->engine) + shared->engine = new QVGPaintEngine(); + return shared->engine; +} + +void qt_vg_destroy_paint_engine(QVGPaintEngine *engine) +{ + Q_UNUSED(engine); +} + +#else + +QVGPaintEngine *qt_vg_create_paint_engine(void) +{ + return new QVGPaintEngine(); +} + +void qt_vg_destroy_paint_engine(QVGPaintEngine *engine) +{ + delete engine; +} + +#endif + +#ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT + +static bool isPremultipliedContext(const QEglContext *context) +{ + EGLint value = 0; + if (context->configAttrib(EGL_SURFACE_TYPE, &value)) + return (value & EGL_VG_ALPHA_FORMAT_PRE_BIT) != 0; + else + return false; +} + +#endif + +static QEglContext *createContext(QPaintDevice *device) +{ + QEglContext *context; + + // Create the context object and open the display. + context = new QEglContext(); + context->setApi(QEgl::OpenVG); + if (!context->openDisplay(device)) { + delete context; + return 0; + } + + // Choose an appropriate configuration for rendering into the device. + QEglProperties configProps; + configProps.setPaintDeviceFormat(device); + int redSize = configProps.value(EGL_RED_SIZE); + if (redSize == EGL_DONT_CARE || redSize == 0) + configProps.setPixelFormat(QImage::Format_ARGB32); // XXX +#ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT + configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT | + EGL_VG_ALPHA_FORMAT_PRE_BIT); + configProps.setRenderableType(QEgl::OpenVG); + if (!context->chooseConfig(configProps)) { + // Try again without the "pre" bit. + configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT); + if (!context->chooseConfig(configProps)) { + delete context; + return 0; + } + } +#else + configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT); + configProps.setRenderableType(QEgl::OpenVG); + if (!context->chooseConfig(configProps)) { + delete context; + return 0; + } +#endif + + // Construct a new EGL context for the selected configuration. + if (!context->createContext()) { + delete context; + return 0; + } + + return context; +} + +#if !defined(QVG_NO_SINGLE_CONTEXT) + +QEglContext *qt_vg_create_context(QPaintDevice *device) +{ + QVGSharedContext *shared = sharedContext(); + if (shared->context) { + ++(shared->refCount); + return shared->context; + } else { + shared->context = createContext(device); + shared->refCount = 1; + return shared->context; + } +} + +void qt_vg_destroy_context(QEglContext *context) +{ + QVGSharedContext *shared = sharedContext(); + if (shared->context != context) { + // This is not the shared context. Shouldn't happen! + delete context; + } else if (--(shared->refCount) <= 0) { + qt_vg_make_current(shared->context, qt_vg_shared_surface()); + delete shared->engine; + shared->engine = 0; + qt_vg_done_current(shared->context, true); + if (shared->surface != EGL_NO_SURFACE) { + qt_vg_destroy_surface(shared->context, shared->surface); + shared->surface = EGL_NO_SURFACE; + } + delete shared->context; + shared->context = 0; + } +} + +EGLSurface qt_vg_shared_surface(void) +{ + QVGSharedContext *shared = sharedContext(); + if (shared->surface == EGL_NO_SURFACE) { + EGLint attribs[7]; + attribs[0] = EGL_WIDTH; + attribs[1] = 16; + attribs[2] = EGL_HEIGHT; + attribs[3] = 16; +#ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT + if (isPremultipliedContext(shared->context)) { + attribs[4] = EGL_VG_ALPHA_FORMAT; + attribs[5] = EGL_VG_ALPHA_FORMAT_PRE; + attribs[6] = EGL_NONE; + } else +#endif + { + attribs[4] = EGL_NONE; + } + shared->surface = eglCreatePbufferSurface + (shared->context->display(), shared->context->config(), attribs); + } + return shared->surface; +} + +void qt_vg_make_current(QEglContext *context, EGLSurface surface) +{ + // Bail out if the context and surface are already current. + if (context->isCurrent() && context->surface() == surface) + return; + + // Are we setting the surface to the same as the last elided doneCurrent()? + QVGSharedContext *shared = sharedContext(); + if (context->isCurrent() && shared->lastSurface == surface) { + shared->lastSurface = EGL_NO_SURFACE; + context->setSurface(surface); + return; + } + + // Switch to the new context and surface. + shared->lastSurface = EGL_NO_SURFACE; + context->setSurface(surface); + context->makeCurrent(); +} + +void qt_vg_done_current(QEglContext *context, bool force) +{ + QVGSharedContext *shared = sharedContext(); + if (force) { + context->doneCurrent(); + shared->lastSurface = EGL_NO_SURFACE; + } else { + // Keep the context current for now just in case we immediately + // reuse the same surface for the next frame. + shared->lastSurface = context->surface(); + } +} + +void qt_vg_destroy_surface(QEglContext *context, EGLSurface surface) +{ + QVGSharedContext *shared = sharedContext(); + if (shared->lastSurface == surface) { + shared->lastSurface = EGL_NO_SURFACE; + context->doneCurrent(); + } + context->setSurface(surface); + context->destroySurface(); +} + +#else + +QEglContext *qt_vg_create_context(QPaintDevice *device) +{ + return createContext(device); +} + +void qt_vg_destroy_context(QEglContext *context) +{ + delete context; +} + +EGLSurface qt_vg_shared_surface(void) +{ + return EGL_NO_SURFACE; +} + +void qt_vg_make_current(QEglContext *context, EGLSurface surface) +{ + context->setSurface(surface); + context->makeCurrent(); +} + +void qt_vg_done_current(QEglContext *context, bool force) +{ + Q_UNUSED(force); + context->doneCurrent(); +} + +void qt_vg_destroy_surface(QEglContext *context, EGLSurface surface) +{ + context->setSurface(surface); + context->destroySurface(); +} + +#endif + +QVGEGLWindowSurfacePrivate::QVGEGLWindowSurfacePrivate(QWindowSurface *win) +{ + winSurface = win; + engine = 0; +} + +QVGEGLWindowSurfacePrivate::~QVGEGLWindowSurfacePrivate() +{ + // Destroy the paint engine if it hasn't been destroyed already. + destroyPaintEngine(); +} + +QVGEGLWindowSurfacePrivate *QVGEGLWindowSurfacePrivate::create + (SurfaceType type, QWindowSurface *win) +{ +#if defined(QVG_VGIMAGE_BACKBUFFERS) + if (type == VGImageSurface) + return new QVGEGLWindowSurfaceVGImage(win); + else if (type == QImageSurface) + return new QVGEGLWindowSurfaceQImage(win); +#endif + if (type == WindowSurface) + return new QVGEGLWindowSurfaceDirect(win); + return 0; +} + +QVGPaintEngine *QVGEGLWindowSurfacePrivate::paintEngine() +{ + if (!engine) + engine = qt_vg_create_paint_engine(); + return engine; +} + +VGImage QVGEGLWindowSurfacePrivate::surfaceImage() const +{ + return VG_INVALID_HANDLE; +} + +void QVGEGLWindowSurfacePrivate::destroyPaintEngine() +{ + if (engine) { + qt_vg_destroy_paint_engine(engine); + engine = 0; + } +} + +QSize QVGEGLWindowSurfacePrivate::windowSurfaceSize(QWidget *widget) const +{ + Q_UNUSED(widget); + + QRect rect = winSurface->geometry(); + QSize newSize = rect.size(); + +#if defined(Q_WS_QWS) + // Account for the widget mask, if any. + if (widget && !widget->mask().isEmpty()) { + const QRegion region = widget->mask() + & rect.translated(-widget->geometry().topLeft()); + newSize = region.boundingRect().size(); + } +#endif + + return newSize; +} + +#if defined(QVG_VGIMAGE_BACKBUFFERS) + +QVGEGLWindowSurfaceVGImage::QVGEGLWindowSurfaceVGImage(QWindowSurface *win) + : QVGEGLWindowSurfacePrivate(win) + , context(0) + , backBuffer(VG_INVALID_HANDLE) + , backBufferSurface(EGL_NO_SURFACE) + , recreateBackBuffer(false) + , isPaintingActive(false) + , windowSurface(EGL_NO_SURFACE) +{ +} + +QVGEGLWindowSurfaceVGImage::~QVGEGLWindowSurfaceVGImage() +{ + destroyPaintEngine(); + if (context) { + if (backBufferSurface != EGL_NO_SURFACE) { + // We need a current context to be able to destroy the image. + // We use the shared surface because the native window handle + // associated with "windowSurface" may have been destroyed already. + qt_vg_make_current(context, qt_vg_shared_surface()); + qt_vg_destroy_surface(context, backBufferSurface); + vgDestroyImage(backBuffer); + qt_vg_done_current(context, true); + } + if (windowSurface != EGL_NO_SURFACE) + qt_vg_destroy_surface(context, windowSurface); + qt_vg_destroy_context(context); + } +} + +QEglContext *QVGEGLWindowSurfaceVGImage::ensureContext(QWidget *widget) +{ + QSize newSize = windowSurfaceSize(widget); + if (context && size != newSize) { + // The surface size has changed, so we need to recreate + // the back buffer. Keep the same context and paint engine. + size = newSize; + if (isPaintingActive) + qt_vg_done_current(context, true); + isPaintingActive = false; + recreateBackBuffer = true; + } + if (!context) { + // Create a new EGL context. We create the surface in beginPaint(). + size = newSize; + context = qt_vg_create_context(widget); + if (!context) + return 0; + isPaintingActive = false; + } + return context; +} + +void QVGEGLWindowSurfaceVGImage::beginPaint(QWidget *widget) +{ + QEglContext *context = ensureContext(widget); + if (context) { + if (recreateBackBuffer || backBufferSurface == EGL_NO_SURFACE) { + // Create a VGImage object to act as the back buffer + // for this window. We have to create the VGImage with a + // current context, so activate the main surface for the window. + qt_vg_make_current(context, mainSurface()); + recreateBackBuffer = false; + if (backBufferSurface != EGL_NO_SURFACE) { + eglDestroySurface(context->display(), backBufferSurface); + backBufferSurface = EGL_NO_SURFACE; + } + if (backBuffer != VG_INVALID_HANDLE) { + vgDestroyImage(backBuffer); + } + VGImageFormat format = qt_vg_config_to_vg_format(context); + backBuffer = vgCreateImage + (format, size.width(), size.height(), + VG_IMAGE_QUALITY_FASTER); + if (backBuffer != VG_INVALID_HANDLE) { + // Create an EGL surface for rendering into the VGImage. + backBufferSurface = eglCreatePbufferFromClientBuffer + (context->display(), EGL_OPENVG_IMAGE, + (EGLClientBuffer)(backBuffer), + context->config(), NULL); + if (backBufferSurface == EGL_NO_SURFACE) { + vgDestroyImage(backBuffer); + backBuffer = VG_INVALID_HANDLE; + } + } + } + if (backBufferSurface != EGL_NO_SURFACE) + qt_vg_make_current(context, backBufferSurface); + else + qt_vg_make_current(context, mainSurface()); + isPaintingActive = true; + } +} + +void QVGEGLWindowSurfaceVGImage::endPaint + (QWidget *widget, const QRegion& region, QImage *image) +{ + Q_UNUSED(region); + Q_UNUSED(image); + QEglContext *context = ensureContext(widget); + if (context) { + if (backBufferSurface != EGL_NO_SURFACE) { + if (isPaintingActive) + vgFlush(); + qt_vg_done_current(context); + } + context->setSurface(EGL_NO_SURFACE); + isPaintingActive = false; + } +} + +VGImage QVGEGLWindowSurfaceVGImage::surfaceImage() const +{ + return backBuffer; +} + +EGLSurface QVGEGLWindowSurfaceVGImage::mainSurface() const +{ + if (windowSurface != EGL_NO_SURFACE) + return windowSurface; + else + return qt_vg_shared_surface(); +} + +QVGEGLWindowSurfaceQImage::QVGEGLWindowSurfaceQImage(QWindowSurface *win) + : QVGEGLWindowSurfaceVGImage(win) +{ +} + +QVGEGLWindowSurfaceQImage::~QVGEGLWindowSurfaceQImage() +{ +} + +void QVGEGLWindowSurfaceQImage::endPaint + (QWidget *widget, const QRegion& region, QImage *image) +{ + QEglContext *context = ensureContext(widget); + if (context) { + if (backBufferSurface != EGL_NO_SURFACE) { + if (isPaintingActive) + vgFlush(); + qt_vg_make_current(context, mainSurface()); + QRegion rgn = region.intersected + (QRect(0, 0, image->width(), image->height())); + if (rgn.numRects() == 1) { + copySubImage(image, backBuffer, rgn.boundingRect()); + } else { + QVector rects = rgn.rects(); + for (int index = 0; index < rects.size(); ++index) + copySubImage(image, backBuffer, rects[index]); + } + qt_vg_done_current(context); + } + context->setSurface(EGL_NO_SURFACE); + isPaintingActive = false; + } +} + +#endif // QVG_VGIMAGE_BACKBUFFERS + +QVGEGLWindowSurfaceDirect::QVGEGLWindowSurfaceDirect(QWindowSurface *win) + : QVGEGLWindowSurfacePrivate(win) + , context(0) + , isPaintingActive(false) + , needToSwap(false) + , windowSurface(EGL_NO_SURFACE) +{ +} + +QVGEGLWindowSurfaceDirect::~QVGEGLWindowSurfaceDirect() +{ +} + +QEglContext *QVGEGLWindowSurfaceDirect::ensureContext(QWidget *widget) +{ + QSize newSize = windowSurfaceSize(widget); + QEglProperties surfaceProps; + +#if defined(QVG_RECREATE_ON_SIZE_CHANGE) +#if !defined(QVG_NO_SINGLE_CONTEXT) + if (context && size != newSize) { + // The surface size has changed, so we need to recreate it. + // We can keep the same context and paint engine. + size = newSize; + if (isPaintingActive) + qt_vg_done_current(context, true); + context->setSurface(windowSurface); + context->destroySurface(); +#if defined(EGL_VG_ALPHA_FORMAT_PRE_BIT) + if (isPremultipliedContext(context)) { + surfaceProps.setValue + (EGL_VG_ALPHA_FORMAT, EGL_VG_ALPHA_FORMAT_PRE); + } else { + surfaceProps.removeValue(EGL_VG_ALPHA_FORMAT); + } +#endif + context->createSurface(widget, &surfaceProps); + windowSurface = context->surface(); + context->setSurface(EGL_NO_SURFACE); + isPaintingActive = false; + } +#else + if (context && size != newSize) { + // The surface size has changed, so we need to recreate + // the EGL context for the widget. We also need to recreate + // the surface's paint engine if context sharing is not + // enabled because we cannot reuse the existing paint objects + // in the new context. + qt_vg_destroy_paint_engine(engine); + engine = 0; + context->setSurface(windowSurface); + context->destroySurface(); + qt_vg_destroy_context(context); + context = 0; + windowSurface = EGL_NO_SURFACE; + } +#endif +#endif + if (!context) { + // Create a new EGL context and bind it to the widget surface. + size = newSize; + context = qt_vg_create_context(widget); + if (!context) + return 0; + // We want a direct to window rendering surface if possible. +#if defined(QVG_DIRECT_TO_WINDOW) + surfaceProps.setValue(EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER); +#endif +#if defined(EGL_VG_ALPHA_FORMAT_PRE_BIT) + if (isPremultipliedContext(context)) { + surfaceProps.setValue + (EGL_VG_ALPHA_FORMAT, EGL_VG_ALPHA_FORMAT_PRE); + } else { + surfaceProps.removeValue(EGL_VG_ALPHA_FORMAT); + } +#endif + if (!context->createSurface(widget, &surfaceProps)) { + qt_vg_destroy_context(context); + context = 0; + return 0; + } + needToSwap = true; +#if defined(QVG_DIRECT_TO_WINDOW) + // Did we get a direct to window rendering surface? + EGLint buffer = 0; + if (eglQueryContext(context->display(), context->context(), + EGL_RENDER_BUFFER, &buffer) && + buffer == EGL_SINGLE_BUFFER) { + needToSwap = false; + } +#endif +#if !defined(QVG_NO_PRESERVED_SWAP) + // Try to force the surface back buffer to preserve its contents. + if (needToSwap) { + eglGetError(); // Clear error state first. + eglSurfaceAttrib(context->display(), context->surface(), + EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED); + if (eglGetError() != EGL_SUCCESS) { + qWarning("QVG: could not enable preserved swap"); + } + } +#endif + windowSurface = context->surface(); + context->setSurface(EGL_NO_SURFACE); + isPaintingActive = false; + } + return context; +} + +void QVGEGLWindowSurfaceDirect::beginPaint(QWidget *widget) +{ + QEglContext *context = ensureContext(widget); + if (context) { + qt_vg_make_current(context, windowSurface); + isPaintingActive = true; + } +} + +void QVGEGLWindowSurfaceDirect::endPaint + (QWidget *widget, const QRegion& region, QImage *image) +{ + Q_UNUSED(region); + Q_UNUSED(image); + QEglContext *context = ensureContext(widget); + if (context) { + if (needToSwap) { + if (!isPaintingActive) + qt_vg_make_current(context, windowSurface); + context->swapBuffers(); + qt_vg_done_current(context); + } else if (isPaintingActive) { + vgFlush(); + qt_vg_done_current(context); + } + context->setSurface(EGL_NO_SURFACE); + isPaintingActive = false; + } +} + +QT_END_NAMESPACE + +#endif diff --git a/src/openvg/qwindowsurface_vgegl_p.h b/src/openvg/qwindowsurface_vgegl_p.h new file mode 100644 index 0000000..aa23772 --- /dev/null +++ b/src/openvg/qwindowsurface_vgegl_p.h @@ -0,0 +1,163 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSURFACE_VGEGL_P_H +#define QWINDOWSURFACE_VGEGL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the QLibrary class. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include +#include "qvg_p.h" + +#if !defined(QT_NO_EGL) + +#include + +QT_BEGIN_NAMESPACE + +class QWindowSurface; + +class Q_OPENVG_EXPORT QVGEGLWindowSurfacePrivate +{ +public: + QVGEGLWindowSurfacePrivate(QWindowSurface *win); + virtual ~QVGEGLWindowSurfacePrivate(); + + enum SurfaceType + { + WindowSurface, + VGImageSurface, + QImageSurface + }; + + static QVGEGLWindowSurfacePrivate *create + (SurfaceType type, QWindowSurface *win); + + QVGPaintEngine *paintEngine(); + virtual QEglContext *ensureContext(QWidget *widget) = 0; + virtual void beginPaint(QWidget *widget) = 0; + virtual void endPaint + (QWidget *widget, const QRegion& region, QImage *image = 0) = 0; + virtual VGImage surfaceImage() const; + virtual QSize surfaceSize() const = 0; + +private: + QVGPaintEngine *engine; + +protected: + QWindowSurface *winSurface; + + void destroyPaintEngine(); + QSize windowSurfaceSize(QWidget *widget) const; +}; + +#if defined(EGL_OPENVG_IMAGE) && !defined(QVG_NO_SINGLE_CONTEXT) + +#define QVG_VGIMAGE_BACKBUFFERS 1 + +class Q_OPENVG_EXPORT QVGEGLWindowSurfaceVGImage : public QVGEGLWindowSurfacePrivate +{ +public: + QVGEGLWindowSurfaceVGImage(QWindowSurface *win); + virtual ~QVGEGLWindowSurfaceVGImage(); + + QEglContext *ensureContext(QWidget *widget); + void beginPaint(QWidget *widget); + void endPaint(QWidget *widget, const QRegion& region, QImage *image); + VGImage surfaceImage() const; + QSize surfaceSize() const { return size; } + +protected: + QEglContext *context; + VGImage backBuffer; + EGLSurface backBufferSurface; + bool recreateBackBuffer; + bool isPaintingActive; + QSize size; + EGLSurface windowSurface; + + EGLSurface mainSurface() const; +}; + +class Q_OPENVG_EXPORT QVGEGLWindowSurfaceQImage : public QVGEGLWindowSurfaceVGImage +{ +public: + QVGEGLWindowSurfaceQImage(QWindowSurface *win); + virtual ~QVGEGLWindowSurfaceQImage(); + + void endPaint(QWidget *widget, const QRegion& region, QImage *image); +}; + +#endif // EGL_OPENVG_IMAGE + +class Q_OPENVG_EXPORT QVGEGLWindowSurfaceDirect : public QVGEGLWindowSurfacePrivate +{ +public: + QVGEGLWindowSurfaceDirect(QWindowSurface *win); + virtual ~QVGEGLWindowSurfaceDirect(); + + QEglContext *ensureContext(QWidget *widget); + void beginPaint(QWidget *widget); + void endPaint(QWidget *widget, const QRegion& region, QImage *image); + QSize surfaceSize() const { return size; } + +protected: + QEglContext *context; + QSize size; + bool isPaintingActive; + bool needToSwap; + EGLSurface windowSurface; +}; + +QT_END_NAMESPACE + +#endif // !QT_NO_EGL + +#endif // QWINDOWSURFACE_VGEGL_P_H diff --git a/src/plugins/graphicssystems/graphicssystems.pro b/src/plugins/graphicssystems/graphicssystems.pro index b8216ff..bfdec6a 100644 --- a/src/plugins/graphicssystems/graphicssystems.pro +++ b/src/plugins/graphicssystems/graphicssystems.pro @@ -1,2 +1,8 @@ TEMPLATE = subdirs contains(QT_CONFIG, opengl):SUBDIRS += opengl +contains(QT_CONFIG, openvg):contains(QT_CONFIG, egl):SUBDIRS += openvg + +contains(QT_CONFIG, shivavg) { + # Only works under X11 at present + !win32:!embedded:!mac:SUBDIRS += shivavg +} diff --git a/src/plugins/graphicssystems/openvg/main.cpp b/src/plugins/graphicssystems/openvg/main.cpp new file mode 100644 index 0000000..265ccd3 --- /dev/null +++ b/src/plugins/graphicssystems/openvg/main.cpp @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "qgraphicssystem_vg_p.h" + +QT_BEGIN_NAMESPACE + +class QVGGraphicsSystemPlugin : public QGraphicsSystemPlugin +{ +public: + QStringList keys() const; + QGraphicsSystem *create(const QString&); +}; + +QStringList QVGGraphicsSystemPlugin::keys() const +{ + QStringList list; + list << "OpenVG"; + return list; +} + +QGraphicsSystem* QVGGraphicsSystemPlugin::create(const QString& system) +{ + if (system.toLower() == "openvg") + return new QVGGraphicsSystem; + + return 0; +} + +Q_EXPORT_PLUGIN2(openvg, QVGGraphicsSystemPlugin) + +QT_END_NAMESPACE diff --git a/src/plugins/graphicssystems/openvg/openvg.pro b/src/plugins/graphicssystems/openvg/openvg.pro new file mode 100644 index 0000000..0abbfbd --- /dev/null +++ b/src/plugins/graphicssystems/openvg/openvg.pro @@ -0,0 +1,20 @@ +TARGET = qvggraphicssystem +include(../../qpluginbase.pri) + +QT += openvg + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/graphicssystems + +SOURCES = main.cpp qgraphicssystem_vg.cpp +HEADERS = qgraphicssystem_vg_p.h + +target.path += $$[QT_INSTALL_PLUGINS]/graphicssystems +INSTALLS += target + +!isEmpty(QMAKE_INCDIR_OPENVG): INCLUDEPATH += $$QMAKE_INCDIR_OPENVG +!isEmpty(QMAKE_LIBDIR_OPENVG): LIBS += -L$$QMAKE_LIBDIR_OPENVG +!isEmpty(QMAKE_LIBS_OPENVG): LIBS += $$QMAKE_LIBS_OPENVG + +!isEmpty(QMAKE_INCDIR_EGL): INCLUDEPATH += $$QMAKE_INCDIR_EGL +!isEmpty(QMAKE_LIBDIR_EGL): LIBS += -L$$QMAKE_LIBDIR_EGL +!isEmpty(QMAKE_LIBS_EGL): LIBS += $$QMAKE_LIBS_EGL diff --git a/src/plugins/graphicssystems/openvg/qgraphicssystem_vg.cpp b/src/plugins/graphicssystems/openvg/qgraphicssystem_vg.cpp new file mode 100644 index 0000000..d975ad7 --- /dev/null +++ b/src/plugins/graphicssystems/openvg/qgraphicssystem_vg.cpp @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgraphicssystem_vg_p.h" +#include +#include + +QT_BEGIN_NAMESPACE + +QVGGraphicsSystem::QVGGraphicsSystem() +{ +} + +QPixmapData *QVGGraphicsSystem::createPixmapData(QPixmapData::PixelType type) const +{ +#if !defined(QVG_NO_SINGLE_CONTEXT) && !defined(QVG_NO_PIXMAP_DATA) + // Pixmaps can use QVGPixmapData; bitmaps must use raster. + if (type == QPixmapData::PixmapType) + return new QVGPixmapData(type); + else + return new QRasterPixmapData(type); +#else + return new QRasterPixmapData(type); +#endif +} + +QWindowSurface *QVGGraphicsSystem::createWindowSurface(QWidget *widget) const +{ + return new QVGWindowSurface(widget); +} + +QT_END_NAMESPACE diff --git a/src/plugins/graphicssystems/openvg/qgraphicssystem_vg_p.h b/src/plugins/graphicssystems/openvg/qgraphicssystem_vg_p.h new file mode 100644 index 0000000..368f48d --- /dev/null +++ b/src/plugins/graphicssystems/openvg/qgraphicssystem_vg_p.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGRAPHICSSYSTEM_VG_P_H +#define QGRAPHICSSYSTEM_VG_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QVGGraphicsSystem : public QGraphicsSystem +{ +public: + QVGGraphicsSystem(); + + QPixmapData *createPixmapData(QPixmapData::PixelType type) const; + QWindowSurface *createWindowSurface(QWidget *widget) const; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/graphicssystems/shivavg/README b/src/plugins/graphicssystems/shivavg/README new file mode 100644 index 0000000..15ee710 --- /dev/null +++ b/src/plugins/graphicssystems/shivavg/README @@ -0,0 +1,8 @@ + +This graphics system uses ShivaVG (http://sourceforge.net/projects/shivavg) +to perform OpenVG rendering on X11 systems. The graphics system name for +the "-graphicssystem" command-line option is "ShivaVG". + +ShivaVG support is experimental, mostly to demonstrate how to integrate +non-EGL OpenVG engines into the system. It will probably not produce +good output. diff --git a/src/plugins/graphicssystems/shivavg/main.cpp b/src/plugins/graphicssystems/shivavg/main.cpp new file mode 100644 index 0000000..037bfb2 --- /dev/null +++ b/src/plugins/graphicssystems/shivavg/main.cpp @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "shivavggraphicssystem.h" + +QT_BEGIN_NAMESPACE + +class ShivaVGGraphicsSystemPlugin : public QGraphicsSystemPlugin +{ +public: + QStringList keys() const; + QGraphicsSystem *create(const QString&); +}; + +QStringList ShivaVGGraphicsSystemPlugin::keys() const +{ + QStringList list; + list << "ShivaVG"; + return list; +} + +QGraphicsSystem* ShivaVGGraphicsSystemPlugin::create(const QString& system) +{ + if (system.toLower() == "shivavg") + return new ShivaVGGraphicsSystem; + + return 0; +} + +Q_EXPORT_PLUGIN2(shivavg, ShivaVGGraphicsSystemPlugin) + +QT_END_NAMESPACE diff --git a/src/plugins/graphicssystems/shivavg/shivavg.pro b/src/plugins/graphicssystems/shivavg/shivavg.pro new file mode 100644 index 0000000..68345af --- /dev/null +++ b/src/plugins/graphicssystems/shivavg/shivavg.pro @@ -0,0 +1,16 @@ +TARGET = qshivavggraphicssystem +include(../../qpluginbase.pri) + +QT += openvg + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/graphicssystems + +SOURCES = main.cpp shivavggraphicssystem.cpp shivavgwindowsurface.cpp +HEADERS = shivavggraphicssystem.h shivavgwindowsurface.h + +target.path += $$[QT_INSTALL_PLUGINS]/graphicssystems +INSTALLS += target + +!isEmpty(QMAKE_INCDIR_OPENVG): INCLUDEPATH += $$QMAKE_INCDIR_OPENVG +!isEmpty(QMAKE_LIBDIR_OPENVG): LIBS += -L$$QMAKE_LIBDIR_OPENVG +!isEmpty(QMAKE_LIBS_OPENVG): LIBS += $$QMAKE_LIBS_OPENVG diff --git a/src/plugins/graphicssystems/shivavg/shivavggraphicssystem.cpp b/src/plugins/graphicssystems/shivavg/shivavggraphicssystem.cpp new file mode 100644 index 0000000..fb60a42 --- /dev/null +++ b/src/plugins/graphicssystems/shivavg/shivavggraphicssystem.cpp @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "shivavggraphicssystem.h" +#include "shivavgwindowsurface.h" +#include + +QT_BEGIN_NAMESPACE + +ShivaVGGraphicsSystem::ShivaVGGraphicsSystem() +{ +} + +QPixmapData *ShivaVGGraphicsSystem::createPixmapData(QPixmapData::PixelType type) const +{ + return new QRasterPixmapData(type); +} + +QWindowSurface *ShivaVGGraphicsSystem::createWindowSurface(QWidget *widget) const +{ + return new ShivaVGWindowSurface(widget); +} + +QT_END_NAMESPACE diff --git a/src/plugins/graphicssystems/shivavg/shivavggraphicssystem.h b/src/plugins/graphicssystems/shivavg/shivavggraphicssystem.h new file mode 100644 index 0000000..1c9ec70 --- /dev/null +++ b/src/plugins/graphicssystems/shivavg/shivavggraphicssystem.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SHIVAVGGRAPHICSSYSTEM_H +#define SHIVAVGGRAPHICSSYSTEM_H + +#include + +QT_BEGIN_NAMESPACE + +class ShivaVGGraphicsSystem : public QGraphicsSystem +{ +public: + ShivaVGGraphicsSystem(); + + QPixmapData *createPixmapData(QPixmapData::PixelType type) const; + QWindowSurface *createWindowSurface(QWidget *widget) const; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/graphicssystems/shivavg/shivavgwindowsurface.cpp b/src/plugins/graphicssystems/shivavg/shivavgwindowsurface.cpp new file mode 100644 index 0000000..bf1f942 --- /dev/null +++ b/src/plugins/graphicssystems/shivavg/shivavgwindowsurface.cpp @@ -0,0 +1,370 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#define GL_GLEXT_PROTOTYPES +#include "shivavgwindowsurface.h" +#include +#if defined(Q_WS_X11) +#include "private/qt_x11_p.h" +#include "qx11info_x11.h" +#include + +extern QX11Info *qt_x11Info(const QPaintDevice *pd); +#endif + +// Define this to use framebuffer objects. +//#define QVG_USE_FBO 1 + +#include + +QT_BEGIN_NAMESPACE + +class QShivaContext +{ +public: + QShivaContext(); + ~QShivaContext(); + + bool makeCurrent(ShivaVGWindowSurfacePrivate *surface); + void doneCurrent(); + + bool initialized; + QSize currentSize; + ShivaVGWindowSurfacePrivate *currentSurface; +}; + +Q_GLOBAL_STATIC(QShivaContext, shivaContext); + +class ShivaVGWindowSurfacePrivate +{ +public: + ShivaVGWindowSurfacePrivate() + : isCurrent(false) + , needsResize(true) + , engine(0) +#if defined(QVG_USE_FBO) + , fbo(0) + , texture(0) +#endif +#if defined(Q_WS_X11) + , drawable(0) + , context(0) +#endif + { + } + ~ShivaVGWindowSurfacePrivate(); + + void ensureContext(QWidget *widget); + + QSize size; + bool isCurrent; + bool needsResize; + QVGPaintEngine *engine; +#if defined(QVG_USE_FBO) + GLuint fbo; + GLuint texture; +#endif +#if defined(Q_WS_X11) + GLXDrawable drawable; + GLXContext context; +#endif +}; + +QShivaContext::QShivaContext() + : initialized(false) + , currentSurface(0) +{ +} + +QShivaContext::~QShivaContext() +{ + if (initialized) + vgDestroyContextSH(); +} + +bool QShivaContext::makeCurrent(ShivaVGWindowSurfacePrivate *surface) +{ + if (currentSurface) + currentSurface->isCurrent = false; + surface->isCurrent = true; + currentSurface = surface; + currentSize = surface->size; +#if defined(Q_WS_X11) + glXMakeCurrent(X11->display, surface->drawable, surface->context); +#endif + if (!initialized) { + if (!vgCreateContextSH(currentSize.width(), currentSize.height())) { + qWarning("vgCreateContextSH(%d, %d): could not create context", currentSize.width(), currentSize.height()); + return false; + } + initialized = true; + } else { + vgResizeSurfaceSH(currentSize.width(), currentSize.height()); + } +#if defined(QVG_USE_FBO) + if (surface->fbo) + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, surface->fbo); + else + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); +#endif + return true; +} + +void QShivaContext::doneCurrent() +{ + if (currentSurface) { + currentSurface->isCurrent = false; + currentSurface = 0; + } +#if defined(Q_WS_X11) + glXMakeCurrent(X11->display, 0, 0); +#endif +} + +ShivaVGWindowSurfacePrivate::~ShivaVGWindowSurfacePrivate() +{ +#if defined(QVG_USE_FBO) + if (fbo) { + glDeleteTextures(1, &texture); + glDeleteFramebuffersEXT(1, &fbo); + } +#endif +} + +void ShivaVGWindowSurfacePrivate::ensureContext(QWidget *widget) +{ +#if defined(Q_WS_X11) + Window win = widget->winId(); + if (win != drawable) { + if (context) + glXDestroyContext(X11->display, context); + drawable = win; + } + if (context == 0) { + const QX11Info *xinfo = qt_x11Info(widget); + int spec[64]; + int i = 0; + spec[i++] = GLX_DOUBLEBUFFER; + spec[i++] = GLX_DEPTH_SIZE; + spec[i++] = 1; + spec[i++] = GLX_STENCIL_SIZE; + spec[i++] = 1; + spec[i++] = GLX_RGBA; + spec[i++] = GLX_RED_SIZE; + spec[i++] = 1; + spec[i++] = GLX_GREEN_SIZE; + spec[i++] = 1; + spec[i++] = GLX_BLUE_SIZE; + spec[i++] = 1; + spec[i++] = GLX_SAMPLE_BUFFERS_ARB; + spec[i++] = 1; + spec[i++] = GLX_SAMPLES_ARB; + spec[i++] = 4; + spec[i] = XNone; + XVisualInfo *visual = glXChooseVisual + (xinfo->display(), xinfo->screen(), spec); + context = glXCreateContext(X11->display, visual, 0, True); + if (!context) + qWarning("glXCreateContext: could not create GL context for VG rendering"); + } +#else + Q_UNUSED(widget); +#endif +#if defined(QVG_USE_FBO) + if (needsResize && fbo) { +#if defined(Q_WS_X11) + glXMakeCurrent(X11->display, drawable, context); +#endif + glDeleteTextures(1, &texture); + glDeleteFramebuffersEXT(1, &fbo); +#if defined(Q_WS_X11) + glXMakeCurrent(X11->display, 0, 0); +#endif + fbo = 0; + texture = 0; + } + if (!fbo) { +#if defined(Q_WS_X11) + glXMakeCurrent(X11->display, drawable, context); +#endif + glGenFramebuffersEXT(1, &fbo); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); + + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, size.width(), size.height(), 0, + GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glFramebufferTexture2DEXT + (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, + texture, 0); + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); +#if defined(Q_WS_X11) + glXMakeCurrent(X11->display, 0, 0); +#endif + } +#endif + needsResize = false; +} + +ShivaVGWindowSurface::ShivaVGWindowSurface(QWidget *window) + : QWindowSurface(window), d_ptr(new ShivaVGWindowSurfacePrivate) +{ +} + +ShivaVGWindowSurface::~ShivaVGWindowSurface() +{ + if (d_ptr->isCurrent) { + shivaContext()->doneCurrent(); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + } +#if defined(Q_WS_X11) + if (d_ptr->context) + glXDestroyContext(X11->display, d_ptr->context); +#endif + delete d_ptr; +} + +QPaintDevice *ShivaVGWindowSurface::paintDevice() +{ + d_ptr->ensureContext(window()); + shivaContext()->makeCurrent(d_ptr); + glClearDepth(0.0f); + glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + return this; +} + +void ShivaVGWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) +{ + Q_UNUSED(region); + Q_UNUSED(offset); + QWidget *parent = widget->internalWinId() ? widget : widget->nativeParentWidget(); + d_ptr->ensureContext(parent); + QShivaContext *context = shivaContext(); + if (!d_ptr->isCurrent) + context->makeCurrent(d_ptr); +#if defined(QVG_USE_FBO) + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + if (d_ptr->fbo) { + static GLfloat const vertices[][2] = { + {-1, -1}, {1, -1}, {1, 1}, {-1, 1} + }; + static GLfloat const texCoords[][2] = { + {0, 0}, {1, 0}, {1, 1}, {0, 1} + }; + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glVertexPointer(2, GL_FLOAT, 0, vertices); + glTexCoordPointer(2, GL_FLOAT, 0, texCoords); + glBindTexture(GL_TEXTURE_2D, d_ptr->texture); + glEnable(GL_TEXTURE_2D); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); + glDisable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, 0); + } +#endif +#if defined(Q_WS_X11) + glXSwapBuffers(X11->display, d_ptr->drawable); +#endif + context->doneCurrent(); +} + +void ShivaVGWindowSurface::setGeometry(const QRect &rect) +{ + QWindowSurface::setGeometry(rect); + d_ptr->needsResize = true; + d_ptr->size = rect.size(); +} + +bool ShivaVGWindowSurface::scroll(const QRegion &area, int dx, int dy) +{ + return QWindowSurface::scroll(area, dx, dy); +} + +void ShivaVGWindowSurface::beginPaint(const QRegion ®ion) +{ + // Nothing to do here. + Q_UNUSED(region); +} + +void ShivaVGWindowSurface::endPaint(const QRegion ®ion) +{ + // Nothing to do here. + Q_UNUSED(region); +} + +Q_GLOBAL_STATIC(QVGPaintEngine, sharedPaintEngine); + +QPaintEngine *ShivaVGWindowSurface::paintEngine() const +{ + if (!d_ptr->engine) + d_ptr->engine = sharedPaintEngine(); + return d_ptr->engine; +} + +// We need to get access to QWidget::metric() from ShivaVGWindowSurface::metric, +// but it is not a friend of QWidget. To get around this, we create a +// fake QX11PaintEngine class, which is a friend. +class QX11PaintEngine +{ +public: + static int metric(const QWidget *widget, QPaintDevice::PaintDeviceMetric met) + { + return widget->metric(met); + } +}; + +int ShivaVGWindowSurface::metric(PaintDeviceMetric met) const +{ + return QX11PaintEngine::metric(window(), met); +} + +QT_END_NAMESPACE diff --git a/src/plugins/graphicssystems/shivavg/shivavgwindowsurface.h b/src/plugins/graphicssystems/shivavg/shivavgwindowsurface.h new file mode 100644 index 0000000..5211ba4 --- /dev/null +++ b/src/plugins/graphicssystems/shivavg/shivavgwindowsurface.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SHIVAVGWINDOWSURFACE_H +#define SHIVAVGWINDOWSURFACE_H + +#include + +QT_BEGIN_NAMESPACE + +class ShivaVGWindowSurfacePrivate; + +class ShivaVGWindowSurface : public QWindowSurface, public QPaintDevice +{ +public: + ShivaVGWindowSurface(QWidget *window); + virtual ~ShivaVGWindowSurface(); + + QPaintDevice *paintDevice(); + void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); + void setGeometry(const QRect &rect); + bool scroll(const QRegion &area, int dx, int dy); + + void beginPaint(const QRegion ®ion); + void endPaint(const QRegion ®ion); + + QPaintEngine *paintEngine() const; + +protected: + int metric(PaintDeviceMetric metric) const; + +private: + ShivaVGWindowSurfacePrivate *d_ptr; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/src.pro b/src/src.pro index f40c6ad..9bff20d 100644 --- a/src/src.pro +++ b/src/src.pro @@ -19,6 +19,7 @@ win32:{ } contains(QT_CONFIG, opengl)|contains(QT_CONFIG, opengles1)|contains(QT_CONFIG, opengles2): SRC_SUBDIRS += src_opengl +contains(QT_CONFIG, openvg): SRC_SUBDIRS += src_openvg contains(QT_CONFIG, xmlpatterns): SRC_SUBDIRS += src_xmlpatterns contains(QT_CONFIG, phonon): SRC_SUBDIRS += src_phonon contains(QT_CONFIG, svg): SRC_SUBDIRS += src_svg @@ -61,6 +62,8 @@ src_scripttools.subdir = $$QT_SOURCE_TREE/src/scripttools src_scripttools.target = sub-scripttools src_opengl.subdir = $$QT_SOURCE_TREE/src/opengl src_opengl.target = sub-opengl +src_openvg.subdir = $$QT_SOURCE_TREE/src/openvg +src_openvg.target = sub-openvg src_qt3support.subdir = $$QT_SOURCE_TREE/src/qt3support src_qt3support.target = sub-qt3support src_phonon.subdir = $$QT_SOURCE_TREE/src/phonon @@ -96,6 +99,7 @@ src_webkit.target = sub-webkit src_scripttools.depends = src_script src_gui src_network src_network.depends = src_corelib src_opengl.depends = src_gui + src_openvg.depends = src_gui src_sql.depends = src_corelib src_testlib.depends = src_corelib src_qt3support.depends = src_gui src_xml src_network src_sql diff --git a/tests/arthur/common/qengines.cpp b/tests/arthur/common/qengines.cpp index e94e9cc..ce1afe4 100644 --- a/tests/arthur/common/qengines.cpp +++ b/tests/arthur/common/qengines.cpp @@ -49,6 +49,7 @@ #include #include #include +#include // For QApplicationPrivate::graphics_system_name #include diff --git a/tools/qdoc3/test/qt-cpp-ignore.qdocconf b/tools/qdoc3/test/qt-cpp-ignore.qdocconf index cfb3afd..9a18abe 100644 --- a/tools/qdoc3/test/qt-cpp-ignore.qdocconf +++ b/tools/qdoc3/test/qt-cpp-ignore.qdocconf @@ -12,6 +12,7 @@ Cpp.ignoretokens = QAXFACTORY_EXPORT \ QM_EXPORT_ICONVIEW \ QM_EXPORT_NETWORK \ QM_EXPORT_OPENGL \ + QM_EXPORT_OPENVG \ QM_EXPORT_SQL \ QM_EXPORT_TABLE \ QM_EXPORT_WORKSPACE \ @@ -50,6 +51,7 @@ Cpp.ignoretokens = QAXFACTORY_EXPORT \ Q_INTERNAL_WIN_NO_THROW \ Q_NETWORK_EXPORT \ Q_OPENGL_EXPORT \ + Q_OPENVG_EXPORT \ Q_OUTOFLINE_TEMPLATE \ Q_SQL_EXPORT \ Q_SVG_EXPORT \ -- cgit v0.12 From a8eda447bbf87ebd4041c851022af389a0e388e0 Mon Sep 17 00:00:00 2001 From: Bill King Date: Mon, 22 Jun 2009 15:34:09 +1000 Subject: Mark tests as XFail until they can be investigated further. --- tests/auto/q3sqlcursor/tst_q3sqlcursor.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/tests/auto/q3sqlcursor/tst_q3sqlcursor.cpp b/tests/auto/q3sqlcursor/tst_q3sqlcursor.cpp index 74126f8..a2f4a66 100644 --- a/tests/auto/q3sqlcursor/tst_q3sqlcursor.cpp +++ b/tests/auto/q3sqlcursor/tst_q3sqlcursor.cpp @@ -301,7 +301,8 @@ void tst_Q3SqlCursor::insert() // check that primeInsert returns a valid QSqlRecord QCOMPARE( (int)irec->count(), 4 ); if ( ( irec->field( 0 ).type() != QVariant::Int ) && - ( irec->field( 0 ).type() != QVariant::String ) ) { + ( irec->field( 0 ).type() != QVariant::String ) && + ( irec->field( 0 ).type() != QVariant::Double ) ) { QFAIL( QString( "Wrong datatype %1 for field 'ID'" " (expected Int or String)" ).arg( QVariant::typeToName( irec->field( 0 ).type() ) ) ); } @@ -533,13 +534,18 @@ void tst_Q3SqlCursor::unicode() cur.del(); if ( res != utf8str ) { - int i; - for ( i = 0; i < (int)res.length(); ++i ) { - if ( res[ i ] != utf8str[ i ] ) - break; - } - QFAIL( QString( "Strings differ at position %1: orig: %2, db: %3" ).arg( i ).arg( utf8str[ i ].unicode(), 0, 16 ).arg( res[ i ].unicode(), 0, 16 ) ); + int i; + for ( i = 0; i < (int)res.length(); ++i ) { + if ( res[ i ] != utf8str[ i ] ) + break; + } + if(db.driverName().startsWith("QMYSQL") || db.driverName().startsWith("QDB2")) + qWarning() << "Needs someone with more Unicode knowledge than I have to fix:" << QString( "Strings differ at position %1: orig: %2, db: %3" ).arg( i ).arg( utf8str[ i ].unicode(), 0, 16 ).arg( res[ i ].unicode(), 0, 16 ); + else + QFAIL( QString( "Strings differ at position %1: orig: %2, db: %3" ).arg( i ).arg( utf8str[ i ].unicode(), 0, 16 ).arg( res[ i ].unicode(), 0, 16 ) ); } + if(db.driverName().startsWith("QMYSQL") || db.driverName().startsWith("QDB2")) + QEXPECT_FAIL("", "See above message", Continue); QVERIFY( res == utf8str ); } -- cgit v0.12 From 3647de5291db9e359e7844f80202251f47e83a97 Mon Sep 17 00:00:00 2001 From: Bill King Date: Tue, 23 Jun 2009 15:10:52 +1000 Subject: Cleanup of db test cases. Mostly cleanup of dropping of tables to a consistent place. Also enable itemmodel tests. --- tests/auto/q3sqlcursor/tst_q3sqlcursor.cpp | 17 ++++-- .../q3sqlselectcursor/tst_q3sqlselectcursor.cpp | 2 +- tests/auto/qitemmodel/qitemmodel.pro | 3 +- tests/auto/qsqldatabase/tst_databases.h | 14 ++++- tests/auto/qsqldatabase/tst_qsqldatabase.cpp | 8 +-- tests/auto/qsqldriver/tst_qsqldriver.cpp | 8 +-- tests/auto/qsqlquery/tst_qsqlquery.cpp | 65 ++++------------------ .../tst_qsqlrelationaltablemodel.cpp | 48 +++++++--------- tests/auto/qsqltablemodel/tst_qsqltablemodel.cpp | 2 +- 9 files changed, 62 insertions(+), 105 deletions(-) diff --git a/tests/auto/q3sqlcursor/tst_q3sqlcursor.cpp b/tests/auto/q3sqlcursor/tst_q3sqlcursor.cpp index a2f4a66..2d89639 100644 --- a/tests/auto/q3sqlcursor/tst_q3sqlcursor.cpp +++ b/tests/auto/q3sqlcursor/tst_q3sqlcursor.cpp @@ -132,6 +132,11 @@ void tst_Q3SqlCursor::createTestTables( QSqlDatabase db ) if ( !db.isValid() ) return; QSqlQuery q( db ); + + if (tst_Databases::isSqlServer(db)) { + QVERIFY_SQL(q, exec("SET ANSI_DEFAULTS ON")); + } + // please never ever change this table; otherwise fix all tests ;) if ( tst_Databases::isMSAccess( db ) ) { QVERIFY_SQL(q, exec( "create table " + qTableName( "qtest" ) + " ( id int not null, t_varchar varchar(40) not null," @@ -753,12 +758,12 @@ void tst_Q3SqlCursor::insertFieldNameContainsWS() { QString tableName = qTableName("qtestws"); QSqlQuery q(db); - q.exec(QString("DROP TABLE %1").arg(tableName)); + tst_Databases::safeDropTable(db, tableName); QString query = QString("CREATE TABLE %1 (id int, \"first Name\" varchar(20), " - "lastName varchar(20))"); - QVERIFY_SQL(q, exec(query.arg(tableName))); + "lastName varchar(20))").arg(tableName); + QVERIFY_SQL(q, exec(query)); - Q3SqlCursor cur(QString("%1").arg(tableName), true, db); + Q3SqlCursor cur(tableName, true, db); cur.select(); QSqlRecord *r = cur.primeInsert(); @@ -774,8 +779,8 @@ void tst_Q3SqlCursor::insertFieldNameContainsWS() { QVERIFY(cur.value(0) == 1); QCOMPARE(cur.value(1).toString(), QString("Kong")); QCOMPARE(cur.value(2).toString(), QString("Harald")); - - q.exec(QString("DROP TABLE %1").arg(tableName)); + + tst_Databases::safeDropTable(db, tableName); } diff --git a/tests/auto/q3sqlselectcursor/tst_q3sqlselectcursor.cpp b/tests/auto/q3sqlselectcursor/tst_q3sqlselectcursor.cpp index d026cbf..ec1f805 100644 --- a/tests/auto/q3sqlselectcursor/tst_q3sqlselectcursor.cpp +++ b/tests/auto/q3sqlselectcursor/tst_q3sqlselectcursor.cpp @@ -114,7 +114,7 @@ void tst_Q3SqlSelectCursor::createTestTables( QSqlDatabase db ) void tst_Q3SqlSelectCursor::dropTestTables( QSqlDatabase db ) { - tst_Databases::safeDropTables( db, QStringList() << qTableName( "qtest" ) ); + tst_Databases::safeDropTable( db, qTableName( "qtest" ) ); } void tst_Q3SqlSelectCursor::populateTestTables( QSqlDatabase db ) diff --git a/tests/auto/qitemmodel/qitemmodel.pro b/tests/auto/qitemmodel/qitemmodel.pro index c51f4c7..38c615b 100644 --- a/tests/auto/qitemmodel/qitemmodel.pro +++ b/tests/auto/qitemmodel/qitemmodel.pro @@ -1,6 +1,5 @@ -CONFIG += qtestlib +load(qttest_p4) SOURCES += tst_qitemmodel.cpp -TARGET = tst_qitemmodel QT += sql diff --git a/tests/auto/qsqldatabase/tst_databases.h b/tests/auto/qsqldatabase/tst_databases.h index a490a2f..b81182a 100644 --- a/tests/auto/qsqldatabase/tst_databases.h +++ b/tests/auto/qsqldatabase/tst_databases.h @@ -238,8 +238,8 @@ public: // addDb( "QIBASE", "/opt/firebird/databases/testdb.fdb", "testuser", "Ee4Gabf6_", "firebird2-nokia.trolltech.com.au" ); // Firebird 2.1.1 // use in-memory database to prevent local files - addDb("QSQLITE", ":memory:"); -// addDb( "QSQLITE", QDir::toNativeSeparators(QDir::tempPath()+"/foo.db") ); +// addDb("QSQLITE", ":memory:"); + addDb( "QSQLITE", QDir::toNativeSeparators(QDir::tempPath()+"/foo.db") ); // addDb( "QSQLITE2", QDir::toNativeSeparators(QDir::tempPath()+"/foo2.db") ); // addDb( "QODBC3", "DRIVER={SQL SERVER};SERVER=iceblink.nokia.troll.no\\ICEBLINK", "troll", "trond", "" ); // addDb( "QODBC3", "DRIVER={SQL Native Client};SERVER=silence.nokia.troll.no\\SQLEXPRESS", "troll", "trond", "" ); @@ -333,6 +333,11 @@ public: } } + static void safeDropTable( QSqlDatabase db, const QString& tableName ) + { + safeDropTables(db, QStringList() << tableName); + } + static void safeDropViews( QSqlDatabase db, const QStringList &viewNames ) { if ( isMSAccess( db ) ) // Access is sooo stupid. @@ -354,6 +359,11 @@ public: } } + static void safeDropView( QSqlDatabase db, const QString& tableName ) + { + safeDropViews(db, QStringList() << tableName); + } + // returns the type name of the blob datatype for the database db. // blobSize is only used if the db doesn't have a generic blob type static QString blobTypeName( QSqlDatabase db, int blobSize = 10000 ) diff --git a/tests/auto/qsqldatabase/tst_qsqldatabase.cpp b/tests/auto/qsqldatabase/tst_qsqldatabase.cpp index cce4602..f697488 100644 --- a/tests/auto/qsqldatabase/tst_qsqldatabase.cpp +++ b/tests/auto/qsqldatabase/tst_qsqldatabase.cpp @@ -249,7 +249,7 @@ struct FieldDef { // excluding the primary key field static int createFieldTable(const FieldDef fieldDefs[], QSqlDatabase db) { - tst_Databases::safeDropTables(db, QStringList() << qTableName("qtestfields")); + tst_Databases::safeDropTable(db, qTableName("qtestfields")); QSqlQuery q(db); // construct a create table statement consisting of all fieldtypes QString qs = "create table " + qTableName("qtestfields"); @@ -357,6 +357,7 @@ void tst_QSqlDatabase::dropTestTables(QSqlDatabase db) tableNames << (qTableName("qtest") + " test"); tst_Databases::safeDropTables(db, tableNames); + tst_Databases::safeDropView(db, qTableName("qtest_view")); } void tst_QSqlDatabase::populateTestTables(QSqlDatabase db) @@ -540,11 +541,6 @@ void tst_QSqlDatabase::tables() QVERIFY(tables.contains(qTableName("temp_tab"), Qt::CaseInsensitive)); QVERIFY(tables.contains(qTableName("qtest"), Qt::CaseInsensitive)); - if (tst_Databases::isMSAccess(db)) - QSqlQuery("drop table " + qTableName("qtest_view"), db); - else - QSqlQuery("drop view " + qTableName("qtest_view"), db); - if (db.driverName().startsWith("QPSQL")) { QVERIFY(tables.contains(qTableName("qtest") + " test")); } diff --git a/tests/auto/qsqldriver/tst_qsqldriver.cpp b/tests/auto/qsqldriver/tst_qsqldriver.cpp index bbd7483..d8f7747 100644 --- a/tests/auto/qsqldriver/tst_qsqldriver.cpp +++ b/tests/auto/qsqldriver/tst_qsqldriver.cpp @@ -85,9 +85,7 @@ void tst_QSqlDriver::recreateTestTables(QSqlDatabase db) { QSqlQuery q(db); - QStringList tableNames; - tableNames << qTableName( "relTEST1" ); - tst_Databases::safeDropTables( db, tableNames ); + tst_Databases::safeDropTable( db, qTableName( "relTEST1" ) ); QVERIFY_SQL( q, exec("create table " + qTableName("relTEST1") + " (id int not null primary key, name varchar(20), title_key int, another_title_key int)")); @@ -105,11 +103,9 @@ void tst_QSqlDriver::initTestCase() void tst_QSqlDriver::cleanupTestCase() { - QStringList tableNames; - tableNames << qTableName( "relTEST1" ); foreach (const QString &dbName, dbs.dbNames) { QSqlDatabase db = QSqlDatabase::database(dbName); - tst_Databases::safeDropTables( db, tableNames ); + tst_Databases::safeDropTable( db, qTableName( "relTEST1" ) ); } dbs.close(); } diff --git a/tests/auto/qsqlquery/tst_qsqlquery.cpp b/tests/auto/qsqlquery/tst_qsqlquery.cpp index 825db6c..9604fa8 100644 --- a/tests/auto/qsqlquery/tst_qsqlquery.cpp +++ b/tests/auto/qsqlquery/tst_qsqlquery.cpp @@ -289,7 +289,8 @@ void tst_QSqlQuery::dropTestTables( QSqlDatabase db ) << qTableName( "bindtest" ) << qTableName( "more_results" ) << qTableName( "blobstest" ) - << qTableName( "oraRowId" ); + << qTableName( "oraRowId" ) + << qTableName( "qtest_batch" ); if ( db.driverName().startsWith("QSQLITE") ) tablenames << qTableName( "record_sqlite" ); @@ -303,6 +304,7 @@ void tst_QSqlQuery::dropTestTables( QSqlDatabase db ) tablenames << qTableName( "Planet" ); #endif tablenames << qTableName( "task_250026" ); + tablenames << qTableName( "task_234422" ); tst_Databases::safeDropTables( db, tablenames ); } @@ -1902,71 +1904,48 @@ void tst_QSqlQuery::batchExec() QSKIP( "Database can't do BatchOperations", SkipSingle ); QSqlQuery q( db ); + QString tableName = qTableName( "qtest_batch" ); - q.exec( "drop table " + qTableName( "qtest_batch" ) ); - - QVERIFY_SQL( q, exec( "create table " + qTableName( "qtest_batch" ) + " (id int, name varchar(20), dt date, num numeric(8, 4))" ) ); - - QVERIFY_SQL( q, prepare( "insert into " + qTableName( "qtest_batch" ) + " (id, name, dt, num) values (?, ?, ?, ?)" ) ); + QVERIFY_SQL( q, exec( "create table " + tableName + " (id int, name varchar(20), dt date, num numeric(8, 4))" ) ); + QVERIFY_SQL( q, prepare( "insert into " + tableName + " (id, name, dt, num) values (?, ?, ?, ?)" ) ); QVariantList intCol; - intCol << 1 << 2 << QVariant( QVariant::Int ); QVariantList charCol; - charCol << QLatin1String( "harald" ) << QLatin1String( "boris" ) << QVariant( QVariant::String ); QVariantList dateCol; - QDateTime dt = QDateTime( QDate::currentDate(), QTime( 1, 2, 3 ) ); - dateCol << dt << dt.addDays( -1 ) << QVariant( QVariant::DateTime ); QVariantList numCol; - numCol << 2.3 << 3.4 << QVariant( QVariant::Double ); q.addBindValue( intCol ); - q.addBindValue( charCol ); - q.addBindValue( dateCol ); - q.addBindValue( numCol ); QVERIFY_SQL( q, execBatch() ); - - QVERIFY_SQL( q, exec( "select id, name, dt, num from " + qTableName( "qtest_batch" ) + " order by id" ) ); + QVERIFY_SQL( q, exec( "select id, name, dt, num from " + tableName + " order by id" ) ); QVERIFY( q.next() ); - QCOMPARE( q.value( 0 ).toInt(), 1 ); - QCOMPARE( q.value( 1 ).toString(), QString( "harald" ) ); - QCOMPARE( q.value( 2 ).toDateTime(), dt ); - QCOMPARE( q.value( 3 ).toDouble(), 2.3 ); QVERIFY( q.next() ); - QCOMPARE( q.value( 0 ).toInt(), 2 ); - QCOMPARE( q.value( 1 ).toString(), QString( "boris" ) ); - QCOMPARE( q.value( 2 ).toDateTime(), dt.addDays( -1 ) ); - QCOMPARE( q.value( 3 ).toDouble(), 3.4 ); QVERIFY( q.next() ); - QVERIFY( q.value( 0 ).isNull() ); - QVERIFY( q.value( 1 ).isNull() ); - QVERIFY( q.value( 2 ).isNull() ); - QVERIFY( q.value( 3 ).isNull() ); } @@ -2344,6 +2323,8 @@ void tst_QSqlQuery::sqlite_finish() QString tableName = qTableName( "qtest_lockedtable" ); QSqlQuery q( db ); + + tst_Databases::safeDropTable( db2, tableName ); q.exec( "CREATE TABLE " + tableName + " (pk_id INTEGER PRIMARY KEY, whatever TEXT)" ); q.exec( "INSERT INTO " + tableName + " values(1, 'whatever')" ); q.exec( "INSERT INTO " + tableName + " values(2, 'whatever more')" ); @@ -2361,7 +2342,8 @@ void tst_QSqlQuery::sqlite_finish() q.finish(); QVERIFY_SQL( q2, exec( "DELETE FROM " + tableName + " WHERE pk_id=2" ) ); QCOMPARE( q2.numRowsAffected(), 1 ); - q.exec( "DROP TABLE " + tableName ); + + tst_Databases::safeDropTable( db2, tableName ); } QSqlDatabase::removeDatabase( "sqlite_finish_sqlite" ); @@ -2574,71 +2556,47 @@ void tst_QSqlQuery::blobsPreparedQuery() QString tableName = qTableName( "blobstest" ); QSqlQuery q( db ); - q.setForwardOnly( true ); // This is needed to make the test work with DB2. - QString shortBLOB( "abc" ); - QString longerBLOB( "abcdefghijklmnopqrstuvxyz¿äëïöü¡ " ); // In PostgreSQL a BLOB is not called a BLOB, but a BYTEA! :-) // ... and in SQL Server it can be called a lot, but IMAGE will do. QString typeName( "BLOB" ); - if ( db.driverName().startsWith( "QPSQL" ) ) typeName = "BYTEA"; else if ( db.driverName().startsWith( "QODBC" ) ) typeName = "IMAGE"; QVERIFY_SQL( q, exec( QString( "CREATE TABLE %1(id INTEGER, data %2)" ).arg( tableName ).arg( typeName ) ) ); - q.prepare( QString( "INSERT INTO %1(id, data) VALUES(:id, :data)" ).arg( tableName ) ); - q.bindValue( ":id", 1 ); - q.bindValue( ":data", shortBLOB.toAscii() ); - QVERIFY_SQL( q, exec() ); q.bindValue( ":id", 2 ); - q.bindValue( ":data", longerBLOB.toAscii() ); - QVERIFY_SQL( q, exec() ); // Two executions and result sets q.prepare( QString( "SELECT data FROM %1 WHERE id = ?" ).arg( tableName ) ); - q.bindValue( 0, QVariant( 1 ) ); - QVERIFY_SQL( q, exec() ); - QVERIFY_SQL( q, next() ); - QCOMPARE( q.value( 0 ).toString(), shortBLOB ); q.bindValue( 0, QVariant( 2 ) ); - QVERIFY_SQL( q, exec() ); - QVERIFY_SQL( q, next() ); - QCOMPARE( q.value( 0 ).toString(), longerBLOB ); // Only one execution and result set q.prepare( QString( "SELECT id, data FROM %1 ORDER BY id" ).arg( tableName ) ); - QVERIFY_SQL( q, exec() ); - QVERIFY_SQL( q, next() ); - QCOMPARE( q.value( 1 ).toString(), shortBLOB ); - QVERIFY_SQL( q, next() ); - QCOMPARE( q.value( 1 ).toString(), longerBLOB ); - - q.exec( QString( "DROP TABLE %1" ).arg( tableName ) ); } // There were problems with navigating past the end of a table returning an error on mysql @@ -2792,7 +2750,6 @@ void tst_QSqlQuery::task_234422() QString tableName = qTableName( "task_234422" ); - query.exec("DROP TABLE " + tableName); QVERIFY_SQL(query,exec("CREATE TABLE " + tableName + " (id int primary key, " "name varchar(20), homecountry varchar(2))")); for (int i = 0; i < m_airlines.count(); ++i) { diff --git a/tests/auto/qsqlrelationaltablemodel/tst_qsqlrelationaltablemodel.cpp b/tests/auto/qsqlrelationaltablemodel/tst_qsqlrelationaltablemodel.cpp index 4588af8..e2dace8 100644 --- a/tests/auto/qsqlrelationaltablemodel/tst_qsqlrelationaltablemodel.cpp +++ b/tests/auto/qsqlrelationaltablemodel/tst_qsqlrelationaltablemodel.cpp @@ -86,6 +86,9 @@ private slots: void escapedRelations(); void escapedTableName(); void whiteSpaceInIdentifiers(); + +private: + void dropTestTables( QSqlDatabase db ); }; @@ -100,18 +103,9 @@ void tst_QSqlRelationalTableModel::initTestCase_data() void tst_QSqlRelationalTableModel::recreateTestTables(QSqlDatabase db) { - QSqlQuery q(db); - - QStringList tableNames; - tableNames << qTableName( "reltest1" ) - << qTableName( "reltest2" ) - << qTableName( "reltest3" ) - << qTableName( "reltest4" ) - << qTableName( "reltest5" ) - << db.driver()->escapeIdentifier(qTableName( "rel test6" ), QSqlDriver::TableName) - << db.driver()->escapeIdentifier(qTableName( "rel test7" ), QSqlDriver::TableName); - tst_Databases::safeDropTables( db, tableNames ); + dropTestTables(db); + QSqlQuery q(db); QVERIFY_SQL( q, exec("create table " + qTableName("reltest1") + " (id int not null primary key, name varchar(20), title_key int, another_title_key int)")); QVERIFY_SQL( q, exec("insert into " + qTableName("reltest1") + " values(1, 'harry', 1, 2)")); @@ -157,20 +151,27 @@ void tst_QSqlRelationalTableModel::initTestCase() void tst_QSqlRelationalTableModel::cleanupTestCase() { + foreach (const QString &dbName, dbs.dbNames) { + QSqlDatabase db = QSqlDatabase::database(dbName); + CHECK_DATABASE( db ); + dropTestTables( QSqlDatabase::database(dbName) ); + } + dbs.close(); +} + +void tst_QSqlRelationalTableModel::dropTestTables( QSqlDatabase db ) +{ QStringList tableNames; tableNames << qTableName( "reltest1" ) << qTableName( "reltest2" ) << qTableName( "reltest3" ) << qTableName( "reltest4" ) - << qTableName( "reltest5" ); - foreach (const QString &dbName, dbs.dbNames) { - QSqlDatabase db = QSqlDatabase::database(dbName); - QStringList tables = tableNames; - tables << db.driver()->escapeIdentifier(qTableName( "rel test6" ), QSqlDriver::TableName) - << db.driver()->escapeIdentifier(qTableName( "rel test7" ), QSqlDriver::TableName); - tst_Databases::safeDropTables( db, tables ); - } - dbs.close(); + << qTableName( "reltest5" ) + << qTableName( "rel test6", db.driver() ) + << qTableName( "rel test7", db.driver() ) + << qTableName("CASETEST1", db.driver() ) + << qTableName("casetest1", db.driver() ); + tst_Databases::safeDropTables( db, tableNames ); } void tst_QSqlRelationalTableModel::init() @@ -916,11 +917,6 @@ void tst_QSqlRelationalTableModel::casing() if (db.driverName().startsWith("QSQLITE")) QSKIP("The casing test for SQLITE is irrelevant since SQLITE is case insensitive", SkipAll); - QStringList tableNames; - tableNames << qTableName("CASETEST1", db.driver()).toUpper(); - tableNames << qTableName("casetest1", db.driver()); - tst_Databases::safeDropTables(db, tableNames); - QSqlQuery q(db); QVERIFY_SQL( q, exec("create table " + qTableName("CASETEST1", db.driver()).toUpper() + " (id int not null primary key, name varchar(20), title_key int, another_title_key int)")); @@ -974,8 +970,6 @@ void tst_QSqlRelationalTableModel::casing() QCOMPARE(model.data(model.index(0, 0)).toInt(), 1); QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry")); QCOMPARE(model.data(model.index(0, 2)).toString(), QString("herr")); - - tst_Databases::safeDropTables(db, tableNames); } void tst_QSqlRelationalTableModel::escapedRelations() diff --git a/tests/auto/qsqltablemodel/tst_qsqltablemodel.cpp b/tests/auto/qsqltablemodel/tst_qsqltablemodel.cpp index aa882be..1445f34 100644 --- a/tests/auto/qsqltablemodel/tst_qsqltablemodel.cpp +++ b/tests/auto/qsqltablemodel/tst_qsqltablemodel.cpp @@ -899,7 +899,7 @@ void tst_QSqlTableModel::sqlite_attachedDatabase() QVERIFY_SQL( q, exec("INSERT INTO atest2 VALUES(2, 'attached-atest2')")); QSqlQuery q2(db); - tst_Databases::safeDropTables(db, QStringList() << "atest"); + tst_Databases::safeDropTable(db, "atest"); QVERIFY_SQL(q2, exec("CREATE TABLE atest(id int, text varchar(20))")); QVERIFY_SQL(q2, exec("INSERT INTO atest VALUES(3, 'main')")); QVERIFY_SQL(q2, exec("ATTACH DATABASE \""+attachedDb.databaseName()+"\" as adb")); -- cgit v0.12