From 52e68d4e106548eb027d4b35e47c941eb2d73f58 Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Mon, 25 Apr 2016 12:29:20 +0200 Subject: winrt: Fix memory leak for file reading IInputStream::ReadAsync might create a separate buffer to fill in data. Passing a buffer with GetAddressOf() can cause a memory leak of the size of data to be read. Instead, pass a separate buffer pointer and continue to use this one after the async operation. This way, the OS can decide whether to switch buffers or not, keeping ref counting in sync. Task-number: QTBUG-52961 Change-Id: I9dfb627287142355ebcf74ca52427b4e8108e8d1 Reviewed-by: Oliver Wolff --- src/plugins/platforms/winrt/qwinrtfileengine.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'src/plugins/platforms/winrt') diff --git a/src/plugins/platforms/winrt/qwinrtfileengine.cpp b/src/plugins/platforms/winrt/qwinrtfileengine.cpp index 858cb841b9..fb7c5e9990 100644 --- a/src/plugins/platforms/winrt/qwinrtfileengine.cpp +++ b/src/plugins/platforms/winrt/qwinrtfileengine.cpp @@ -463,14 +463,20 @@ qint64 QWinRTFileEngine::read(char *data, qint64 maxlen) hr = stream->ReadAsync(buffer.Get(), length, InputStreamOptions_None, &op); RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::ReadError, -1); - hr = QWinRTFunctions::await(op, buffer.GetAddressOf()); + // Quoting MSDN IInputStream::ReadAsync() documentation: + // "Depending on the implementation, the data that's read might be placed + // into the input buffer, or it might be returned in a different buffer." + // Using GetAddressOf can cause ref counting errors leaking the original + // buffer. + ComPtr effectiveBuffer; + hr = QWinRTFunctions::await(op, effectiveBuffer.GetAddressOf()); RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::ReadError, -1); - hr = buffer->get_Length(&length); + hr = effectiveBuffer->get_Length(&length); RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::ReadError, -1); ComPtr byteArrayAccess; - hr = buffer.As(&byteArrayAccess); + hr = effectiveBuffer.As(&byteArrayAccess); RETURN_AND_SET_ERROR_IF_FAILED(QFileDevice::ReadError, -1); byte *bytes; -- cgit v1.2.3 From 8a7311532ba331252d87cbcc08ea676f106242e9 Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Wed, 27 Apr 2016 10:19:42 +0200 Subject: winrt: Refactor pointer device handling to support pen In addition to pen events being handled as tablet events, we create touch events. Same principle is used on other platforms as well. This allows devices as Surfaces to use the pen with Qt applications. Furthermore, the first update event does not have to be a press event, as in a pen has proximity values describing a move without touch, but also the HoloLens uses touch points as permanent pointer devices. They all send an exit event once released or out of range. Hence, clean up the internal touchpoint hash when the touch device is gone, not on release. Task-number: QTBUG-38681 Change-Id: I38acaa034a3cfe224098bfa36bfead5428f4db16 Reviewed-by: Friedemann Kleint Reviewed-by: Oliver Wolff --- src/plugins/platforms/winrt/qwinrtscreen.cpp | 67 +++++++++++++++------------- 1 file changed, 37 insertions(+), 30 deletions(-) (limited to 'src/plugins/platforms/winrt') diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index 7fe8362817..0255527e91 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -952,8 +952,20 @@ HRESULT QWinRTScreen::onPointerEntered(ICoreWindow *, IPointerEventArgs *args) return S_OK; } -HRESULT QWinRTScreen::onPointerExited(ICoreWindow *, IPointerEventArgs *) +HRESULT QWinRTScreen::onPointerExited(ICoreWindow *, IPointerEventArgs *args) { + Q_D(QWinRTScreen); + + ComPtr pointerPoint; + if (FAILED(args->get_CurrentPoint(&pointerPoint))) + return E_INVALIDARG; + + quint32 id; + if (FAILED(pointerPoint->get_PointerId(&id))) + return E_INVALIDARG; + + d->touchPoints.remove(id); + QWindowSystemInterface::handleLeaveEvent(0); return S_OK; } @@ -1037,6 +1049,7 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args) break; } + case PointerDeviceType_Pen: case PointerDeviceType_Touch: { if (!d->touchDevice) { d->touchDevice = new QTouchDevice; @@ -1055,51 +1068,45 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args) float pressure; properties->get_Pressure(&pressure); - QHash::iterator it = d->touchPoints.find(id); - if (it != d->touchPoints.end()) { - boolean isPressed; + boolean isPressed; #ifndef Q_OS_WINPHONE - pointerPoint->get_IsInContact(&isPressed); + pointerPoint->get_IsInContact(&isPressed); #else - properties->get_IsLeftButtonPressed(&isPressed); // IsInContact not reliable on phone + properties->get_IsLeftButtonPressed(&isPressed); // IsInContact not reliable on phone #endif - it.value().state = isPressed ? Qt::TouchPointMoved : Qt::TouchPointReleased; - } else { + + const QRectF areaRect(area.X * d->scaleFactor, area.Y * d->scaleFactor, + area.Width * d->scaleFactor, area.Height * d->scaleFactor); + + QHash::iterator it = d->touchPoints.find(id); + if (it == d->touchPoints.end()) { it = d->touchPoints.insert(id, QWindowSystemInterface::TouchPoint()); - it.value().state = Qt::TouchPointPressed; it.value().id = id; } - it.value().area = QRectF(area.X * d->scaleFactor, area.Y * d->scaleFactor, - area.Width * d->scaleFactor, area.Height * d->scaleFactor); + + if (isPressed && it.value().pressure == 0.) + it.value().state = Qt::TouchPointPressed; + else if (!isPressed && it.value().pressure > 0.) + it.value().state = Qt::TouchPointReleased; + else if (it.value().area == areaRect) + it.value().state = Qt::TouchPointStationary; + else + it.value().state = Qt::TouchPointMoved; + + it.value().area = areaRect; it.value().normalPosition = QPointF(point.X/d->logicalRect.width(), point.Y/d->logicalRect.height()); it.value().pressure = pressure; QWindowSystemInterface::handleTouchEvent(topWindow(), d->touchDevice, d->touchPoints.values(), mods); - // Remove released points, station others - for (QHash::iterator i = d->touchPoints.begin(); i != d->touchPoints.end();) { - if (i.value().state == Qt::TouchPointReleased) - i = d->touchPoints.erase(i); - else - (i++).value().state = Qt::TouchPointStationary; - } - - break; - } - case PointerDeviceType_Pen: { - quint32 id; - pointerPoint->get_PointerId(&id); - - boolean isPressed; - pointerPoint->get_IsInContact(&isPressed); + // Fall-through for pen to generate tablet event + if (pointerDeviceType != PointerDeviceType_Pen) + break; boolean isEraser; properties->get_IsEraser(&isEraser); int pointerType = isEraser ? 3 : 1; - float pressure; - properties->get_Pressure(&pressure); - float xTilt; properties->get_XTilt(&xTilt); -- cgit v1.2.3