Merge remote-tracking branch 'origin/5.9' into dev

Conflicts:
	src/qml/jit/qv4assembler.cpp
	src/qml/jit/qv4assembler_p.h

Change-Id: Ibfe69610ccd1f275f181b2bd87feece4ba221e50
This commit is contained in:
Liang Qi 2017-03-30 11:11:55 +02:00
commit 22cc4d6707
21 changed files with 308 additions and 58 deletions

View File

@ -94,6 +94,7 @@ public:
using DataLabelCompact = typename MacroAssemblerBase::DataLabelCompact;
using Jump = typename MacroAssemblerBase::Jump;
using PatchableJump = typename MacroAssemblerBase::PatchableJump;
using MacroAssemblerBase::PointerSize;
using MacroAssemblerBase::pop;
using MacroAssemblerBase::jump;
@ -200,19 +201,19 @@ public:
// described in terms of other macro assembly methods.
void pop()
{
addPtr(TrustedImm32(sizeof(void*)), MacroAssemblerBase::stackPointerRegister);
addPtr(TrustedImm32(PointerSize), MacroAssemblerBase::stackPointerRegister);
}
void peek(RegisterID dest, int index = 0)
{
loadPtr(Address(MacroAssemblerBase::stackPointerRegister, (index * sizeof(void*))), dest);
loadPtr(Address(MacroAssemblerBase::stackPointerRegister, (index * PointerSize)), dest);
}
Address addressForPoke(int index)
{
return Address(MacroAssemblerBase::stackPointerRegister, (index * sizeof(void*)));
return Address(MacroAssemblerBase::stackPointerRegister, (index * PointerSize));
}
void poke(RegisterID src, int index = 0)
{
storePtr(src, addressForPoke(index));
@ -223,10 +224,12 @@ public:
store32(value, addressForPoke(index));
}
#if !defined(V4_BOOTSTRAP)
void poke(TrustedImmPtr imm, int index = 0)
{
storePtr(imm, addressForPoke(index));
}
#endif
#if (CPU(X86_64) || CPU(ARM64)) && !defined(V4_BOOTSTRAP)
void peek64(RegisterID dest, int index = 0)

View File

@ -127,6 +127,8 @@ private:
static const ptrdiff_t REPATCH_OFFSET_CALL_TO_POINTER = -16;
public:
static const int PointerSize = 8;
MacroAssemblerARM64()
: m_dataMemoryTempRegister(this, dataTempRegister)
, m_cachedMemoryTempRegister(this, memoryTempRegister)

View File

