diff options
author | Liang Qi <liang.qi@theqtcompany.com> | 2015-10-23 14:01:35 +0200 |
---|---|---|
committer | Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com> | 2015-10-23 14:45:03 +0200 |
commit | 790aef362fd195adf97d8c780a7cbbbade27d51f (patch) | |
tree | 8be464687ab21806cfe9f7ada27098b563aa41b2 /src/gui | |
parent | 9720efbd1035c2e939b0581163e6d804c713dd96 (diff) | |
parent | 07475c662eb73c833da2d461b8ef2702ca1e2cfb (diff) |
Merge remote-tracking branch 'origin/5.6' into dev
Conflicts:
.qmake.conf
configure
src/corelib/global/qglobal.h
src/tools/qdoc/node.cpp
src/tools/qdoc/qdocdatabase.cpp
tests/auto/corelib/io/qsettings/tst_qsettings.cpp
tools/configure/configureapp.cpp
Change-Id: I66028ae5e441a06b73ee85ba72a03a3af3e8593f
Diffstat (limited to 'src/gui')
23 files changed, 327 insertions, 189 deletions
diff --git a/src/gui/doc/qtgui.qdocconf b/src/gui/doc/qtgui.qdocconf index 436e2e0b34..e34347b801 100644 --- a/src/gui/doc/qtgui.qdocconf +++ b/src/gui/doc/qtgui.qdocconf @@ -4,7 +4,7 @@ project = QtGui description = Qt GUI Reference Documentation version = $QT_VERSION -examplesinstallpath = gui +examplesinstallpath = qtbase/gui qhp.projects = QtGui diff --git a/src/gui/image/qicon.cpp b/src/gui/image/qicon.cpp index 7ae081adfb..cebe5ce5f9 100644 --- a/src/gui/image/qicon.cpp +++ b/src/gui/image/qicon.cpp @@ -45,6 +45,7 @@ #include "qcache.h" #include "qdebug.h" #include "qpalette.h" +#include "qmath.h" #include "private/qhexstring_p.h" #include "private/qguiapplication_p.h" @@ -1029,19 +1030,13 @@ void QIcon::addFile(const QString &fileName, const QSize &size, Mode mode, State d->engine = new QPixmapIconEngine; } } + d->engine->addFile(fileName, size, mode, state); - // Check if a "@2x" file exists and add it. - static bool disable2xImageLoading = !qEnvironmentVariableIsEmpty("QT_HIGHDPI_DISABLE_2X_IMAGE_LOADING"); - if (!disable2xImageLoading && qApp->devicePixelRatio() > 1.0) { - QString at2xfileName = fileName; - int dotIndex = fileName.lastIndexOf(QLatin1Char('.')); - if (dotIndex == -1) /* no dot */ - dotIndex = fileName.size(); /* append */ - at2xfileName.insert(dotIndex, QStringLiteral("@2x")); - if (QFile::exists(at2xfileName)) - d->engine->addFile(at2xfileName, size, mode, state); - } + // Check if a "@Nx" file exists and add it. + QString atNxFileName = qt_findAtNxFile(fileName, qApp->devicePixelRatio()); + if (atNxFileName != fileName) + d->engine->addFile(atNxFileName, size, mode, state); } /*! @@ -1395,5 +1390,39 @@ QDebug operator<<(QDebug dbg, const QIcon &i) \internal */ +/*! + \internal + \since 5.6 + Attempts to find a suitable @Nx file for the given \a targetDevicePixelRatio + Returns the the \a baseFileName if no such file was found. + + Given base foo.png and a target dpr of 2.5, this function will look for + foo@3x.png, then foo@2x, then fall back to foo.png if not found. +*/ +QString qt_findAtNxFile(const QString &baseFileName, qreal targetDevicePixelRatio) +{ + if (targetDevicePixelRatio <= 1.0) + return baseFileName; + + static bool disableNxImageLoading = !qEnvironmentVariableIsEmpty("QT_HIGHDPI_DISABLE_2X_IMAGE_LOADING"); + if (disableNxImageLoading) + return baseFileName; + + QString atNx = QLatin1String("@%1x"); + int dotIndex = baseFileName.lastIndexOf(QLatin1Char('.')); + if (dotIndex == -1) /* no dot */ + dotIndex = baseFileName.size(); /* append */ + + // Check for @Nx, ..., @3x, @2x file versions, + for (int n = qCeil(targetDevicePixelRatio); n > 1; --n) { + QString atNxfileName = baseFileName; + atNxfileName.insert(dotIndex, atNx.arg(n)); + if (QFile::exists(atNxfileName)) + return atNxfileName; + } + + return baseFileName; +} + QT_END_NAMESPACE #endif //QT_NO_ICON diff --git a/src/gui/image/qicon.h b/src/gui/image/qicon.h index 329ae3deb3..6808bc2828 100644 --- a/src/gui/image/qicon.h +++ b/src/gui/image/qicon.h @@ -140,6 +140,8 @@ Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QIcon &); Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QIcon &); #endif +Q_GUI_EXPORT QString qt_findAtNxFile(const QString &baseFileName, qreal targetDevicePixelRatio); + QT_END_NAMESPACE #endif // QICON_H diff --git a/src/gui/image/qpixmap_win.cpp b/src/gui/image/qpixmap_win.cpp index 12e19440dc..a7a9b375ff 100644 --- a/src/gui/image/qpixmap_win.cpp +++ b/src/gui/image/qpixmap_win.cpp @@ -345,9 +345,22 @@ static QImage qt_imageFromWinIconHBITMAP(HDC hdc, HBITMAP bitmap, int w, int h) return image; } +static inline bool hasAlpha(const QImage &image) +{ + const int w = image.width(); + const int h = image.height(); + for (int y = 0; y < h; ++y) { + const QRgb *scanLine = reinterpret_cast<const QRgb *>(image.scanLine(y)); + for (int x = 0; x < w; ++x) { + if (qAlpha(scanLine[x]) != 0) + return true; + } + } + return false; +} + Q_GUI_EXPORT QPixmap qt_pixmapFromWinHICON(HICON icon) { - bool foundAlpha = false; HDC screenDevice = GetDC(0); HDC hdc = CreateCompatibleDC(screenDevice); ReleaseDC(0, screenDevice); @@ -356,6 +369,7 @@ Q_GUI_EXPORT QPixmap qt_pixmapFromWinHICON(HICON icon) const bool result = GetIconInfo(icon, &iconinfo); //x and y Hotspot describes the icon center if (!result) { qErrnoWarning("QPixmap::fromWinHICON(), failed to GetIconInfo()"); + DeleteDC(hdc); return QPixmap(); } @@ -371,17 +385,7 @@ Q_GUI_EXPORT QPixmap qt_pixmapFromWinHICON(HICON icon) DrawIconEx( hdc, 0, 0, icon, iconinfo.xHotspot * 2, iconinfo.yHotspot * 2, 0, 0, DI_NORMAL); QImage image = qt_imageFromWinIconHBITMAP(hdc, winBitmap, w, h); - for (int y = 0 ; y < h && !foundAlpha ; y++) { - const QRgb *scanLine= reinterpret_cast<const QRgb *>(image.scanLine(y)); - for (int x = 0; x < w ; x++) { - if (qAlpha(scanLine[x]) != 0) { - foundAlpha = true; - break; - } - } - } - if (!foundAlpha) { - //If no alpha was found, we use the mask to set alpha values + if (!image.isNull() && !hasAlpha(image)) { //If no alpha was found, we use the mask to set alpha values DrawIconEx( hdc, 0, 0, icon, w, h, 0, 0, DI_MASK); const QImage mask = qt_imageFromWinIconHBITMAP(hdc, winBitmap, w, h); diff --git a/src/gui/image/qpixmapcache.cpp b/src/gui/image/qpixmapcache.cpp index 2df813367d..6265a0c16d 100644 --- a/src/gui/image/qpixmapcache.cpp +++ b/src/gui/image/qpixmapcache.cpp @@ -652,7 +652,8 @@ void QPixmapCache::remove(const Key &key) void QPixmapCache::clear() { QT_TRY { - pm_cache()->clear(); + if (pm_cache.exists()) + pm_cache->clear(); } QT_CATCH(const std::bad_alloc &) { // if we ran out of memory during pm_cache(), it's no leak, // so just ignore it. diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index b717585b54..35e880fc5b 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -902,7 +902,7 @@ QWindowList QGuiApplication::topLevelWindows() if (!list.at(i)->parent() && list.at(i)->type() != Qt::Desktop) { // Top windows of embedded QAxServers do not have QWindow parents, // but they are not true top level windows, so do not include them. - const bool embedded = list.at(i)->handle() && list.at(i)->handle()->isEmbedded(0); + const bool embedded = list.at(i)->handle() && list.at(i)->handle()->isEmbedded(); if (!embedded) topLevelWindows.prepend(list.at(i)); } diff --git a/src/gui/kernel/qplatformintegration.cpp b/src/gui/kernel/qplatformintegration.cpp index 457a420148..14633d8b30 100644 --- a/src/gui/kernel/qplatformintegration.cpp +++ b/src/gui/kernel/qplatformintegration.cpp @@ -208,8 +208,7 @@ QPlatformServices *QPlatformIntegration::services() const behavior for desktop platforms. \value ForeignWindows The platform allows creating QWindows which represent - native windows created by other processes or anyway created by using native - libraries. + native windows created by other processes or by using native libraries. \value NonFullScreenWindows The platform supports top-level windows which do not fill the screen. The default implementation returns \c true. Returning false for diff --git a/src/gui/kernel/qplatformwindow.h b/src/gui/kernel/qplatformwindow.h index 9c2817906f..850e2b4bfe 100644 --- a/src/gui/kernel/qplatformwindow.h +++ b/src/gui/kernel/qplatformwindow.h @@ -95,7 +95,7 @@ public: virtual bool isExposed() const; virtual bool isActive() const; - virtual bool isEmbedded(const QPlatformWindow *parentWindow) const; + virtual bool isEmbedded(const QPlatformWindow *parentWindow = 0) const; virtual QPoint mapToGlobal(const QPoint &pos) const; virtual QPoint mapFromGlobal(const QPoint &pos) const; diff --git a/src/gui/kernel/qshapedpixmapdndwindow.cpp b/src/gui/kernel/qshapedpixmapdndwindow.cpp index 5736c41e25..d77b6dc262 100644 --- a/src/gui/kernel/qshapedpixmapdndwindow.cpp +++ b/src/gui/kernel/qshapedpixmapdndwindow.cpp @@ -35,12 +35,16 @@ #include <QtGui/QPainter> #include <QtGui/QCursor> +#include <QtGui/QGuiApplication> +#include <QtGui/QPalette> +#include <QtGui/QBitmap> QT_BEGIN_NAMESPACE QShapedPixmapWindow::QShapedPixmapWindow(QScreen *screen) : QWindow(screen), - m_backingStore(0) + m_backingStore(0), + m_useCompositing(true) { QSurfaceFormat format; format.setAlphaBufferSize(8); @@ -68,7 +72,10 @@ void QShapedPixmapWindow::render() { QPainter p(device); - p.setCompositionMode(QPainter::CompositionMode_Source); + if (m_useCompositing) + p.setCompositionMode(QPainter::CompositionMode_Source); + else + p.fillRect(rect, QGuiApplication::palette().base()); p.drawPixmap(0, 0, m_pixmap); } @@ -79,6 +86,8 @@ void QShapedPixmapWindow::render() void QShapedPixmapWindow::setPixmap(const QPixmap &pixmap) { m_pixmap = pixmap; + if (!m_useCompositing) + setMask(m_pixmap.mask()); } void QShapedPixmapWindow::setHotspot(const QPoint &hotspot) diff --git a/src/gui/kernel/qshapedpixmapdndwindow_p.h b/src/gui/kernel/qshapedpixmapdndwindow_p.h index 7536c09165..3d7974fa82 100644 --- a/src/gui/kernel/qshapedpixmapdndwindow_p.h +++ b/src/gui/kernel/qshapedpixmapdndwindow_p.h @@ -60,6 +60,7 @@ public: void render(); + void setUseCompositing(bool on) { m_useCompositing = on; } void setPixmap(const QPixmap &pixmap); void setHotspot(const QPoint &hotspot); @@ -72,6 +73,7 @@ private: QBackingStore *m_backingStore; QPixmap m_pixmap; QPoint m_hotSpot; + bool m_useCompositing; }; QT_END_NAMESPACE diff --git a/src/gui/kernel/qshortcutmap.cpp b/src/gui/kernel/qshortcutmap.cpp index 3b2e6ffd29..9c8218b7b5 100644 --- a/src/gui/kernel/qshortcutmap.cpp +++ b/src/gui/kernel/qshortcutmap.cpp @@ -84,7 +84,7 @@ struct QShortcutEntry QShortcutMap::ContextMatcher contextMatcher; }; -#if 0 //ndef QT_NO_DEBUG_STREAM +#ifdef Dump_QShortcutMap /*! \internal QDebug operator<< for easy debug output of the shortcut entries. */ @@ -99,7 +99,7 @@ static QDebug &operator<<(QDebug &dbg, const QShortcutEntry *se) << "), owner(" << se->owner << ')'; return dbg; } -#endif // QT_NO_DEBUGSTREAM +#endif // Dump_QShortcutMap /* \internal Private data for QShortcutMap diff --git a/src/gui/kernel/qsimpledrag.cpp b/src/gui/kernel/qsimpledrag.cpp index d2efeaca28..706786385b 100644 --- a/src/gui/kernel/qsimpledrag.cpp +++ b/src/gui/kernel/qsimpledrag.cpp @@ -88,7 +88,7 @@ static QWindow* topLevelAt(const QPoint &pos) QBasicDrag::QBasicDrag() : m_restoreCursor(false), m_eventLoop(0), m_executed_drop_action(Qt::IgnoreAction), m_can_drop(false), - m_drag(0), m_drag_icon_window(0) + m_drag(0), m_drag_icon_window(0), m_useCompositing(true) { } @@ -234,6 +234,7 @@ void QBasicDrag::recreateShapedPixmapWindow(QScreen *screen, const QPoint &pos) // when QDrag is used without a pixmap - QDrag::setPixmap() m_drag_icon_window = new QShapedPixmapWindow(screen); + m_drag_icon_window->setUseCompositing(m_useCompositing); m_drag_icon_window->setPixmap(m_drag->pixmap()); m_drag_icon_window->setHotspot(m_drag->hotSpot()); m_drag_icon_window->updateGeometry(pos); diff --git a/src/gui/kernel/qsimpledrag_p.h b/src/gui/kernel/qsimpledrag_p.h index 34679a7540..d5dacd8fd2 100644 --- a/src/gui/kernel/qsimpledrag_p.h +++ b/src/gui/kernel/qsimpledrag_p.h @@ -88,6 +88,9 @@ protected: bool canDrop() const { return m_can_drop; } void setCanDrop(bool c) { m_can_drop = c; } + bool useCompositing() const { return m_useCompositing; } + void setUseCompositing(bool on) { m_useCompositing = on; } + Qt::DropAction executedDropAction() const { return m_executed_drop_action; } void setExecutedDropAction(Qt::DropAction da) { m_executed_drop_action = da; } @@ -105,6 +108,7 @@ private: bool m_can_drop; QDrag *m_drag; QShapedPixmapWindow *m_drag_icon_window; + bool m_useCompositing; }; class Q_GUI_EXPORT QSimpleDrag : public QBasicDrag diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index d4edc0fca1..e262f3f8a4 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -389,25 +389,31 @@ void QWindowPrivate::setTopLevelScreen(QScreen *newScreen, bool recreate) void QWindowPrivate::create(bool recursive) { Q_Q(QWindow); + if (platformWindow) + return; + + platformWindow = QGuiApplicationPrivate::platformIntegration()->createPlatformWindow(q); + Q_ASSERT(platformWindow); + if (!platformWindow) { - platformWindow = QGuiApplicationPrivate::platformIntegration()->createPlatformWindow(q); - QObjectList childObjects = q->children(); - for (int i = 0; i < childObjects.size(); i ++) { - QObject *object = childObjects.at(i); - if (object->isWindowType()) { - QWindow *window = static_cast<QWindow *>(object); - if (recursive) - window->d_func()->create(true); - if (window->d_func()->platformWindow) - window->d_func()->platformWindow->setParent(platformWindow); - } - } + qWarning() << "Failed to create platform window for" << q << "with flags" << q->flags(); + return; + } - if (platformWindow) { - QPlatformSurfaceEvent e(QPlatformSurfaceEvent::SurfaceCreated); - QGuiApplication::sendEvent(q, &e); + QObjectList childObjects = q->children(); + for (int i = 0; i < childObjects.size(); i ++) { + QObject *object = childObjects.at(i); + if (object->isWindowType()) { + QWindow *window = static_cast<QWindow *>(object); + if (recursive) + window->d_func()->create(true); + if (window->d_func()->platformWindow) + window->d_func()->platformWindow->setParent(platformWindow); } } + + QPlatformSurfaceEvent e(QPlatformSurfaceEvent::SurfaceCreated); + QGuiApplication::sendEvent(q, &e); } void QWindowPrivate::clearFocusObject() @@ -588,8 +594,7 @@ QWindow *QWindow::parent() const Setting \a parent to be 0 will make the window become a top level window. If \a parent is a window created by fromWinId(), then the current window - will be embedded inside \a parent, if the platform supports it. Window - embedding is currently supported only by the X11 platform plugin. + will be embedded inside \a parent, if the platform supports it. */ void QWindow::setParent(QWindow *parent) { @@ -2292,10 +2297,10 @@ QPoint QWindow::mapToGlobal(const QPoint &pos) const Q_D(const QWindow); // QTBUG-43252, prefer platform implementation for foreign windows. if (d->platformWindow - && (type() == Qt::ForeignWindow || d->platformWindow->isEmbedded(0))) { + && (type() == Qt::ForeignWindow || d->platformWindow->isEmbedded())) { return d->platformWindow->mapToGlobal(pos); } - return pos + d_func()->globalPosition(); + return pos + d->globalPosition(); } @@ -2312,10 +2317,10 @@ QPoint QWindow::mapFromGlobal(const QPoint &pos) const Q_D(const QWindow); // QTBUG-43252, prefer platform implementation for foreign windows. if (d->platformWindow - && (type() == Qt::ForeignWindow || d->platformWindow->isEmbedded(0))) { + && (type() == Qt::ForeignWindow || d->platformWindow->isEmbedded())) { return d->platformWindow->mapFromGlobal(pos); } - return pos - d_func()->globalPosition(); + return pos - d->globalPosition(); } @@ -2377,9 +2382,16 @@ QWindow *QWindowPrivate::topLevelWindow() const Given the handle \a id to a native window, this method creates a QWindow object which can be used to represent the window when invoking methods like setParent() and setTransientParent(). - This can be used, on platforms which support it, to embed a window inside a - container or to make a window stick on top of a window created by another - process. + + This can be used, on platforms which support it, to embed a QWindow inside a + native window, or to embed a native window inside a QWindow. + + If foreign windows are not supported, this function returns 0. + + \note The resulting QWindow should not be used to manipulate the underlying + native window (besides re-parenting), or to observe state changes of the + native window. Any support for these kind of operations is incidental, highly + platform dependent and untested. \sa setParent() \sa setTransientParent() diff --git a/src/gui/opengl/qopenglpaintengine.cpp b/src/gui/opengl/qopenglpaintengine.cpp index a9a4adaddc..4836dde343 100644 --- a/src/gui/opengl/qopenglpaintengine.cpp +++ b/src/gui/opengl/qopenglpaintengine.cpp @@ -2076,7 +2076,7 @@ bool QOpenGL2PaintEngineEx::begin(QPaintDevice *pdev) d->device->ensureActiveTarget(); - if (d->device->context() != QOpenGLContext::currentContext()) { + if (d->device->context() != QOpenGLContext::currentContext() || !d->device->context()) { qWarning("QPainter::begin(): QOpenGLPaintDevice's context needs to be current"); return false; } diff --git a/src/gui/opengl/qopengltextureblitter.cpp b/src/gui/opengl/qopengltextureblitter.cpp index 0f9fa6400d..1c6a7937e5 100644 --- a/src/gui/opengl/qopengltextureblitter.cpp +++ b/src/gui/opengl/qopengltextureblitter.cpp @@ -39,6 +39,10 @@ #include <QtGui/QOpenGLContext> #include <QtGui/QOpenGLFunctions> +#ifndef GL_TEXTURE_EXTERNAL_OES +#define GL_TEXTURE_EXTERNAL_OES 0x8D65 +#endif + QT_BEGIN_NAMESPACE static const char vertex_shader150[] = @@ -88,6 +92,18 @@ static const char fragment_shader[] = " gl_FragColor = swizzle ? tmpFragColor.bgra : tmpFragColor;" "}"; +static const char fragment_shader_external_oes[] = + "#extension GL_OES_EGL_image_external : require\n" + "varying highp vec2 uv;" + "uniform samplerExternalOES textureSampler;\n" + "uniform bool swizzle;" + "uniform highp float opacity;" + "void main() {" + " highp vec4 tmpFragColor = texture2D(textureSampler, uv);" + " tmpFragColor.a *= opacity;" + " gl_FragColor = swizzle ? tmpFragColor.bgra : tmpFragColor;" + "}"; + static const GLfloat vertex_buffer_data[] = { -1,-1, 0, -1, 1, 0, @@ -109,14 +125,17 @@ static const GLfloat texture_buffer_data[] = { class TextureBinder { public: - TextureBinder(GLuint textureId) + TextureBinder(GLenum target, GLuint textureId) : m_target(target) { - QOpenGLContext::currentContext()->functions()->glBindTexture(GL_TEXTURE_2D, textureId); + QOpenGLContext::currentContext()->functions()->glBindTexture(m_target, textureId); } ~TextureBinder() { - QOpenGLContext::currentContext()->functions()->glBindTexture(GL_TEXTURE_2D, 0); + QOpenGLContext::currentContext()->functions()->glBindTexture(m_target, 0); } + +private: + GLenum m_target; }; class QOpenGLTextureBlitterPrivate @@ -128,74 +147,106 @@ public: IdentityFlipped }; - QOpenGLTextureBlitterPrivate() - : program(0) - , vertexCoordAttribPos(0) - , vertexTransformUniformPos(0) - , textureCoordAttribPos(0) - , textureTransformUniformPos(0) - , swizzle(false) - , swizzleOld(false) - , opacity(1.0f) - , opacityOld(0.0f) - , textureMatrixUniformState(User) - , vao(new QOpenGLVertexArrayObject()) + enum ProgramIndex { + TEXTURE_2D, + TEXTURE_EXTERNAL_OES + }; + + QOpenGLTextureBlitterPrivate() : + swizzle(false), + opacity(1.0f), + vao(new QOpenGLVertexArrayObject), + currentTarget(TEXTURE_2D) { } + bool buildProgram(ProgramIndex idx, const char *vs, const char *fs); + void blit(GLuint texture, const QMatrix4x4 &vertexTransform, const QMatrix3x3 &textureTransform); void blit(GLuint texture, const QMatrix4x4 &vertexTransform, QOpenGLTextureBlitter::Origin origin); - void prepareProgram(const QMatrix4x4 &vertexTransform) - { - vertexBuffer.bind(); - program->setAttributeBuffer(vertexCoordAttribPos, GL_FLOAT, 0, 3, 0); - program->enableAttributeArray(vertexCoordAttribPos); - vertexBuffer.release(); - - program->setUniformValue(vertexTransformUniformPos, vertexTransform); - - textureBuffer.bind(); - program->setAttributeBuffer(textureCoordAttribPos, GL_FLOAT, 0, 2, 0); - program->enableAttributeArray(textureCoordAttribPos); - textureBuffer.release(); - - if (swizzle != swizzleOld) { - program->setUniformValue(swizzleUniformPos, swizzle); - swizzleOld = swizzle; - } - - if (opacity != opacityOld) { - program->setUniformValue(opacityUniformPos, opacity); - opacityOld = opacity; - } - } + void prepareProgram(const QMatrix4x4 &vertexTransform); QOpenGLBuffer vertexBuffer; QOpenGLBuffer textureBuffer; - QScopedPointer<QOpenGLShaderProgram> program; - GLuint vertexCoordAttribPos; - GLuint vertexTransformUniformPos; - GLuint textureCoordAttribPos; - GLuint textureTransformUniformPos; - GLuint swizzleUniformPos; - GLuint opacityUniformPos; + struct Program { + Program() : + vertexCoordAttribPos(0), + vertexTransformUniformPos(0), + textureCoordAttribPos(0), + textureTransformUniformPos(0), + swizzleUniformPos(0), + opacityUniformPos(0), + swizzle(false), + opacity(0.0f), + textureMatrixUniformState(User) + { } + QScopedPointer<QOpenGLShaderProgram> glProgram; + GLuint vertexCoordAttribPos; + GLuint vertexTransformUniformPos; + GLuint textureCoordAttribPos; + GLuint textureTransformUniformPos; + GLuint swizzleUniformPos; + GLuint opacityUniformPos; + bool swizzle; + float opacity; + TextureMatrixUniform textureMatrixUniformState; + } programs[2]; bool swizzle; - bool swizzleOld; float opacity; - float opacityOld; - TextureMatrixUniform textureMatrixUniformState; QScopedPointer<QOpenGLVertexArrayObject> vao; + GLenum currentTarget; }; +static inline QOpenGLTextureBlitterPrivate::ProgramIndex targetToProgramIndex(GLenum target) +{ + switch (target) { + case GL_TEXTURE_2D: + return QOpenGLTextureBlitterPrivate::TEXTURE_2D; + case GL_TEXTURE_EXTERNAL_OES: + return QOpenGLTextureBlitterPrivate::TEXTURE_EXTERNAL_OES; + default: + qWarning("Unsupported texture target 0x%x", target); + return QOpenGLTextureBlitterPrivate::TEXTURE_2D; + } +} + +void QOpenGLTextureBlitterPrivate::prepareProgram(const QMatrix4x4 &vertexTransform) +{ + Program *program = &programs[targetToProgramIndex(currentTarget)]; + + vertexBuffer.bind(); + program->glProgram->setAttributeBuffer(program->vertexCoordAttribPos, GL_FLOAT, 0, 3, 0); + program->glProgram->enableAttributeArray(program->vertexCoordAttribPos); + vertexBuffer.release(); + + program->glProgram->setUniformValue(program->vertexTransformUniformPos, vertexTransform); + + textureBuffer.bind(); + program->glProgram->setAttributeBuffer(program->textureCoordAttribPos, GL_FLOAT, 0, 2, 0); + program->glProgram->enableAttributeArray(program->textureCoordAttribPos); + textureBuffer.release(); + + if (swizzle != program->swizzle) { + program->glProgram->setUniformValue(program->swizzleUniformPos, swizzle); + program->swizzle = swizzle; + } + + if (opacity != program->opacity) { + program->glProgram->setUniformValue(program->opacityUniformPos, opacity); + program->opacity = opacity; + } +} + void QOpenGLTextureBlitterPrivate::blit(GLuint texture, const QMatrix4x4 &vertexTransform, const QMatrix3x3 &textureTransform) { - TextureBinder binder(texture); + TextureBinder binder(currentTarget, texture); prepareProgram(vertexTransform); - program->setUniformValue(textureTransformUniformPos, textureTransform); - textureMatrixUniformState = User; + Program *program = &programs[targetToProgramIndex(currentTarget)]; + program->glProgram->setUniformValue(program->textureTransformUniformPos, textureTransform); + program->textureMatrixUniformState = User; QOpenGLContext::currentContext()->functions()->glDrawArrays(GL_TRIANGLES, 0, 6); } @@ -204,25 +255,54 @@ void QOpenGLTextureBlitterPrivate::blit(GLuint texture, const QMatrix4x4 &vertexTransform, QOpenGLTextureBlitter::Origin origin) { - TextureBinder binder(texture); + TextureBinder binder(currentTarget, texture); prepareProgram(vertexTransform); + Program *program = &programs[targetToProgramIndex(currentTarget)]; if (origin == QOpenGLTextureBlitter::OriginTopLeft) { - if (textureMatrixUniformState != IdentityFlipped) { + if (program->textureMatrixUniformState != IdentityFlipped) { QMatrix3x3 flipped; flipped(1,1) = -1; flipped(1,2) = 1; - program->setUniformValue(textureTransformUniformPos, flipped); - textureMatrixUniformState = IdentityFlipped; + program->glProgram->setUniformValue(program->textureTransformUniformPos, flipped); + program->textureMatrixUniformState = IdentityFlipped; } - } else if (textureMatrixUniformState != Identity) { - program->setUniformValue(textureTransformUniformPos, QMatrix3x3()); - textureMatrixUniformState = Identity; + } else if (program->textureMatrixUniformState != Identity) { + program->glProgram->setUniformValue(program->textureTransformUniformPos, QMatrix3x3()); + program->textureMatrixUniformState = Identity; } QOpenGLContext::currentContext()->functions()->glDrawArrays(GL_TRIANGLES, 0, 6); } +bool QOpenGLTextureBlitterPrivate::buildProgram(ProgramIndex idx, const char *vs, const char *fs) +{ + Program *p = &programs[idx]; + + p->glProgram.reset(new QOpenGLShaderProgram); + + p->glProgram->addShaderFromSourceCode(QOpenGLShader::Vertex, vs); + p->glProgram->addShaderFromSourceCode(QOpenGLShader::Fragment, fs); + p->glProgram->link(); + if (!p->glProgram->isLinked()) { + qWarning() << Q_FUNC_INFO << "Could not link shader program:\n" << p->glProgram->log(); + return false; + } + + p->glProgram->bind(); + + p->vertexCoordAttribPos = p->glProgram->attributeLocation("vertexCoord"); + p->vertexTransformUniformPos = p->glProgram->uniformLocation("vertexTransform"); + p->textureCoordAttribPos = p->glProgram->attributeLocation("textureCoord"); + p->textureTransformUniformPos = p->glProgram->uniformLocation("textureTransform"); + p->swizzleUniformPos = p->glProgram->uniformLocation("swizzle"); + p->opacityUniformPos = p->glProgram->uniformLocation("opacity"); + + p->glProgram->setUniformValue(p->swizzleUniformPos, false); + + return true; +} + QOpenGLTextureBlitter::QOpenGLTextureBlitter() : d_ptr(new QOpenGLTextureBlitterPrivate) { @@ -241,28 +321,21 @@ bool QOpenGLTextureBlitter::create() Q_D(QOpenGLTextureBlitter); - if (d->program) + if (d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_2D].glProgram) return true; - d->program.reset(new QOpenGLShaderProgram()); - QSurfaceFormat format = currentContext->format(); - if (format.profile() == QSurfaceFormat::CoreProfile && format.version() >= qMakePair(3,2)) { - d->program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertex_shader150); - d->program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragment_shader150); + if (!d->buildProgram(QOpenGLTextureBlitterPrivate::TEXTURE_2D, vertex_shader150, fragment_shader150)) + return false; } else { - d->program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertex_shader); - d->program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragment_shader); - } - d->program->link(); - if (!d->program->isLinked()) { - qWarning() << Q_FUNC_INFO << "Could not link shader program:\n" << d->program->log(); - return false; + if (!d->buildProgram(QOpenGLTextureBlitterPrivate::TEXTURE_2D, vertex_shader, fragment_shader)) + return false; + if (supportsExternalOESTarget()) + if (!d->buildProgram(QOpenGLTextureBlitterPrivate::TEXTURE_EXTERNAL_OES, vertex_shader, fragment_shader_external_oes)) + return false; } - d->program->bind(); - // Create and bind the VAO, if supported. QOpenGLVertexArrayObject::Binder vaoBinder(d->vao.data()); @@ -276,22 +349,13 @@ bool QOpenGLTextureBlitter::create() d->textureBuffer.allocate(texture_buffer_data, sizeof(texture_buffer_data)); d->textureBuffer.release(); - d->vertexCoordAttribPos = d->program->attributeLocation("vertexCoord"); - d->vertexTransformUniformPos = d->program->uniformLocation("vertexTransform"); - d->textureCoordAttribPos = d->program->attributeLocation("textureCoord"); - d->textureTransformUniformPos = d->program->uniformLocation("textureTransform"); - d->swizzleUniformPos = d->program->uniformLocation("swizzle"); - d->opacityUniformPos = d->program->uniformLocation("opacity"); - - d->program->setUniformValue(d->swizzleUniformPos,false); - return true; } bool QOpenGLTextureBlitter::isCreated() const { Q_D(const QOpenGLTextureBlitter); - return d->program; + return d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_2D].glProgram; } void QOpenGLTextureBlitter::destroy() @@ -299,36 +363,45 @@ void QOpenGLTextureBlitter::destroy() if (!isCreated()) return; Q_D(QOpenGLTextureBlitter); - d->program.reset(); + d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_2D].glProgram.reset(); + d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_EXTERNAL_OES].glProgram.reset(); d->vertexBuffer.destroy(); d->textureBuffer.destroy(); d->vao.reset(); } -void QOpenGLTextureBlitter::bind() +bool QOpenGLTextureBlitter::supportsExternalOESTarget() const +{ + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + return ctx && ctx->isOpenGLES() && ctx->hasExtension("GL_OES_EGL_image_external"); +} + +void QOpenGLTextureBlitter::bind(GLenum target) { Q_D(QOpenGLTextureBlitter); if (d->vao->isCreated()) d->vao->bind(); - d->program->bind(); + d->currentTarget = target; + QOpenGLTextureBlitterPrivate::Program *p = &d->programs[targetToProgramIndex(target)]; + p->glProgram->bind(); d->vertexBuffer.bind(); - d->program->setAttributeBuffer(d->vertexCoordAttribPos, GL_FLOAT, 0, 3, 0); - d->program->enableAttributeArray(d->vertexCoordAttribPos); + p->glProgram->setAttributeBuffer(p->vertexCoordAttribPos, GL_FLOAT, 0, 3, 0); + p->glProgram->enableAttributeArray(p->vertexCoordAttribPos); d->vertexBuffer.release(); d->textureBuffer.bind(); - d->program->setAttributeBuffer(d->textureCoordAttribPos, GL_FLOAT, 0, 2, 0); - d->program->enableAttributeArray(d->textureCoordAttribPos); + p->glProgram->setAttributeBuffer(p->textureCoordAttribPos, GL_FLOAT, 0, 2, 0); + p->glProgram->enableAttributeArray(p->textureCoordAttribPos); d->textureBuffer.release(); } void QOpenGLTextureBlitter::release() { Q_D(QOpenGLTextureBlitter); - d->program->release(); + d->programs[targetToProgramIndex(d->currentTarget)].glProgram->release(); if (d->vao->isCreated()) d->vao->release(); } diff --git a/src/gui/opengl/qopengltextureblitter_p.h b/src/gui/opengl/qopengltextureblitter_p.h index 8f7eae1c32..ebf3a4bfbb 100644 --- a/src/gui/opengl/qopengltextureblitter_p.h +++ b/src/gui/opengl/qopengltextureblitter_p.h @@ -68,7 +68,9 @@ public: bool isCreated() const; void destroy(); - void bind(); + bool supportsExternalOESTarget() const; + + void bind(GLenum target = GL_TEXTURE_2D); void release(); void setSwizzleRB(bool swizzle); diff --git a/src/gui/painting/qcolor.cpp b/src/gui/painting/qcolor.cpp index 1012ed7c6d..3f30c061dc 100644 --- a/src/gui/painting/qcolor.cpp +++ b/src/gui/painting/qcolor.cpp @@ -2075,7 +2075,7 @@ QColor QColor::fromHsl(int h, int s, int l, int a) || s < 0 || s > 255 || l < 0 || l > 255 || a < 0 || a > 255) { - qWarning("QColor::fromHsv: HSV parameters out of range"); + qWarning("QColor::fromHsl: HSL parameters out of range"); return QColor(); } @@ -2107,7 +2107,7 @@ QColor QColor::fromHslF(qreal h, qreal s, qreal l, qreal a) || (s < qreal(0.0) || s > qreal(1.0)) || (l < qreal(0.0) || l > qreal(1.0)) || (a < qreal(0.0) || a > qreal(1.0))) { - qWarning("QColor::fromHsvF: HSV parameters out of range"); + qWarning("QColor::fromHslF: HSL parameters out of range"); return QColor(); } diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 64a363868a..6cfc4b9307 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -503,14 +503,16 @@ static const uint *QT_FASTCALL convertRGBA8888PMFromARGB32PM(uint *buffer, const template<bool RGBA, bool maskAlpha> static inline void qConvertARGB32PMToARGB64PM_sse2(QRgba64 *buffer, const uint *src, int count) { + if (count <= 0) + return; + const __m128i amask = _mm_set1_epi32(0xff000000); int i = 0; - if (((uintptr_t)buffer & 0xf) && count > 0) { + for (; ((uintptr_t)buffer & 0xf) && i < count; ++i) { uint s = *src++; if (RGBA) s = RGBA2ARGB(s); *buffer++ = QRgba64::fromArgb32(s); - i++; } for (; i < count-3; i += 4) { __m128i vs = _mm_loadu_si128((const __m128i*)src); @@ -641,15 +643,18 @@ static const uint *QT_FASTCALL convertA2RGB30PMToARGB32PM(uint *buffer, const ui template<QtPixelOrder PixelOrder> static inline void qConvertA2RGB30PMToARGB64PM_sse2(QRgba64 *buffer, const uint *src, int count) { + if (count <= 0) + return; + const __m128i rmask = _mm_set1_epi32(0x3ff00000); const __m128i gmask = _mm_set1_epi32(0x000ffc00); const __m128i bmask = _mm_set1_epi32(0x000003ff); const __m128i afactor = _mm_set1_epi16(0x5555); int i = 0; - if (((uintptr_t)buffer & 0xf) && count > 0) { + + for (; ((uintptr_t)buffer & 0xf) && i < count; ++i) *buffer++ = qConvertA2rgb30ToRgb64<PixelOrder>(*src++); - i++; - } + for (; i < count-3; i += 4) { __m128i vs = _mm_loadu_si128((const __m128i*)src); src += 4; diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp index 0f81f09f60..47483b2869 100644 --- a/src/gui/painting/qpdf.cpp +++ b/src/gui/painting/qpdf.cpp @@ -377,8 +377,8 @@ QByteArray QPdf::generateDashes(const QPen &pen) s << dw; } s << ']'; - //qDebug() << "dasharray: pen has" << dasharray; - //qDebug() << " => " << result; + s << pen.dashOffset() * w; + s << " d\n"; return result; } @@ -1209,7 +1209,7 @@ void QPdfEngine::setPen() } *d->currentPage << pdfJoinStyle << "j "; - *d->currentPage << QPdf::generateDashes(d->pen) << " 0 d\n"; + *d->currentPage << QPdf::generateDashes(d->pen); } diff --git a/src/gui/painting/qplatformbackingstore.cpp b/src/gui/painting/qplatformbackingstore.cpp index c86fdebea5..dd02e24676 100644 --- a/src/gui/painting/qplatformbackingstore.cpp +++ b/src/gui/painting/qplatformbackingstore.cpp @@ -48,6 +48,16 @@ #include <qpa/qplatformgraphicsbuffer.h> #include <qpa/qplatformgraphicsbufferhelper.h> +#ifndef GL_TEXTURE_BASE_LEVEL +#define GL_TEXTURE_BASE_LEVEL 0x813C +#endif +#ifndef GL_TEXTURE_MAX_LEVEL +#define GL_TEXTURE_MAX_LEVEL 0x813D +#endif +#ifndef GL_UNPACK_ROW_LENGTH +#define GL_UNPACK_ROW_LENGTH 0x0CF2 +#endif + QT_BEGIN_NAMESPACE class QPlatformBackingStorePrivate @@ -311,12 +321,11 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®i funcs->glDeleteTextures(1, &d_ptr->textureId); funcs->glGenTextures(1, &d_ptr->textureId); funcs->glBindTexture(GL_TEXTURE_2D, d_ptr->textureId); -#ifndef QT_OPENGL_ES_2 - if (!QOpenGLContext::currentContext()->isOpenGLES()) { + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) { funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); } -#endif funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -435,18 +444,16 @@ GLuint QPlatformBackingStore::toTexture(const QRegion &dirtyRegion, QSize *textu image = image.convertToFormat(QImage::Format_RGBA8888); QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); - if (resized) { if (d_ptr->textureId) funcs->glDeleteTextures(1, &d_ptr->textureId); funcs->glGenTextures(1, &d_ptr->textureId); funcs->glBindTexture(GL_TEXTURE_2D, d_ptr->textureId); -#ifndef QT_OPENGL_ES_2 - if (!QOpenGLContext::currentContext()->isOpenGLES()) { + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) { funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); } -#endif funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -459,15 +466,13 @@ GLuint QPlatformBackingStore::toTexture(const QRegion &dirtyRegion, QSize *textu QRect imageRect = image.rect(); QRect rect = dirtyRegion.boundingRect() & imageRect; -#ifndef QT_OPENGL_ES_2 - if (!QOpenGLContext::currentContext()->isOpenGLES()) { + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) { funcs->glPixelStorei(GL_UNPACK_ROW_LENGTH, image.width()); funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, image.constScanLine(rect.y()) + rect.x() * 4); funcs->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - } else -#endif - { + } else { // if the rect is wide enough it's cheaper to just // extend it instead of doing an image copy if (rect.width() >= imageRect.width() / 2) { diff --git a/src/gui/text/qtextimagehandler.cpp b/src/gui/text/qtextimagehandler.cpp index 54d7fe1738..686a00e42a 100644 --- a/src/gui/text/qtextimagehandler.cpp +++ b/src/gui/text/qtextimagehandler.cpp @@ -45,6 +45,7 @@ QT_BEGIN_NAMESPACE +extern QString qt_findAtNxFile(const QString &baseFileName, qreal targetDevicePixelRatio); static QString resolveFileName(QString fileName, QUrl *url, qreal targetDevicePixelRatio) { // We might use the fileName for loading if url loading fails @@ -63,19 +64,8 @@ static QString resolveFileName(QString fileName, QUrl *url, qreal targetDevicePi if (targetDevicePixelRatio <= 1.0) return fileName; - // try to find a 2x version - - const int dotIndex = fileName.lastIndexOf(QLatin1Char('.')); - if (dotIndex != -1) { - QString at2xfileName = fileName; - at2xfileName.insert(dotIndex, QStringLiteral("@2x")); - if (QFile::exists(at2xfileName)) { - fileName = at2xfileName; - *url = QUrl(fileName); - } - } - - return fileName; + // try to find a Nx version + return qt_findAtNxFile(fileName, targetDevicePixelRatio); } diff --git a/src/gui/util/qdesktopservices.cpp b/src/gui/util/qdesktopservices.cpp index 4c92e5d000..354dfeb78c 100644 --- a/src/gui/util/qdesktopservices.cpp +++ b/src/gui/util/qdesktopservices.cpp @@ -231,13 +231,13 @@ void QDesktopServices::setUrlHandler(const QString &scheme, QObject *receiver, c QOpenUrlHandlerRegistry *registry = handlerRegistry(); QMutexLocker locker(®istry->mutex); if (!receiver) { - registry->handlers.remove(scheme); + registry->handlers.remove(scheme.toLower()); return; } QOpenUrlHandlerRegistry::Handler h; h.receiver = receiver; h.name = method; - registry->handlers.insert(scheme, h); + registry->handlers.insert(scheme.toLower(), h); QObject::connect(receiver, SIGNAL(destroyed(QObject*)), registry, SLOT(handlerDestroyed(QObject*))); } |