Source

Target

Commits (21)
Showing with 164 additions and 38 deletions
......@@ -40,6 +40,7 @@
#include "mainwindow.h"
#include "fbitem.h"
#include <QCoreApplication>
#include <QVBoxLayout>
#include <QGroupBox>
#include <QRadioButton>
......
......@@ -54,6 +54,7 @@
#include <private/qqmlcompiler_p.h>
#include "qqmlinfo.h"
#include <private/qjsvalue_p.h>
#include <private/qv4value_p.h>
#include <private/qv4qobjectwrapper_p.h>
......@@ -224,7 +225,9 @@ void QQmlBoundSignalExpression::evaluate(void **a)
//### ideally we would use metaTypeToJS, however it currently gives different results
// for several cases (such as QVariant type and QObject-derived types)
//args[ii] = engine->metaTypeToJS(type, a[ii + 1]);
if (type == QMetaType::QVariant) {
if (type == qMetaTypeId<QJSValue>()) {
callData->args[ii] = *QJSValuePrivate::getValue(reinterpret_cast<QJSValue *>(a[ii + 1]));
} else if (type == QMetaType::QVariant) {
callData->args[ii] = scope.engine->fromVariant(*((QVariant *)a[ii + 1]));
} else if (type == QMetaType::Int) {
//### optimization. Can go away if we switch to metaTypeToJS, or be expanded otherwise
......
......@@ -490,8 +490,8 @@ QQmlType *QQmlType::resolveCompositeBaseType(QQmlEnginePrivate *engine) const
Q_ASSERT(isComposite());
if (!engine)
return 0;
QQmlTypeData *td = engine->typeLoader.getType(sourceUrl());
if (!td || !td->isComplete())
QQmlRefPointer<QQmlTypeData> td(engine->typeLoader.getType(sourceUrl()), QQmlRefPointer<QQmlTypeData>::Adopt);
if (td.isNull() || !td->isComplete())
return 0;
QQmlCompiledData *cd = td->compiledData();
const QMetaObject *mo = cd->rootPropertyCache->firstCppMetaObject();
......
......@@ -84,7 +84,7 @@
stretches horizontally. The azure rectangle can be resized from 50x150 to 300x150, and the plum
rectangle can be resized from 100x100 to ∞x100.
\snippet windowconstraints.qml rowlayout
\snippet qml/windowconstraints.qml rowlayout
\image rowlayout-minimum.png "RowLayout at its minimum"
......
......@@ -180,7 +180,7 @@ dedicated thread. Qt attempts to choose a suitable loop based on the
platform and possibly the graphics drivers in use. When this is not
satisfactory, or for testing purposes, the environment variable
\c QSG_RENDER_LOOP can be used to force the usage of a given loop. To
verify which render loop is in use, enable the \c qt.scenegraph.info
verify which render loop is in use, enable the \c qt.scenegraph.general
\l {QLoggingCategory}{logging category}.
\note The \c threaded and \c windows render loops rely on the OpenGL
......@@ -368,7 +368,7 @@ addition to being helpful to Qt contributors.
\li \c {qt.scenegraph.time.glyph} - logs the time spent preparing distance field glyphs
\li \c {qt.scenegraph.info} - logs general information about various parts of the scene graph and the graphics stack
\li \c {qt.scenegraph.general} - logs general information about various parts of the scene graph and the graphics stack
\li \c {qt.scenegraph.renderloop} - creates a detailed log of the various stages involved in rendering. This log mode is primarily useful for developers working on Qt.
......
......@@ -135,7 +135,7 @@ Creator.
\div {class="doc-column"}
\b{Layouts and Views}
\list
\li \l{Qt Quick Controls - Basic Layouts Example}{Basic Layouts}
\li \l{Qt Quick Layouts - Basic Example}
\li \l{Qt Quick Examples - Positioners}{Positioners}
\li \l{Qt Quick Examples - Views}{Views}
\li \l{Qt Quick Examples - Window and Screen}{Windows and Screen}
......
......@@ -5762,6 +5762,8 @@ bool QQuickItemPrivate::setEffectiveVisibleRecur(bool newEffectiveVisible)
QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window);
if (windowPriv->mouseGrabberItem == q)
q->ungrabMouse();
if (!effectiveVisible)
q->ungrabTouchPoints();
}
bool childVisibilityChanged = false;
......@@ -5810,6 +5812,8 @@ void QQuickItemPrivate::setEffectiveEnableRecur(QQuickItem *scope, bool newEffec
QQuickWindowPrivate *windowPriv = QQuickWindowPrivate::get(window);
if (windowPriv->mouseGrabberItem == q)
q->ungrabMouse();
if (!effectiveEnable)
q->ungrabTouchPoints();
if (scope && !effectiveEnable && activeFocus) {
windowPriv->clearFocusInScope(
scope, q, Qt::OtherFocusReason, QQuickWindowPrivate::DontChangeFocusProperty | QQuickWindowPrivate::DontChangeSubFocusItem);
......
......@@ -3147,7 +3147,7 @@ bool QQuickListViewPrivate::applyInsertionChange(const QQmlChangeSet::Change &ch
}
}
int prevVisibleCount = visibleItems.count();
bool visibleAffected = false;
if (insertResult->visiblePos.isValid() && pos < insertResult->visiblePos) {
// Insert items before the visible item.
int insertionIdx = index;
......@@ -3170,6 +3170,7 @@ bool QQuickListViewPrivate::applyInsertionChange(const QQmlChangeSet::Change &ch
if (!item)
return false;
visibleAffected = true;
visibleItems.insert(insertionIdx, item);
if (insertionIdx == 0)
insertResult->changedFirstItem = true;
......@@ -3201,6 +3202,9 @@ bool QQuickListViewPrivate::applyInsertionChange(const QQmlChangeSet::Change &ch
} else {
qreal to = buffer + displayMarginEnd + tempPos + size();
visibleAffected = count > 0 && pos < to;
for (int i = 0; i < count && pos <= to; ++i) {
FxViewItem *item = 0;
if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i))))
......@@ -3251,7 +3255,7 @@ bool QQuickListViewPrivate::applyInsertionChange(const QQmlChangeSet::Change &ch
updateVisibleIndex();
return visibleItems.count() > prevVisibleCount;
return visibleAffected;
}
void QQuickListViewPrivate::translateAndTransitionItemsAfter(int afterModelIndex, const ChangeResult &insertionResult, const ChangeResult &removalResult)
......
......@@ -405,6 +405,15 @@ QImage QQuickSpriteEngine::assembledImage()
QImage img = state->m_pix.image();
{
const QSize frameSize(state->m_frameWidth, state->m_frameHeight);
if (!(img.size() - frameSize).isValid()) {
qmlInfo(state).nospace() << "SpriteEngine: Invalid frame size " << frameSize << "."
" It's bigger than image size " << img.size() << ".";
return QImage();
}
}
//Check that the frame sizes are the same within one sprite
if (!state->m_frameWidth)
state->m_frameWidth = img.width() / state->frames();
......
......@@ -240,8 +240,6 @@ public:
uint clearBeforeRendering : 1;
// Currently unused in the default implementation, as we're not stopping
// rendering when obscured as we should...
uint persistentGLContext : 1;
uint persistentSceneGraph : 1;
......
......@@ -92,7 +92,7 @@ QT_BEGIN_NAMESPACE
// Used for very high-level info about the renderering and gl context
// Includes GL_VERSION, type of render loop, atlas size, etc.
Q_LOGGING_CATEGORY(QSG_LOG_INFO, "qt.scenegraph.info")
Q_LOGGING_CATEGORY(QSG_LOG_INFO, "qt.scenegraph.general")
// Used to debug the renderloop logic. Primarily useful for platform integrators
// and when investigating the render loop logic.
......
......@@ -96,10 +96,7 @@ void QQuickWidgetPrivate::init(QQmlEngine* e)
engine = e;
if (engine.isNull())
engine = new QQmlEngine(q);
if (!engine.data()->incubationController())
if (!engine.isNull() && !engine.data()->incubationController())
engine.data()->setIncubationController(offscreenWindow->incubationController());
#ifndef QT_NO_DRAGANDDROP
......@@ -112,6 +109,16 @@ void QQuickWidgetPrivate::init(QQmlEngine* e)
QObject::connect(renderControl, SIGNAL(sceneChanged()), q, SLOT(triggerUpdate()));
}
void QQuickWidgetPrivate::ensureEngine() const
{
Q_Q(const QQuickWidget);
if (!engine.isNull())
return;
engine = new QQmlEngine(const_cast<QQuickWidget*>(q));
engine.data()->setIncubationController(offscreenWindow->incubationController());
}
void QQuickWidgetPrivate::invalidateRenderControl()
{
if (!context) // this is not an error, could be called before creating the context, or multiple times
......@@ -167,10 +174,7 @@ QQuickWidgetPrivate::~QQuickWidgetPrivate()
void QQuickWidgetPrivate::execute()
{
Q_Q(QQuickWidget);
if (!engine) {
qWarning() << "QQuickWidget: invalid qml engine.";
return;
}
ensureEngine();
if (root) {
delete root;
......@@ -404,7 +408,6 @@ QQuickWidget::QQuickWidget(QQmlEngine* engine, QWidget *parent)
{
setMouseTracking(true);
setFocusPolicy(Qt::StrongFocus);
Q_ASSERT(engine);
d_func()->init(engine);
}
......@@ -490,7 +493,8 @@ QUrl QQuickWidget::source() const
QQmlEngine* QQuickWidget::engine() const
{
Q_D(const QQuickWidget);
return d->engine ? const_cast<QQmlEngine *>(d->engine.data()) : 0;
d->ensureEngine();
return const_cast<QQmlEngine *>(d->engine.data());
}
/*!
......@@ -503,7 +507,8 @@ QQmlEngine* QQuickWidget::engine() const
QQmlContext* QQuickWidget::rootContext() const
{
Q_D(const QQuickWidget);
return d->engine ? d->engine.data()->rootContext() : 0;
d->ensureEngine();
return d->engine.data()->rootContext();
}
/*!
......@@ -548,7 +553,7 @@ QQmlContext* QQuickWidget::rootContext() const
QQuickWidget::Status QQuickWidget::status() const
{
Q_D(const QQuickWidget);
if (!d->engine)
if (!d->engine && !d->source.isEmpty())
return QQuickWidget::Error;
if (!d->component)
......@@ -574,11 +579,12 @@ QList<QQmlError> QQuickWidget::errors() const
if (d->component)
errs = d->component->errors();
if (!d->engine) {
if (!d->engine && !d->source.isEmpty()) {
QQmlError error;
error.setDescription(QLatin1String("QQuickWidget: invalid qml engine."));
errs << error;
} else if (d->component && d->component->status() == QQmlComponent::Ready && !d->root) {
}
if (d->component && d->component->status() == QQmlComponent::Ready && !d->root) {
QQmlError error;
error.setDescription(QLatin1String("QQuickWidget: invalid root object."));
errs << error;
......@@ -776,9 +782,10 @@ void QQuickWidget::createFramebufferObject()
return;
}
if (context->shareContext() != QWidgetPrivate::get(window())->shareContext()) {
context->setShareContext(QWidgetPrivate::get(window())->shareContext());
context->setScreen(context->shareContext()->screen());
QOpenGLContext *shareWindowContext = QWidgetPrivate::get(window())->shareContext();
if (shareWindowContext && context->shareContext() != shareWindowContext) {
context->setShareContext(shareWindowContext);
context->setScreen(shareWindowContext->screen());
if (!context->create())
qWarning("QQuickWidget: Failed to recreate context");
// The screen may be different so we must recreate the offscreen surface too.
......@@ -1106,7 +1113,14 @@ void QQuickWidget::showEvent(QShowEvent *)
d->createContext();
if (d->offscreenWindow->openglContext()) {
d->render(true);
if (d->updatePending) {
// render() may have led to a QQuickWindow::update() call (for
// example, having a scene with a QQuickFramebufferObject::Renderer
// calling update() in its render()) which in turn results in
// renderRequested in the rendercontrol, ending up in
// triggerUpdate. In this case just calling update() is not
// acceptable, we need the full renderSceneGraph issued from
// timerEvent().
if (!d->eventPending && d->updatePending) {
d->updatePending = false;
update();
}
......@@ -1228,6 +1242,17 @@ bool QQuickWidget::event(QEvent *e)
break;
case QEvent::ScreenChangeInternal:
if (QWindow *window = this->window()->windowHandle()) {
QScreen *newScreen = window->screen();
if (d->offscreenWindow)
d->offscreenWindow->setScreen(newScreen);
if (d->offscreenSurface)
d->offscreenSurface->setScreen(newScreen);
if (d->context)
d->context->setScreen(newScreen);
}
if (d->fbo) {
// This will check the size taking the devicePixelRatio into account
// and recreate if needed.
......
......@@ -105,6 +105,7 @@ public:
QImage grabFramebuffer() Q_DECL_OVERRIDE;
void init(QQmlEngine* e = 0);
void ensureEngine() const;
void handleWindowChange();
void invalidateRenderControl();
......@@ -114,7 +115,7 @@ public:
QUrl source;
QPointer<QQmlEngine> engine;
mutable QPointer<QQmlEngine> engine;
QQmlComponent *component;
QBasicTimer resizetimer;
QQuickWindow *offscreenWindow;
......
......@@ -9,8 +9,3 @@ linux
linux
[ListView::test_listInteractiveCurrentIndexEnforce]
linux
[Text::test_linecount]
osx
windows
[TextInput::test_doublevalidators]
osx
......@@ -102,7 +102,7 @@ Item {
property int callCount: 0;
property bool ready: false;
function handleGrab(result) {
if (!result.saveToFile("image.png"))
if (!result.saveToFile("itemgrabber/image.png"))
print("Error: Failed to save image to disk...");
source = "image.png";
ready = true;
......@@ -116,7 +116,7 @@ Item {
y: 0
property bool ready: false;
function handleGrab(result) {
if (!result.saveToFile("image_small.png"))
if (!result.saveToFile("itemgrabber/image_small.png"))
print("Error: Failed to save image to disk...");
source = "image_small.png";
ready = true;
......
......@@ -277,6 +277,7 @@ Item {
}
function test_doublevalidators(row) {
txtdoublevalidator.validator.locale = "C"
compare(txtdoublevalidator.validator.top, 2.0)
compare(txtdoublevalidator.validator.bottom, 1.0)
txtdoublevalidator.text = row.testnumber;
......
tests/auto/quick/qquickanimatedsprite/data/img100x100.png

238 Bytes

tests/auto/quick/qquickanimatedsprite/data/img50x50.png

135 Bytes

/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/
import QtQuick 2.4
AnimatedSprite {
id: animatedSprite
source: big ? "img100x100.png" : "img50x50.png"
frameWidth: 100
frameHeight: 100
property bool big: true
MouseArea {
anchors.fill: parent
onClicked: animatedSprite.big = !animatedSprite.big
}
}
......@@ -35,6 +35,7 @@
#include <QtGui/qopenglcontext.h>
#include <QtGui/qopenglfunctions.h>
#include <QtGui/qoffscreensurface.h>
#include <QtQml/qqmlproperty.h>
class tst_qquickanimatedsprite : public QQmlDataTest
{
......@@ -50,6 +51,7 @@ private slots:
void test_largeAnimation_data();
void test_largeAnimation();
void test_reparenting();
void test_changeSourceToSmallerImgKeepingBigFrameSize();
};
void tst_qquickanimatedsprite::initTestCase()
......@@ -286,6 +288,43 @@ void tst_qquickanimatedsprite::test_reparenting()
QTRY_COMPARE(QQuickItemPrivate::get(sprite)->polishScheduled, false);
}
class KillerThread : public QThread
{
Q_OBJECT
protected:
void run() Q_DECL_OVERRIDE {
sleep(3);
qFatal("Either the GUI or the render thread is stuck in an infinite loop.");
}
};
// Regression test for QTBUG-53937
void tst_qquickanimatedsprite::test_changeSourceToSmallerImgKeepingBigFrameSize()
{
QQuickView window;
window.setSource(testFileUrl("sourceSwitch.qml"));
window.show();
QVERIFY(QTest::qWaitForWindowExposed(&window));
QVERIFY(window.rootObject());
QQuickAnimatedSprite* sprite = qobject_cast<QQuickAnimatedSprite*>(window.rootObject());
QVERIFY(sprite);
QQmlProperty big(sprite, "big");
big.write(QVariant::fromValue(false));
KillerThread *killer = new KillerThread;
killer->start(); // will kill us in case the GUI or render thread enters an infinite loop
QTest::qWait(50); // let it draw with the new source.
// If we reach this point it's because we didn't hit QTBUG-53937
killer->terminate();
killer->wait();
delete killer;
}
QTEST_MAIN(tst_qquickanimatedsprite)
#include "tst_qquickanimatedsprite.moc"