@ -46,6 +46,8 @@ protected: // the YarrJIT needs know about addressTempRegister in order to push
inline ARMRegisters::FPSingleRegisterID fpTempRegisterAsSingle() { return ARMRegisters::asSingle(fpTempRegister); }
public:
static const int PointerSize = 4;
MacroAssemblerARMv7()
: m_makeJumpPatchable(false)
{
@ -1242,7 +1244,7 @@ public:
void pop(RegisterID dest)
{
// store postindexed with writeback
m_assembler.ldr(dest, ARMRegisters::sp, sizeof(void*), false, true);
m_assembler.ldr(dest, ARMRegisters::sp, 4 /*sizeof(void*)*/, false, true);
}
void push(RegisterID src)

View File

@ -37,6 +37,7 @@ namespace JSC {
class MacroAssemblerMIPS : public AbstractMacroAssembler<MIPSAssembler> {
public:
typedef MIPSRegisters::FPRegisterID FPRegisterID;
static const int PointerSize = 4;
MacroAssemblerMIPS()
: m_fixedWidth(false)

View File

@ -35,6 +35,7 @@ namespace JSC {
class MacroAssemblerX86 : public MacroAssemblerX86Common {
public:
static const Scale ScalePtr = TimesFour;
static const int PointerSize = 4;
using MacroAssemblerX86Common::add32;
using MacroAssemblerX86Common::and32;

View File

@ -37,6 +37,7 @@ namespace JSC {
class MacroAssemblerX86_64 : public MacroAssemblerX86Common {
public:
static const Scale ScalePtr = TimesEight;
static const int PointerSize = 8;
using MacroAssemblerX86Common::add32;
using MacroAssemblerX86Common::and32;

View File

@ -95,6 +95,12 @@ bool CompilationUnit::memoryMapCode(QString *errorString)
JSC::MacroAssemblerCodeRef codeRef = JSC::MacroAssemblerCodeRef::createSelfManagedCodeRef(JSC::MacroAssemblerCodePtr(codePtr));
JSC::ExecutableAllocator::makeExecutable(codePtr, compiledFunction->codeSize);
codeRefs[i] = codeRef;
static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_ASM");
if (showCode) {
WTF::dataLogF("Mapped JIT code for %s\n", qPrintable(stringAt(compiledFunction->nameIndex)));
disassemble(codeRef.code(), compiledFunction->codeSize, " ", WTF::dataFile());
}
}
return true;
@ -535,9 +541,7 @@ void Assembler<TargetConfiguration>::returnFromFunction(IR::Ret *s, RegisterInfo
const int locals = stackLayout().calculateJSStackFrameSize();
subPtr(TrustedImm32(sizeof(QV4::Value)*locals), JITTargetPlatform::LocalsRegister);
loadPtr(Address(JITTargetPlatform::EngineRegister, targetStructureOffset(offsetof(QV4::EngineBase, current))), JITTargetPlatform::ScratchRegister);
loadPtr(Address(JITTargetPlatform::ScratchRegister, targetStructureOffset(Heap::ExecutionContextData::baseOffset + offsetof(Heap::ExecutionContextData, engine))), JITTargetPlatform::ScratchRegister);
storePtr(JITTargetPlatform::LocalsRegister, Address(JITTargetPlatform::ScratchRegister, targetStructureOffset(offsetof(EngineBase, jsStackTop))));
storePtr(JITTargetPlatform::LocalsRegister, Address(JITTargetPlatform::EngineRegister, targetStructureOffset(offsetof(EngineBase, jsStackTop))));
leaveStandardStackFrame(regularRegistersToSave, fpRegistersToSave);
ret();

View File

@ -1387,13 +1387,6 @@ public:
RegisterSizeDependentOps::emitWriteBarrier(this, dest);
}
void storeValue(QV4::Primitive value, RegisterID destination)
{
Q_UNUSED(value);
Q_UNUSED(destination);
Q_UNREACHABLE();
}
void storeValue(QV4::Primitive value, Address destination, WriteBarrier::Type barrier)
{
RegisterSizeDependentOps::storeValue(this, value, destination, barrier);
@ -1463,7 +1456,7 @@ public:
template <int ArgumentIndex, typename Parameter>
struct SizeOnStack
{
enum { Size = Select<ArgumentIndex >= RegisterArgumentCount, sizeof(void*), 0>::Chosen };
enum { Size = Select<ArgumentIndex >= RegisterArgumentCount, RegisterSize, 0>::Chosen };
};
template <int ArgumentIndex>

View File

@ -370,7 +370,7 @@ public:
// There are two designated frame-pointer registers on ARM, depending on which instruction set
// is used for the subroutine: r7 for Thumb or Thumb2, and r11 for ARM. We assign the constants
// accordingly, and assign the locals-register to the "other" register.
#if CPU(ARM_THUMB2)
#if CPU(ARM_THUMB2) || defined(V4_BOOTSTRAP)
static const RegisterID FramePointerRegister = JSC::ARMRegisters::r7;
static const RegisterID LocalsRegister = JSC::ARMRegisters::r11;
#else // Thumbs down
@ -397,7 +397,7 @@ public:
<< RI(JSC::ARMRegisters::r4, QStringLiteral("r4"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
<< RI(JSC::ARMRegisters::r5, QStringLiteral("r5"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
<< RI(JSC::ARMRegisters::r6, QStringLiteral("r6"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
#if !CPU(ARM_THUMB2)
#if !CPU(ARM_THUMB2) && !defined(V4_BOOTSTRAP)
<< RI(JSC::ARMRegisters::r7, QStringLiteral("r7"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
#endif
<< RI(JSC::ARMRegisters::r8, QStringLiteral("r8"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
@ -405,7 +405,7 @@ public:
<< RI(JSC::ARMRegisters::r9, QStringLiteral("r9"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
#endif
<< RI(JSC::ARMRegisters::r10, QStringLiteral("r10"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
#if CPU(ARM_THUMB2)
#if CPU(ARM_THUMB2) && !defined(V4_BOOTSTRAP)
<< RI(JSC::ARMRegisters::r11, QStringLiteral("r11"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
#endif
<< RI(JSC::ARMRegisters::d2, QStringLiteral("d2"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)

View File

@ -64,6 +64,7 @@
#include <QtCore/qwaitcondition.h>
#include <QtCore/qloggingcategory.h>
#include <QtQml/qqmlextensioninterface.h>
#include <QtCore/qcryptographichash.h>
#include <functional>

View File

@ -2301,7 +2301,8 @@ bool QQuickFlickable::filterMouseEvent(QQuickItem *receiver, QMouseEvent *event)
bool receiverDisabled = receiver && !receiver->isEnabled();
bool stealThisEvent = d->stealMouse;
if ((stealThisEvent || contains(localPos)) && (!receiver || !receiver->keepMouseGrab() || receiverDisabled)) {
bool receiverKeepsGrab = receiver && (receiver->keepMouseGrab() || receiver->keepTouchGrab());
if ((stealThisEvent || contains(localPos)) && (!receiver || !receiverKeepsGrab || receiverDisabled)) {
QScopedPointer<QMouseEvent> mouseEvent(QQuickWindowPrivate::cloneMouseEvent(event, &localPos));
mouseEvent->setAccepted(false);
@ -2321,7 +2322,7 @@ bool QQuickFlickable::filterMouseEvent(QQuickItem *receiver, QMouseEvent *event)
default:
break;
}
if ((receiver && stealThisEvent && !receiver->keepMouseGrab() && receiver != this) || receiverDisabled) {
if ((receiver && stealThisEvent && !receiverKeepsGrab && receiver != this) || receiverDisabled) {
d->clearDelayedPress();
grabMouse();
} else if (d->delayedPressEvent) {
@ -2337,7 +2338,7 @@ bool QQuickFlickable::filterMouseEvent(QQuickItem *receiver, QMouseEvent *event)
d->lastPosTime = -1;
returnToBounds();
}
if (event->type() == QEvent::MouseButtonRelease || (receiver && receiver->keepMouseGrab() && !receiverDisabled)) {
if (event->type() == QEvent::MouseButtonRelease || (receiverKeepsGrab && !receiverDisabled)) {
// mouse released, or another item has claimed the grab
d->lastPosTime = -1;
d->clearDelayedPress();

View File

@ -746,6 +746,7 @@ void QQuickWindowPrivate::setMouseGrabber(QQuickItem *grabber)
qCDebug(DBG_MOUSE_TARGET) << "grabber" << q->mouseGrabberItem() << "->" << grabber;
QQuickItem *oldGrabber = q->mouseGrabberItem();
bool fromTouch = false;
if (grabber && touchMouseId != -1 && touchMouseDevice) {
// update the touch item for mouse touch id to the new grabber
@ -753,6 +754,7 @@ void QQuickWindowPrivate::setMouseGrabber(QQuickItem *grabber)
auto point = touchMouseDevice->pointerEvent()->pointById(touchMouseId);
if (point)
point->setGrabber(grabber);
fromTouch = true;
} else {
QQuickPointerEvent *event = QQuickPointerDevice::genericMouseDevice()->pointerEvent();
Q_ASSERT(event->pointCount() == 1);
@ -762,8 +764,11 @@ void QQuickWindowPrivate::setMouseGrabber(QQuickItem *grabber)
if (oldGrabber) {
QEvent e(QEvent::UngrabMouse);
QSet<QQuickItem *> hasFiltered;
if (!sendFilteredMouseEvent(oldGrabber->parentItem(), oldGrabber, &e, &hasFiltered))
if (!sendFilteredMouseEvent(oldGrabber->parentItem(), oldGrabber, &e, &hasFiltered)) {
oldGrabber->mouseUngrabEvent();
if (fromTouch)
oldGrabber->touchUngrabEvent();
}
}
}
@ -2585,28 +2590,39 @@ bool QQuickWindowPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem
break;
}
bool touchMouseUnset = (touchMouseId == -1);
// Only deliver mouse event if it is the touchMouseId or it could become the touchMouseId
if (touchMouseId == -1 || touchMouseId == tp.id()) {
if (touchMouseUnset || touchMouseId == tp.id()) {
// targetEvent is already transformed wrt local position, velocity, etc.
// FIXME: remove asTouchEvent!!!
QScopedPointer<QMouseEvent> mouseEvent(touchToMouseEvent(t, tp, event->asTouchEvent(), item, false));
// If a filtering item calls QQuickWindow::mouseGrabberItem(), it should
// report the touchpoint's grabber. Whenever we send a synthetic mouse event,
// touchMouseId and touchMouseDevice must be set, even if it's only temporarily and isn't grabbed.
touchMouseId = tp.id();
touchMouseDevice = event->device();
if (target->childMouseEventFilter(item, mouseEvent.data())) {
qCDebug(DBG_TOUCH) << " - second chance intercepted on childMouseEventFilter by " << target;
if (t != QEvent::MouseButtonRelease) {
qCDebug(DBG_TOUCH_TARGET) << "TP" << tp.id() << "->" << target;
touchMouseDevice = event->device();
if (touchMouseId == -1) {
if (touchMouseUnset) {
// the point was grabbed as a pure touch point before, now it will be treated as mouse
// but the old receiver still needs to be informed
if (auto oldGrabber = touchMouseDevice->pointerEvent()->pointById(tp.id())->grabber())
oldGrabber->touchUngrabEvent();
}
touchMouseId = tp.id();
touchMouseUnset = false; // We want to leave touchMouseId and touchMouseDevice set
target->grabMouse();
}
filtered = true;
}
if (touchMouseUnset) {
// Now that we're done sending a synth mouse event, and it wasn't grabbed,
// the touchpoint is no longer acting as a synthetic mouse. Restore previous state.
touchMouseId = -1;
touchMouseDevice = nullptr;
}
// Only one event can be filtered as a mouse event.
break;
}

View File

@ -353,10 +353,9 @@ QImage QQuickWidgetPrivate::grabFramebuffer()
return renderControl->grab();
}
QObject *QQuickWidgetPrivate::focusObject()
{
return offscreenWindow ? offscreenWindow->focusObject() : 0;
}
// Intentionally not overriding the QQuickWindow's focusObject.
// Key events should go to our key event handlers, and then to the
// QQuickWindow, not any in-scene item.
/*!
\module QtQuickWidgets

View File

@ -99,8 +99,6 @@ public:
void destroyContext();
void handleContextCreationFailure(const QSurfaceFormat &format, bool isEs);
QObject *focusObject() Q_DECL_OVERRIDE;
#if QT_CONFIG(opengl)
GLuint textureId() const Q_DECL_OVERRIDE;
QImage grabFramebuffer() Q_DECL_OVERRIDE;

View File

@ -18,4 +18,7 @@ qtHaveModule(gui):qtConfig(opengl(es1|es2)?) {
# console applications not supported
uikit: SUBDIRS -= qmltest
# Restricted sub-set for now
boot2qt: SUBDIRS = qml
installed_cmake.depends = cmake

View File

@ -71,7 +71,7 @@ void tst_EcmaScriptTests::runTests()
#endif
}
QTEST_MAIN(tst_EcmaScriptTests)
QTEST_GUILESS_MAIN(tst_EcmaScriptTests)
#include "tst_ecmascripttests.moc"

View File

@ -7,6 +7,9 @@ PUBLICTESTS += \
parserstress \
qjsvalueiterator \
qjsonbinding \
!boot2qt {
PUBLICTESTS += \
qmlmin \
qqmlcomponent \
qqmlconsole \
@ -25,15 +28,21 @@ PUBLICTESTS += \
qquickfolderlistmodel \
qqmlapplicationengine \
qqmlsettings \
qqmlstatemachine
qqmlstatemachine \
qmldiskcache
}
PRIVATETESTS += \
animation \
qqmlcpputils \
qqmldirparser \
v4misc \
!boot2qt {
PRIVATETESTS += \
animation \
qqmlecmascript \
qqmlcontext \
qqmlexpression \
qqmldirparser \
qqmlglobal \
qqmllanguage \
qqmlopenmetaobject \
@ -57,13 +66,12 @@ PRIVATETESTS += \
qqmltimer \
qqmlinstantiator \
qqmlenginecleanup \
v4misc \
qqmltranslation \
qqmlimport \
qqmlobjectmodel \
qmldiskcache \
qv4mm \
ecmascripttests
}
qtHaveModule(widgets) {
PUBLICTESTS += \
@ -73,7 +81,7 @@ qtHaveModule(widgets) {
SUBDIRS += $$PUBLICTESTS
SUBDIRS += $$METATYPETESTS
qtConfig(process) {
qtConfig(process):!boot2qt {
!contains(QT_CONFIG, no-qml-debug): SUBDIRS += debugger
SUBDIRS += qmllint qmlplugindump
}

View File

@ -0,0 +1,36 @@
import QtQuick 2.0
import Test 1.0
Flickable {
width: 240
height: 320
contentWidth: width * 1.5
contentHeight: height * 1.5
contentY: height * 0.25
Rectangle {
id: slider
width: 50
height: 200
color: "lightgray"
border.color: drag.active ? "green" : "black"
anchors.centerIn: parent
radius: 4
TouchDragArea {
id: drag
objectName: "drag"
anchors.fill: parent
}
Rectangle {
width: parent.width - 2
height: 20
radius: 5
color: "darkgray"
border.color: "black"
x: 1
y: Math.min(slider.height - height, Math.max(0, drag.pos.y - height / 2))
}
}
}

View File

@ -46,12 +46,109 @@
using namespace QQuickViewTestUtil;
using namespace QQuickVisualTestUtil;
// an abstract Slider which only handles touch events
class TouchDragArea : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(QPointF pos READ pos NOTIFY posChanged)
Q_PROPERTY(bool active READ active NOTIFY activeChanged)
Q_PROPERTY(bool keepMouseGrab READ keepMouseGrab WRITE setKeepMouseGrab NOTIFY keepMouseGrabChanged)
Q_PROPERTY(bool keepTouchGrab READ keepTouchGrab WRITE setKeepTouchGrab NOTIFY keepTouchGrabChanged)
public:
TouchDragArea(QQuickItem *parent = 0)
: QQuickItem(parent)
, touchEvents(0)
, touchUpdates(0)
, touchReleases(0)
, ungrabs(0)
, m_active(false)
{
setFlags(ItemAcceptsDrops);
}
QPointF pos() const { return m_pos; }
bool active() const { return m_active; }
void setKeepMouseGrab(bool keepMouseGrab)
{
QQuickItem::setKeepMouseGrab(keepMouseGrab);
emit keepMouseGrabChanged();
}
void setKeepTouchGrab(bool keepTouchGrab)
{
QQuickItem::setKeepTouchGrab(keepTouchGrab);
emit keepTouchGrabChanged();
}
int touchEvents;
int touchUpdates;
int touchReleases;
int ungrabs;
QVector<Qt::TouchPointState> touchPointStates;
protected:
void touchEvent(QTouchEvent *ev) override
{
QCOMPARE(ev->touchPoints().count(), 1);
auto touchpoint = ev->touchPoints().first();
switch (touchpoint.state()) {
case Qt::TouchPointPressed:
QVERIFY(!m_active);
m_active = true;
emit activeChanged();
grabTouchPoints(QVector<int>() << touchpoint.id());
break;
case Qt::TouchPointMoved:
++touchUpdates;
break;
case Qt::TouchPointReleased:
QVERIFY(m_active);
m_active = false;
++touchReleases;
emit activeChanged();
case Qt::TouchPointStationary:
break;
}
touchPointStates << touchpoint.state();
++touchEvents;
m_pos = touchpoint.pos();
emit posChanged();
}
void touchUngrabEvent() override
{
++ungrabs;
QVERIFY(m_active);
emit ungrabbed();
m_active = false;
emit activeChanged();
}
signals:
void ungrabbed();
void posChanged();
void keepMouseGrabChanged();
void keepTouchGrabChanged();
void activeChanged();
private:
QPointF m_pos;
bool m_active;
};
class tst_qquickflickable : public QQmlDataTest
{
Q_OBJECT
public:
tst_qquickflickable()
: touchDevice(QTest::createTouchDevice())
{}
private slots:
void initTestCase() override;
void create();
void horizontalViewportSize();
void verticalViewportSize();
@ -89,6 +186,8 @@ private slots:
void stopAtBounds();
void stopAtBounds_data();
void nestedMouseAreaUsingTouch();
void nestedSliderUsingTouch();
void nestedSliderUsingTouch_data();
void pressDelayWithLoader();
void movementFromProgrammaticFlick();
void cleanup();
@ -101,9 +200,16 @@ private slots:
void overshoot_reentrant();
private:
void flickWithTouch(QQuickWindow *window, QTouchDevice *touchDevice, const QPoint &from, const QPoint &to);
void flickWithTouch(QQuickWindow *window, const QPoint &from, const QPoint &to);
QTouchDevice *touchDevice;
};
void tst_qquickflickable::initTestCase()
{
QQmlDataTest::initTestCase();
qmlRegisterType<TouchDragArea>("Test",1,0,"TouchDragArea");
}
void tst_qquickflickable::cleanup()
{
QVERIFY(QGuiApplication::topLevelWindows().isEmpty());
@ -1530,12 +1636,6 @@ void tst_qquickflickable::clickAndDragWhenTransformed()
void tst_qquickflickable::flickTwiceUsingTouches()
{
QTouchDevice *touchDevice = new QTouchDevice;
touchDevice->setName("Fake Touchscreen");
touchDevice->setType(QTouchDevice::TouchScreen);
touchDevice->setCapabilities(QTouchDevice::Position);
QWindowSystemInterface::registerTouchDevice(touchDevice);
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("longList.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
@ -1548,7 +1648,7 @@ void tst_qquickflickable::flickTwiceUsingTouches()
QVERIFY(flickable != 0);
QCOMPARE(flickable->contentY(), 0.0f);
flickWithTouch(window.data(), touchDevice, QPoint(100, 400), QPoint(100, 240));
flickWithTouch(window.data(), QPoint(100, 400), QPoint(100, 240));
qreal contentYAfterFirstFlick = flickable->contentY();
qDebug() << "contentYAfterFirstFlick " << contentYAfterFirstFlick;
@ -1556,7 +1656,7 @@ void tst_qquickflickable::flickTwiceUsingTouches()
// Wait until view stops moving
QTRY_VERIFY(!flickable->isMoving());
flickWithTouch(window.data(), touchDevice, QPoint(100, 400), QPoint(100, 240));
flickWithTouch(window.data(), QPoint(100, 400), QPoint(100, 240));
// In the original bug, that second flick would cause Flickable to halt immediately
qreal contentYAfterSecondFlick = flickable->contentY();
@ -1564,7 +1664,7 @@ void tst_qquickflickable::flickTwiceUsingTouches()
QTRY_VERIFY(contentYAfterSecondFlick > (contentYAfterFirstFlick + 80.0f));
}
void tst_qquickflickable::flickWithTouch(QQuickWindow *window, QTouchDevice *touchDevice, const QPoint &from, const QPoint &to)
void tst_qquickflickable::flickWithTouch(QQuickWindow *window, const QPoint &from, const QPoint &to)
{
QTest::touchEvent(window, touchDevice).press(0, from, window);
QQuickTouchUtils::flush(window);
@ -1869,12 +1969,6 @@ void tst_qquickflickable::stopAtBounds()
void tst_qquickflickable::nestedMouseAreaUsingTouch()
{
QTouchDevice *touchDevice = new QTouchDevice;
touchDevice->setName("Fake Touchscreen");
touchDevice->setType(QTouchDevice::TouchScreen);
touchDevice->setCapabilities(QTouchDevice::Position);
QWindowSystemInterface::registerTouchDevice(touchDevice);
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("nestedmousearea.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
@ -1887,7 +1981,7 @@ void tst_qquickflickable::nestedMouseAreaUsingTouch()
QVERIFY(flickable != 0);
QCOMPARE(flickable->contentY(), 50.0f);
flickWithTouch(window.data(), touchDevice, QPoint(100, 300), QPoint(100, 200));
flickWithTouch(window.data(), QPoint(100, 300), QPoint(100, 200));
// flickable should not have moved
QCOMPARE(flickable->contentY(), 50.0);
@ -1897,6 +1991,65 @@ void tst_qquickflickable::nestedMouseAreaUsingTouch()
QVERIFY(nested->y() < 100.0);
}
void tst_qquickflickable::nestedSliderUsingTouch_data()
{
QTest::addColumn<bool>("keepMouseGrab");
QTest::addColumn<bool>("keepTouchGrab");
QTest::addColumn<int>("updates");
QTest::addColumn<int>("releases");
QTest::addColumn<int>("ungrabs");
QTest::newRow("keepBoth") << true << true << 8 << 1 << 0;
QTest::newRow("keepMouse") << true << false << 8 << 1 << 0;
QTest::newRow("keepTouch") << false << true << 8 << 1 << 0;
QTest::newRow("keepNeither") << false << false << 6 << 0 << 1;
}
void tst_qquickflickable::nestedSliderUsingTouch()
{
QFETCH(bool, keepMouseGrab);
QFETCH(bool, keepTouchGrab);
QFETCH(int, updates);
QFETCH(int, releases);
QFETCH(int, ungrabs);
QQuickView *window = new QQuickView;
QScopedPointer<QQuickView> windowPtr(window);
windowPtr->setSource(testFileUrl("nestedSlider.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
QQuickViewTestUtil::centerOnScreen(window);
QQuickViewTestUtil::moveMouseAway(window);
window->show();
QVERIFY(QTest::qWaitForWindowActive(window));
QVERIFY(window->rootObject() != 0);
QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject());
QVERIFY(flickable);
TouchDragArea *tda = flickable->findChild<TouchDragArea*>("drag");
QVERIFY(tda);
// Drag down and a little to the right: flickable will steal the grab only if tda allows it
const int dragThreshold = qApp->styleHints()->startDragDistance();
tda->setKeepMouseGrab(keepMouseGrab);
tda->setKeepTouchGrab(keepTouchGrab);
QPoint p0 = tda->mapToScene(QPoint(20, 20)).toPoint();
QTest::touchEvent(window, touchDevice).press(0, p0, window);
QQuickTouchUtils::flush(window);
for (int i = 0; i < 8; ++i) {
p0 += QPoint(dragThreshold / 6, dragThreshold / 4);
QTest::touchEvent(window, touchDevice).move(0, p0, window);
QQuickTouchUtils::flush(window);
}
QCOMPARE(tda->active(), !ungrabs);
QTest::touchEvent(window, touchDevice).release(0, p0, window);
QQuickTouchUtils::flush(window);
QCOMPARE(tda->touchPointStates.first(), Qt::TouchPointPressed);
QCOMPARE(tda->touchUpdates, updates);
QCOMPARE(tda->touchReleases, releases);
QCOMPARE(tda->ungrabs, ungrabs);
}
// QTBUG-31328
void tst_qquickflickable::pressDelayWithLoader()
{

View File

@ -375,7 +375,7 @@ void tst_qquickimage::mirror()
}
QImage img = expected.toImage();
QCOMPARE(screenshots[fillMode], img);
QCOMPARE(screenshots[fillMode].convertToFormat(img.format()), img);
}
}

View File

@ -58,6 +58,7 @@ private slots:
void grabBeforeShow();
void reparentToNewWindow();
void nullEngine();
void keyEvents();
};
@ -337,6 +338,33 @@ void tst_qquickwidget::nullEngine()
QVERIFY(widget.engine());
}
class KeyHandlingWidget : public QQuickWidget
{
public:
void keyPressEvent(QKeyEvent *e) override {
if (e->key() == Qt::Key_A)
ok = true;
}
bool ok = false;
};
void tst_qquickwidget::keyEvents()
{
// A QQuickWidget should behave like a normal widget when it comes to event handling.
// Verify that key events actually reach the widget. (QTBUG-45757)
KeyHandlingWidget widget;
widget.setSource(testFileUrl("rectangle.qml"));
widget.show();
QVERIFY(QTest::qWaitForWindowExposed(widget.window(), 5000));
// Note: send the event to the QWindow, not the QWidget, in order
// to simulate the full event processing chain.
QTest::keyClick(widget.window()->windowHandle(), Qt::Key_A);
QTRY_VERIFY(widget.ok);
}
QTEST_MAIN(tst_qquickwidget)
#include "tst_qquickwidget.moc"