diff options
32 files changed, 526 insertions, 80 deletions
diff --git a/examples/quick/demos/samegame/content/samegame.js b/examples/quick/demos/samegame/content/samegame.js index 99154320ca..99154320ca 100755..100644 --- a/examples/quick/demos/samegame/content/samegame.js +++ b/examples/quick/demos/samegame/content/samegame.js diff --git a/examples/quick/particles/images/backgroundLeaves.jpg b/examples/quick/particles/images/backgroundLeaves.jpg Binary files differindex 08be16751d..08be16751d 100755..100644 --- a/examples/quick/particles/images/backgroundLeaves.jpg +++ b/examples/quick/particles/images/backgroundLeaves.jpg diff --git a/examples/quick/touchinteraction/flickable/content/Panel.qml b/examples/quick/touchinteraction/flickable/content/Panel.qml index a144c347e1..b2926f8098 100644 --- a/examples/quick/touchinteraction/flickable/content/Panel.qml +++ b/examples/quick/touchinteraction/flickable/content/Panel.qml @@ -116,7 +116,7 @@ Component { drag.maximumY: page.height - 80 drag.minimumX: 100 drag.maximumX: page.width - 140 - onClicked: { myText.focus = true; Qt.inputMethod.show(); } + onClicked: myText.forceActiveFocus() } } } diff --git a/examples/quick/tutorials/samegame/samegame4/highscores/score_data.xml b/examples/quick/tutorials/samegame/samegame4/highscores/score_data.xml index c3fd90d9cf..c3fd90d9cf 100755..100644 --- a/examples/quick/tutorials/samegame/samegame4/highscores/score_data.xml +++ b/examples/quick/tutorials/samegame/samegame4/highscores/score_data.xml diff --git a/examples/quick/tutorials/samegame/samegame4/highscores/score_style.xsl b/examples/quick/tutorials/samegame/samegame4/highscores/score_style.xsl index 670354c965..670354c965 100755..100644 --- a/examples/quick/tutorials/samegame/samegame4/highscores/score_style.xsl +++ b/examples/quick/tutorials/samegame/samegame4/highscores/score_style.xsl diff --git a/examples/quick/tutorials/samegame/samegame4/highscores/scores.php b/examples/quick/tutorials/samegame/samegame4/highscores/scores.php index 86e4187acd..86e4187acd 100755..100644 --- a/examples/quick/tutorials/samegame/samegame4/highscores/scores.php +++ b/examples/quick/tutorials/samegame/samegame4/highscores/scores.php diff --git a/src/imports/models/plugin.cpp b/src/imports/models/plugin.cpp index c0877be967..82c64764d8 100644 --- a/src/imports/models/plugin.cpp +++ b/src/imports/models/plugin.cpp @@ -38,7 +38,7 @@ QT_BEGIN_NAMESPACE /*! - \qmlmodule QtQml.Models 2 + \qmlmodule QtQml.Models 2.1 \title Qt QML Models QML Types \ingroup qmlmodules \brief Provides QML types for data models diff --git a/src/imports/qtquick2/plugin.cpp b/src/imports/qtquick2/plugin.cpp index d5096fc6e8..ad3db2290f 100644 --- a/src/imports/qtquick2/plugin.cpp +++ b/src/imports/qtquick2/plugin.cpp @@ -49,6 +49,11 @@ public: Q_UNUSED(uri); QQmlQtQuick2Module::defineModule(); } + + ~QtQuick2Plugin() + { + QQmlQtQuick2Module::undefineModule(); + } }; //![class decl] diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index 3a27a859fd..8edf4bbe7c 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -1389,7 +1389,7 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI if (!mo) continue; - static QQmlType *componentType = QQmlMetaType::qmlType(&QQmlComponent::staticMetaObject); + QQmlType *componentType = QQmlMetaType::qmlType(&QQmlComponent::staticMetaObject); Q_ASSERT(componentType); QmlIR::Object *syntheticComponent = pool->New<QmlIR::Object>(); diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index 74530e7ae9..6d95f039c5 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -73,11 +73,6 @@ struct Q_QML_EXPORT ExecutionContext : public Managed Type_CallContext = 0x5, Type_QmlContext = 0x6 }; - struct EvalCode - { - Function *function; - EvalCode *next; - }; struct Data : Managed::Data { Data(ExecutionEngine *engine, ContextType t) @@ -89,7 +84,6 @@ struct Q_QML_EXPORT ExecutionContext : public Managed , outer(0) , lookups(0) , compilationUnit(0) - , currentEvalCode(0) , lineNumber(-1) { engine->current = reinterpret_cast<ExecutionContext *>(this); @@ -104,7 +98,6 @@ struct Q_QML_EXPORT ExecutionContext : public Managed ExecutionContext *outer; Lookup *lookups; CompiledData::CompilationUnit *compilationUnit; - EvalCode *currentEvalCode; int lineNumber; @@ -122,7 +115,6 @@ struct Q_QML_EXPORT ExecutionContext : public Managed d()->outer = 0; d()->lookups = 0; d()->compilationUnit = 0; - d()->currentEvalCode = 0; d()->lineNumber = -1; engine->current = this; } @@ -238,7 +230,6 @@ inline void ExecutionEngine::pushContext(CallContext *context) { context->d()->parent = current; current = context; - current->d()->currentEvalCode = 0; } inline ExecutionContext *ExecutionEngine::popContext() diff --git a/src/qml/jsruntime/qv4debugging.cpp b/src/qml/jsruntime/qv4debugging.cpp index bcf0d07719..6a8d364a08 100644 --- a/src/qml/jsruntime/qv4debugging.cpp +++ b/src/qml/jsruntime/qv4debugging.cpp @@ -49,25 +49,36 @@ namespace { class JavaScriptJob: public Debugger::Job { QV4::ExecutionEngine *engine; + int frameNr; const QString &script; public: - JavaScriptJob(QV4::ExecutionEngine *engine, const QString &script) + JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr, const QString &script) : engine(engine) + , frameNr(frameNr) , script(script) {} void run() { - QV4::Scope scope(engine); - QV4::ExecutionContext *ctx = engine->currentContext(); - ContextStateSaver ctxSaver(ctx); - QV4::ScopedValue result(scope); + Scope scope(engine); + + ExecutionContextSaver saver(engine->currentContext()); + + Value *savedContexts = scope.alloc(frameNr); + for (int i = 0; i < frameNr; ++i) { + savedContexts[i] = engine->currentContext(); + engine->popContext(); + } + ExecutionContext *ctx = engine->currentContext(); QV4::Script script(ctx, this->script); script.strictMode = ctx->d()->strictMode; - script.inheritContext = false; + // In order for property lookups in QML to work, we need to disable fast v4 lookups. That + // is a side-effect of inheritContext. + script.inheritContext = true; script.parse(); + QV4::ScopedValue result(scope); if (!scope.engine->hasException) result = script.run(); if (scope.engine->hasException) @@ -85,7 +96,7 @@ class EvalJob: public JavaScriptJob public: EvalJob(QV4::ExecutionEngine *engine, const QString &script) - : JavaScriptJob(engine, script) + : JavaScriptJob(engine, /*frameNr*/-1, script) , result(false) {} @@ -105,8 +116,8 @@ class ExpressionEvalJob: public JavaScriptJob Debugger::Collector *collector; public: - ExpressionEvalJob(ExecutionEngine *engine, const QString &expression, Debugger::Collector *collector) - : JavaScriptJob(engine, expression) + ExpressionEvalJob(ExecutionEngine *engine, int frameNr, const QString &expression, Debugger::Collector *collector) + : JavaScriptJob(engine, frameNr, expression) , collector(collector) { } @@ -486,13 +497,10 @@ QVector<ExecutionContext::ContextType> Debugger::getScopeTypes(int frame) const void Debugger::evaluateExpression(int frameNr, const QString &expression, Debugger::Collector *resultsCollector) { Q_ASSERT(state() == Paused); - Q_UNUSED(frameNr); Q_ASSERT(m_runningJob == 0); - ExpressionEvalJob job(m_engine, expression, resultsCollector); - m_runningJob = &job; - m_runningJob->run(); - m_runningJob = 0; + ExpressionEvalJob job(m_engine, frameNr, expression, resultsCollector); + runInEngine(&job); } void Debugger::maybeBreakAtInstruction() diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp index 49032e5bcf..9a9de8bb41 100644 --- a/src/qml/jsruntime/qv4globalobject.cpp +++ b/src/qml/jsruntime/qv4globalobject.cpp @@ -395,11 +395,6 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) ContextStateSaver stateSaver(ctx); - ExecutionContext::EvalCode evalCode; - evalCode.function = function; - evalCode.next = ctx->d()->currentEvalCode; - ctx->d()->currentEvalCode = &evalCode; - // set the correct strict mode flag on the context ctx->d()->strictMode = strictMode(); ctx->d()->compilationUnit = function->compilationUnit; diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h index 29d2bc6193..dfbf04a50f 100644 --- a/src/qml/qml/qqmlprivate.h +++ b/src/qml/qml/qqmlprivate.h @@ -122,12 +122,12 @@ namespace QQmlPrivate typedef int yes_type; typedef char no_type; - static yes_type check(To *); - static no_type check(...); + static yes_type checkType(To *); + static no_type checkType(...); static inline int cast() { - return StaticCastSelectorClass<From, To, sizeof(check(reinterpret_cast<From *>(0)))>::cast(); + return StaticCastSelectorClass<From, To, sizeof(checkType(reinterpret_cast<From *>(0)))>::cast(); } }; @@ -145,10 +145,10 @@ namespace QQmlPrivate typedef char no_type; template<typename ReturnType> - static yes_type check(ReturnType *(*)(QObject *)); - static no_type check(...); + static yes_type checkType(ReturnType *(*)(QObject *)); + static no_type checkType(...); - static bool const value = sizeof(check(&T::qmlAttachedProperties)) == sizeof(yes_type); + static bool const value = sizeof(checkType(&T::qmlAttachedProperties)) == sizeof(yes_type); }; template <typename T> diff --git a/src/quick/items/qquickanimatedsprite.cpp b/src/quick/items/qquickanimatedsprite.cpp index f1201cf549..5ca17aecec 100644 --- a/src/quick/items/qquickanimatedsprite.cpp +++ b/src/quick/items/qquickanimatedsprite.cpp @@ -625,8 +625,25 @@ void QQuickAnimatedSprite::prepareNextFrame() qreal w = m_spriteEngine->spriteWidth() / m_sheetSize.width(); qreal h = m_spriteEngine->spriteHeight() / m_sheetSize.height(); - qreal x1 = m_spriteEngine->spriteX() / m_sheetSize.width() + frameAt * w; - qreal y1 = m_spriteEngine->spriteY() / m_sheetSize.height(); + qreal x1; + qreal y1; + if (m_paused) { + int spriteY = m_spriteEngine->spriteY(); + if (reverse) { + int rows = m_spriteEngine->maxFrames() * m_spriteEngine->spriteWidth() / m_sheetSize.width(); + spriteY -= rows * m_spriteEngine->spriteHeight(); + frameAt = (frameCount - 1) - frameAt; + } + + int position = frameAt * m_spriteEngine->spriteWidth() + m_spriteEngine->spriteX(); + int row = position / m_sheetSize.width(); + + x1 = (position - (row * m_sheetSize.width())) / m_sheetSize.width(); + y1 = (row * m_spriteEngine->spriteHeight() + spriteY) / m_sheetSize.height(); + } else { + x1 = m_spriteEngine->spriteX() / m_sheetSize.width() + frameAt * w; + y1 = m_spriteEngine->spriteY() / m_sheetSize.height(); + } //### hard-coded 0/1 work because we are the only // images in the sprite sheet (without this we cannot assume diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 825dd8ddfa..2722f48ce9 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -2481,7 +2481,7 @@ void QQuickItem::setParentItem(QQuickItem *parentItem) return; if (parentItem) { - QQuickItem *itemAncestor = parentItem->parentItem(); + QQuickItem *itemAncestor = parentItem; while (itemAncestor != 0) { if (itemAncestor == this) { qWarning("QQuickItem::setParentItem: Parent is already part of this items subtree."); diff --git a/src/quick/items/qquickrendercontrol.cpp b/src/quick/items/qquickrendercontrol.cpp index 7ccd3a0fb4..a666bb59c9 100644 --- a/src/quick/items/qquickrendercontrol.cpp +++ b/src/quick/items/qquickrendercontrol.cpp @@ -106,7 +106,7 @@ extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_ rendered by calling render(). After making the context current, applications are expected to call render(). - \li QQuickRenderControl::sceneChanged() Inidcates that the scene has changed + \li QQuickRenderControl::sceneChanged() Indicates that the scene has changed meaning that, before rendering, polishing and synchronizing is also necessary. \endlist @@ -172,6 +172,10 @@ void QQuickRenderControlPrivate::windowDestroyed() /*! Initializes the scene graph resources. The context \a gl has to be the current context. + + \note Qt Quick does not take ownership of the context. It is up to the + application to destroy it after a call to invalidate() or after the + QQuickRenderControl instance is destroyed. */ void QQuickRenderControl::initialize(QOpenGLContext *gl) { @@ -274,7 +278,6 @@ void QQuickRenderControl::invalidate() // application right after returning from this function. Invalidating is // also essential to allow a subsequent initialize() to succeed. d->rc->invalidate(); - QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); d->initialized = false; } @@ -296,6 +299,10 @@ void QQuickRenderControl::render() \fn void QQuickRenderControl::renderRequested() This signal is emitted when the scene graph needs to be rendered. It is not necessary to call sync(). + + \note Avoid triggering rendering directly when this signal is + emitted. Instead, prefer deferring it by using a timer for example. This + will lead to better performance. */ /*! @@ -304,6 +311,10 @@ void QQuickRenderControl::render() This signal is emitted when the scene graph is updated, meaning that polishItems() and sync() needs to be called. If sync() returns true, then render() needs to be called. + + \note Avoid triggering polishing, synchronization and rendering directly + when this signal is emitted. Instead, prefer deferring it by using a timer + for example. This will lead to better performance. */ /*! diff --git a/src/quick/items/qquickview.cpp b/src/quick/items/qquickview.cpp index a55d056c75..b5b542a791 100644 --- a/src/quick/items/qquickview.cpp +++ b/src/quick/items/qquickview.cpp @@ -379,10 +379,6 @@ QList<QQmlError> QQuickView::errors() const If this property is set to SizeRootObjectToView, the view will automatically resize the root item to the size of the view. - Regardless of this property, the sizeHint of the view - is the initial size of the root item. Note though that - since QML may load dynamically, that size may change. - \sa initialSize() */ diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 10e63430ae..359f68a114 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -968,10 +968,10 @@ void QQuickWindowPrivate::cleanup(QSGNode *n) Alternatively you can set or bind \l x and \l y to position the Window explicitly on the screen. - When the user attempts to close a window, the \a closing signal will be + When the user attempts to close a window, the \l closing signal will be emitted. You can force the window to stay open (for example to prompt the - user to save changes) by writing an onClosing handler and setting - close.accepted = false. + user to save changes) by writing an \c onClosing handler and setting + \c {close.accepted = false}. */ /*! \class QQuickWindow @@ -1796,7 +1796,9 @@ void QQuickWindowPrivate::deliverTouchEvent(QTouchEvent *event) if (!delayedTouch) { delayedTouch = new QTouchEvent(event->type(), event->device(), event->modifiers(), event->touchPointStates(), event->touchPoints()); delayedTouch->setTimestamp(event->timestamp()); - if (windowManager) + if (renderControl) + QQuickRenderControlPrivate::get(renderControl)->maybeUpdate(); + else if (windowManager) windowManager->maybeUpdate(q); return; } else { @@ -3003,7 +3005,7 @@ QOpenGLContext *QQuickWindow::openglContext() const \since 5.1 Notification that a window is about to be closed by the windowing system - (e.g. the user clicked the titlebar close button). The CloseEvent contains + (e.g. the user clicked the title bar close button). The CloseEvent contains an accepted property which can be set to false to abort closing the window. \sa Window.closing() @@ -3030,9 +3032,9 @@ QOpenGLContext *QQuickWindow::openglContext() const This signal is emitted when the user tries to close the window. - This signal includes a closeEvent parameter. The \a close \l accepted + This signal includes a \a close parameter. The \a close \l accepted property is true by default so that the window is allowed to close; but you - can implement an onClosing() handler and set close.accepted = false if + can implement an \c onClosing handler and set \c {close.accepted = false} if you need to do something else before the window can be closed. The corresponding handler is \c onClosing. @@ -3714,7 +3716,7 @@ void QQuickWindow::resetOpenGLState() Whether the window is visible on the screen. - Setting visible to false is the same as setting \l visibility to Hidden. + Setting visible to false is the same as setting \l visibility to \l {QWindow::}{Hidden}. \sa visibility */ @@ -3727,13 +3729,14 @@ void QQuickWindow::resetOpenGLState() Visibility is whether the window should appear in the windowing system as normal, minimized, maximized, fullscreen or hidden. - To set the visibility to AutomaticVisibility means to give the window a - default visible state, which might be fullscreen or windowed depending on - the platform. However when reading the visibility property you will always - get the actual state, never AutomaticVisibility. + To set the visibility to \l {QWindow::}{AutomaticVisibility} means to give the + window a default visible state, which might be \l {QWindow::}{FullScreen} or + \l {QWindow::}{Windowed} depending on the platform. However when reading the + visibility property you will always get the actual state, never + \c AutomaticVisibility. When a window is not visible its visibility is Hidden, and setting - visibility to Hidden is the same as setting \l visible to false. + visibility to \l {QWindow::}{Hidden} is the same as setting \l visible to \c false. \sa visible \since 5.1 @@ -3745,7 +3748,7 @@ void QQuickWindow::resetOpenGLState() This attached property holds whether the window is currently shown in the windowing system as normal, minimized, maximized, fullscreen or - hidden. The Window attached property can be attached to any Item. If the + hidden. The \c Window attached property can be attached to any Item. If the item is not shown in any window, the value will be \l {QWindow::}{Hidden}. \sa visible, visibility @@ -3846,12 +3849,94 @@ void QQuickWindow::resetOpenGLState() \qmlmethod QtQuick::Window::alert(int msec) \since 5.1 - Causes an alert to be shown for \a msec miliseconds. If \a msec is \c 0 (the - default), then the alert is shown indefinitely until the window becomes - active again. + Causes an alert to be shown for \a msec milliseconds. If \a msec is \c 0 + (the default), then the alert is shown indefinitely until the window + becomes active again. - In alert state, the window indicates that it demands attention, for example by - flashing or bouncing the taskbar entry. + In alert state, the window indicates that it demands attention, for example + by flashing or bouncing the taskbar entry. +*/ + +/*! + \qmlmethod QtQuick::Window::close() + + Closes the window. + + When this method is called, or when the user tries to close the window by + its title bar button, the \l closing signal will be emitted. If there is no + handler, or the handler does not revoke permission to close, the window + will subsequently close. If the QGuiApplication::quitOnLastWindowClosed + property is \c true, and there are no other windows open, the application + will quit. +*/ + +/*! + \qmlmethod QtQuick::Window::raise() + + Raises the window in the windowing system. + + Requests that the window be raised to appear above other windows. +*/ + +/*! + \qmlmethod QtQuick::Window::lower() + + Lowers the window in the windowing system. + + Requests that the window be lowered to appear below other windows. +*/ + +/*! + \qmlmethod QtQuick::Window::show() + + Shows the window. + + This is equivalent to calling showFullScreen(), showMaximized(), or showNormal(), + depending on the platform's default behavior for the window type and flags. + + \sa showFullScreen(), showMaximized(), showNormal(), hide(), flags() +*/ + +/*! + \qmlmethod QtQuick::Window::hide() + + Hides the window. + + Equivalent to setting \l visible to \c false or \l visibility to \l {QWindow::}{Hidden}. + + \sa show() +*/ + +/*! + \qmlmethod QtQuick::Window::showMinimized() + + Shows the window as minimized. + + Equivalent to setting \l visibility to \l {QWindow::}{Minimized}. +*/ + +/*! + \qmlmethod QtQuick::Window::showMaximized() + + Shows the window as maximized. + + Equivalent to setting \l visibility to \l {QWindow::}{Maximized}. +*/ + +/*! + \qmlmethod QtQuick::Window::showFullScreen() + + Shows the window as fullscreen. + + Equivalent to setting \l visibility to \l {QWindow::}{FullScreen}. +*/ + +/*! + \qmlmethod QtQuick::Window::showNormal() + + Shows the window as normal, i.e. neither maximized, minimized, nor fullscreen. + + Equivalent to setting \l visibility to \l {QWindow::}{Windowed}. */ /*! @@ -3870,7 +3955,7 @@ void QQuickWindow::resetOpenGLState() /*! \since 5.4 - Schedule \a job to run when the rendering of this window reaches + Schedules \a job to run when the rendering of this window reaches the given \a stage. This is a convenience to the equivalent signals in QQuickWindow for diff --git a/src/quick/qtquick2.cpp b/src/quick/qtquick2.cpp index 6acff85961..09784d161a 100644 --- a/src/quick/qtquick2.cpp +++ b/src/quick/qtquick2.cpp @@ -194,5 +194,10 @@ void QQmlQtQuick2Module::defineModule() } } +void QQmlQtQuick2Module::undefineModule() +{ + QQuick_deinitializeProviders(); +} + QT_END_NAMESPACE diff --git a/src/quick/qtquick2_p.h b/src/quick/qtquick2_p.h index 2847d5d3ff..8f415cbd02 100644 --- a/src/quick/qtquick2_p.h +++ b/src/quick/qtquick2_p.h @@ -42,6 +42,7 @@ class Q_QUICK_PRIVATE_EXPORT QQmlQtQuick2Module { public: static void defineModule(); + static void undefineModule(); }; QT_END_NAMESPACE diff --git a/src/quick/qtquickglobal_p.h b/src/quick/qtquickglobal_p.h index e2bf198b1c..7fe09da92e 100644 --- a/src/quick/qtquickglobal_p.h +++ b/src/quick/qtquickglobal_p.h @@ -54,6 +54,7 @@ QT_BEGIN_NAMESPACE void QQuick_initializeProviders(); +void QQuick_deinitializeProviders(); Q_DECLARE_LOGGING_CATEGORY(DBG_TOUCH) Q_DECLARE_LOGGING_CATEGORY(DBG_MOUSE) diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp index 90102f1110..99695f058f 100644 --- a/src/quick/scenegraph/qsgcontext.cpp +++ b/src/quick/scenegraph/qsgcontext.cpp @@ -357,7 +357,7 @@ void QSGContext::renderContextInitialized(QSGRenderContext *renderContext) // before without a context. Now the context is ready. if (!d->distanceFieldAntialiasingDecided) { d->distanceFieldAntialiasingDecided = true; -#ifndef Q_OS_WIN +#ifndef Q_OS_WIN32 if (renderContext->openglContext()->isOpenGLES()) d->distanceFieldAntialiasing = QSGGlyphNode::GrayAntialiasing; #endif diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp index 093e84b618..3d958245d2 100644 --- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp +++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp @@ -48,6 +48,10 @@ QT_BEGIN_NAMESPACE DEFINE_BOOL_CONFIG_OPTION(qmlUseGlyphCacheWorkaround, QML_USE_GLYPHCACHE_WORKAROUND) +#if !defined(QSG_DEFAULT_DISTANCEFIELD_GLYPH_CACHE_PADDING) +# define QSG_DEFAULT_DISTANCEFIELD_GLYPH_CACHE_PADDING 2 +#endif + QSGDefaultDistanceFieldGlyphCache::QSGDefaultDistanceFieldGlyphCache(QSGDistanceFieldGlyphCacheManager *man, QOpenGLContext *c, const QRawFont &font) : QSGDistanceFieldGlyphCache(man, c, font) , m_maxTextureSize(0) @@ -90,8 +94,9 @@ void QSGDefaultDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyph for (QSet<glyph_t>::const_iterator it = glyphs.constBegin(); it != glyphs.constEnd() ; ++it) { glyph_t glyphIndex = *it; + int padding = QSG_DEFAULT_DISTANCEFIELD_GLYPH_CACHE_PADDING; int glyphWidth = qCeil(glyphData(glyphIndex).boundingRect.width()) + distanceFieldRadius() * 2; - QSize glyphSize(glyphWidth, QT_DISTANCEFIELD_TILESIZE(doubleGlyphResolution())); + QSize glyphSize(glyphWidth + padding * 2, QT_DISTANCEFIELD_TILESIZE(doubleGlyphResolution()) + padding * 2); QRect alloc = m_areaAllocator->allocate(glyphSize); if (alloc.isNull()) { @@ -101,7 +106,10 @@ void QSGDefaultDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyph TexCoord unusedCoord = glyphTexCoord(unusedGlyph); int unusedGlyphWidth = qCeil(glyphData(unusedGlyph).boundingRect.width()) + distanceFieldRadius() * 2; - m_areaAllocator->deallocate(QRect(unusedCoord.x, unusedCoord.y, unusedGlyphWidth, QT_DISTANCEFIELD_TILESIZE(doubleGlyphResolution()))); + m_areaAllocator->deallocate(QRect(unusedCoord.x - padding, + unusedCoord.y - padding, + padding * 2 + unusedGlyphWidth, + padding * 2 + QT_DISTANCEFIELD_TILESIZE(doubleGlyphResolution()))); m_unusedGlyphs.remove(unusedGlyph); m_glyphsTexture.remove(unusedGlyph); @@ -117,11 +125,14 @@ void QSGDefaultDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyph TextureInfo *tex = textureInfo(alloc.y() / maxTextureSize()); alloc = QRect(alloc.x(), alloc.y() % maxTextureSize(), alloc.width(), alloc.height()); + tex->allocatedArea |= alloc; + Q_ASSERT(tex->padding == padding || tex->padding < 0); + tex->padding = padding; GlyphPosition p; p.glyph = glyphIndex; - p.position = alloc.topLeft(); + p.position = alloc.topLeft() + QPoint(padding, padding); glyphPositions.append(p); glyphsToRender.append(glyphIndex); @@ -153,13 +164,14 @@ void QSGDefaultDistanceFieldGlyphCache::storeGlyphs(const QList<QDistanceField> glyphTextures[texInfo].append(glyphIndex); + int padding = texInfo->padding; int expectedWidth = qCeil(c.width + c.xMargin * 2); - if (glyph.width() != expectedWidth) - glyph = glyph.copy(0, 0, expectedWidth, glyph.height()); + glyph = glyph.copy(-padding, -padding, + expectedWidth + padding * 2, glyph.height() + padding * 2); if (useTextureResizeWorkaround()) { uchar *inBits = glyph.scanLine(0); - uchar *outBits = texInfo->image.scanLine(int(c.y)) + int(c.x); + uchar *outBits = texInfo->image.scanLine(int(c.y) - padding) + int(c.x) - padding; for (int y = 0; y < glyph.height(); ++y) { memcpy(outBits, inBits, glyph.width()); inBits += glyph.width(); @@ -175,13 +187,13 @@ void QSGDefaultDistanceFieldGlyphCache::storeGlyphs(const QList<QDistanceField> if (useTextureUploadWorkaround()) { for (int i = 0; i < glyph.height(); ++i) { m_funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, - c.x, c.y + i, glyph.width(),1, + c.x - padding, c.y + i - padding, glyph.width(),1, format, GL_UNSIGNED_BYTE, glyph.scanLine(i)); } } else { m_funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, - c.x, c.y, glyph.width(), glyph.height(), + c.x - padding, c.y - padding, glyph.width(), glyph.height(), format, GL_UNSIGNED_BYTE, glyph.constBits()); } diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h index f7314776d6..2f9331f6d8 100644 --- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h +++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h @@ -73,8 +73,9 @@ private: QSize size; QRect allocatedArea; QDistanceField image; + int padding; - TextureInfo() : texture(0) + TextureInfo() : texture(0), padding(-1) { } }; diff --git a/src/quick/scenegraph/util/qsgsimpletexturenode.cpp b/src/quick/scenegraph/util/qsgsimpletexturenode.cpp index 1e7133cf26..1fbeba83bc 100644 --- a/src/quick/scenegraph/util/qsgsimpletexturenode.cpp +++ b/src/quick/scenegraph/util/qsgsimpletexturenode.cpp @@ -260,6 +260,8 @@ QSGSimpleTextureNode::TextureCoordinatesTransformMode QSGSimpleTextureNode::text By default, the node does not take ownership of the texture. \sa setTexture() + + \since 5.4 */ void QSGSimpleTextureNode::setOwnsTexture(bool owns) { @@ -269,6 +271,8 @@ void QSGSimpleTextureNode::setOwnsTexture(bool owns) /*! Returns \c true if the node takes ownership of the texture; otherwise returns \c false. + + \since 5.4 */ bool QSGSimpleTextureNode::ownsTexture() const { diff --git a/src/quick/util/qquickglobal.cpp b/src/quick/util/qquickglobal.cpp index 455e180dbe..139bae4038 100644 --- a/src/quick/util/qquickglobal.cpp +++ b/src/quick/util/qquickglobal.cpp @@ -982,4 +982,11 @@ void QQuick_initializeProviders() QQml_setGuiProvider(getGuiProvider()); } +void QQuick_deinitializeProviders() +{ + QQml_removeValueTypeProvider(getValueTypeProvider()); + QQml_setColorProvider(0); // technically, another plugin may have overridden our providers + QQml_setGuiProvider(0); // but we cannot handle that case in a sane way. +} + QT_END_NAMESPACE diff --git a/tests/auto/qml/qqmlenginecleanup/data/testFile1.qml b/tests/auto/qml/qqmlenginecleanup/data/testFile1.qml new file mode 100644 index 0000000000..3bd8e22ce4 --- /dev/null +++ b/tests/auto/qml/qqmlenginecleanup/data/testFile1.qml @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Item { + Item { + id: c1 + } + property Item a: c1 +} diff --git a/tests/auto/qml/qqmlenginecleanup/data/testFile2.qml b/tests/auto/qml/qqmlenginecleanup/data/testFile2.qml new file mode 100644 index 0000000000..9a32114918 --- /dev/null +++ b/tests/auto/qml/qqmlenginecleanup/data/testFile2.qml @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Item { + property variant a: Qt.rgba(0.3, 0.4, 0.5, 0.6) +} diff --git a/tests/auto/qml/qqmlenginecleanup/data/testFile3.qml b/tests/auto/qml/qqmlenginecleanup/data/testFile3.qml new file mode 100644 index 0000000000..c55c355388 --- /dev/null +++ b/tests/auto/qml/qqmlenginecleanup/data/testFile3.qml @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +Item { + width: 320 + height: 480 + + ListView { + anchors.fill: parent + model: simpleModel + delegate: Text { + text: name + } + } + + ListModel { + id: simpleModel + ListElement { + name: "first" + } + ListElement { + name: "second" + } + ListElement { + name: "third" + } + } +} diff --git a/tests/auto/qml/qqmlenginecleanup/tst_qqmlenginecleanup.cpp b/tests/auto/qml/qqmlenginecleanup/tst_qqmlenginecleanup.cpp index fcc3e6a0a9..c8fae624a7 100644 --- a/tests/auto/qml/qqmlenginecleanup/tst_qqmlenginecleanup.cpp +++ b/tests/auto/qml/qqmlenginecleanup/tst_qqmlenginecleanup.cpp @@ -46,6 +46,7 @@ public: private slots: void test_qmlClearTypeRegistrations(); + void test_valueTypeProviderModule(); // QTBUG-43004 }; void tst_qqmlenginecleanup::test_qmlClearTypeRegistrations() @@ -85,6 +86,50 @@ void tst_qqmlenginecleanup::test_qmlClearTypeRegistrations() delete component; } +static void cleanState(QQmlEngine **e) +{ + delete *e; + qmlClearTypeRegistrations(); + *e = new QQmlEngine; + QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + QCoreApplication::processEvents(); +} + +void tst_qqmlenginecleanup::test_valueTypeProviderModule() +{ + // this test ensures that a module which installs a value type + // provider can be reinitialized after multiple calls to + // qmlClearTypeRegistrations() without causing cycles in the + // value type provider list. + QQmlEngine *e = 0; + QUrl testFile1 = testFileUrl("testFile1.qml"); + QUrl testFile2 = testFileUrl("testFile2.qml"); + bool noCycles = false; + for (int i = 0; i < 20; ++i) { + cleanState(&e); + QQmlComponent c(e, this); + c.loadUrl(i % 2 == 0 ? testFile1 : testFile2); // this will hang if cycles exist. + } + delete e; + e = 0; + noCycles = true; + QVERIFY(noCycles); + + // this test ensures that no crashes occur due to using + // a dangling QQmlType pointer in the type compiler + // which results from qmlClearTypeRegistrations() + QUrl testFile3 = testFileUrl("testFile3.qml"); + bool noDangling = false; + for (int i = 0; i < 20; ++i) { + cleanState(&e); + QQmlComponent c(e, this); + c.loadUrl(i % 2 == 0 ? testFile1 : testFile3); // this will crash if dangling ptr exists. + } + delete e; + noDangling = true; + QVERIFY(noDangling); +} + QTEST_MAIN(tst_qqmlenginecleanup) #include "tst_qqmlenginecleanup.moc" diff --git a/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp b/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp index 3fe14fa216..63bfffacaa 100644 --- a/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp +++ b/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp @@ -33,6 +33,8 @@ #include <QtTest/QtTest> #include <QJSEngine> +#include <QQmlEngine> +#include <QQmlComponent> #include <private/qv4engine_p.h> #include <private/qv4debugging_p.h> #include <private/qv8engine_p.h> @@ -182,6 +184,14 @@ public: m_stackTrace = debugger->stackTrace(); + while (!m_expressionRequests.isEmpty()) { + ExpressionRequest request = m_expressionRequests.takeFirst(); + QVariantMap result; + collector.setDestination(&result); + debugger->evaluateExpression(request.frameNr, request.expression, &collector); + m_expressionResults << result[QString::fromLatin1("body")]; + } + if (m_captureContextInfo) captureContextInfo(debugger); @@ -233,6 +243,13 @@ public: QList<QVariantMap> m_capturedLocals; QVariant m_thrownValue; + struct ExpressionRequest { + QString expression; + int frameNr; + }; + QVector<ExpressionRequest> m_expressionRequests; + QVector<QVariant> m_expressionResults; + // Utility methods: void dumpStackTrace() const { @@ -259,6 +276,7 @@ private slots: void addBreakPointWhilePaused(); void removeBreakPointForNextInstruction(); void conditionalBreakPoint(); + void conditionalBreakPointInQml(); // context access: void readArguments(); @@ -269,6 +287,8 @@ private slots: // exceptions: void pauseOnThrow(); + void evaluateExpression(); + private: void evaluateJavaScript(const QString &script, const QString &fileName, int lineNumber = 1) { @@ -428,6 +448,42 @@ void tst_qv4debugger::conditionalBreakPoint() QCOMPARE(m_debuggerAgent->m_capturedLocals[0]["i"].toInt(), 11); } +void tst_qv4debugger::conditionalBreakPointInQml() +{ + QQmlEngine engine; + QV4::ExecutionEngine *v4 = QV8Engine::getV4(&engine); + v4->enableDebugger(); + + QScopedPointer<QThread> debugThread(new QThread); + debugThread->start(); + QScopedPointer<TestAgent> debuggerAgent(new TestAgent); + debuggerAgent->addDebugger(v4->debugger); + debuggerAgent->moveToThread(debugThread.data()); + + QQmlComponent component(&engine); + component.setData("import QtQml 2.0\n" + "QtObject {\n" + " id: root\n" + " property int foo: 42\n" + " property bool success: false\n" + " Component.onCompleted: {\n" + " success = true;\n" // breakpoint here + " }\n" + "}\n", QUrl("test.qml")); + + debuggerAgent->addBreakPoint("test.qml", 7, /*enabled*/true, "root.foo == 42"); + + QScopedPointer<QObject> obj(component.create()); + QCOMPARE(obj->property("success").toBool(), true); + + QCOMPARE(debuggerAgent->m_statesWhenPaused.count(), 1); + QCOMPARE(debuggerAgent->m_statesWhenPaused.at(0).fileName, QStringLiteral("test.qml")); + QCOMPARE(debuggerAgent->m_statesWhenPaused.at(0).lineNumber, 7); + + debugThread->quit(); + debugThread->wait(); +} + void tst_qv4debugger::readArguments() { m_debuggerAgent->m_captureContextInfo = true; @@ -556,6 +612,33 @@ void tst_qv4debugger::pauseOnThrow() QCOMPARE(m_debuggerAgent->m_thrownValue.toString(), QString("hard")); } +void tst_qv4debugger::evaluateExpression() +{ + QString script = + "function testFunction() {\n" + " var x = 10\n" + " return x\n" // breakpoint + "}\n" + "var x = 20\n" + "testFunction()\n"; + + TestAgent::ExpressionRequest request; + request.expression = "x"; + request.frameNr = 0; + m_debuggerAgent->m_expressionRequests << request; + request.expression = "x"; + request.frameNr = 1; + m_debuggerAgent->m_expressionRequests << request; + + m_debuggerAgent->addBreakPoint("evaluateExpression", 3); + + evaluateJavaScript(script, "evaluateExpression"); + + QCOMPARE(m_debuggerAgent->m_expressionResults.count(), 2); + QCOMPARE(m_debuggerAgent->m_expressionResults[0].toInt(), 10); + QCOMPARE(m_debuggerAgent->m_expressionResults[1].toInt(), 20); +} + QTEST_MAIN(tst_qv4debugger) #include "tst_qv4debugger.moc" diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp index 26819ff48b..a3d902a054 100644 --- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp +++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp @@ -91,12 +91,17 @@ private slots: void stopAtBounds_data(); void nestedMouseAreaUsingTouch(); void pressDelayWithLoader(); + void cleanup(); private: void flickWithTouch(QQuickWindow *window, QTouchDevice *touchDevice, const QPoint &from, const QPoint &to); - QQmlEngine engine; }; +void tst_qquickflickable::cleanup() +{ + QVERIFY(QGuiApplication::topLevelWindows().isEmpty()); +} + void tst_qquickflickable::create() { QQmlEngine engine; @@ -199,6 +204,7 @@ void tst_qquickflickable::properties() void tst_qquickflickable::boundsBehavior() { + QQmlEngine engine; QQmlComponent component(&engine); component.setData("import QtQuick 2.0; Flickable { boundsBehavior: Flickable.StopAtBounds }", QUrl::fromLocalFile("")); QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(component.create()); @@ -330,6 +336,7 @@ void tst_qquickflickable::rebound() void tst_qquickflickable::maximumFlickVelocity() { + QQmlEngine engine; QQmlComponent component(&engine); component.setData("import QtQuick 2.0; Flickable { maximumFlickVelocity: 1.0; }", QUrl::fromLocalFile("")); QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(component.create()); @@ -349,6 +356,7 @@ void tst_qquickflickable::maximumFlickVelocity() void tst_qquickflickable::flickDeceleration() { + QQmlEngine engine; QQmlComponent component(&engine); component.setData("import QtQuick 2.0; Flickable { flickDeceleration: 1.0; }", QUrl::fromLocalFile("")); QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(component.create()); @@ -553,6 +561,7 @@ void tst_qquickflickable::nestedClickThenFlick() void tst_qquickflickable::flickableDirection() { + QQmlEngine engine; QQmlComponent component(&engine); component.setData("import QtQuick 2.0; Flickable { flickableDirection: Flickable.VerticalFlick; }", QUrl::fromLocalFile("")); QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(component.create()); @@ -1213,9 +1222,16 @@ void tst_qquickflickable::flickVelocity() void tst_qquickflickable::margins() { - QQmlEngine engine; - QQmlComponent c(&engine, testFileUrl("margins.qml")); - QQuickItem *root = qobject_cast<QQuickItem*>(c.create()); + QScopedPointer<QQuickView> window(new QQuickView); + window->setSource(testFileUrl("margins.qml")); + QTRY_COMPARE(window->status(), QQuickView::Ready); + QQuickViewTestUtil::centerOnScreen(window.data()); + QQuickViewTestUtil::moveMouseAway(window.data()); + window->setTitle(QTest::currentTestFunction()); + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window.data())); + QQuickItem *root = window->rootObject(); + QVERIFY(root); QQuickFlickable *obj = qobject_cast<QQuickFlickable*>(root); QVERIFY(obj != 0); |