diff options
author | Piotr Mikolajczyk <piotr.mikolajczyk@qt.io> | 2021-02-02 06:45:21 +0100 |
---|---|---|
committer | Ville Voutilainen <ville.voutilainen@qt.io> | 2021-03-08 08:00:18 +0000 |
commit | bacf9cd04c21c62075087febe0a799ed8d1c5f8c (patch) | |
tree | cecdec78bc5301a734c63493b71cd8daf2cac0cd /src/plugins/platforms/android | |
parent | 4f37cf2ce544dad5b207161536566627b6b0b1ef (diff) |
Android: Add grabWindow handling
Draws to a pixmap contents of the requested window. On Android it works
only for QtWidgets application.
Qml application contents could not be grabbed due to lack of access to
the contents of OpenGL framebuffer from QAndroidPlatformScreen
Fixes: QTBUG-63275
Pick-to: 5.15
Change-Id: Ief7de1b709387d798138387bb735f4b48cf2928d
Reviewed-by: Ville Voutilainen <ville.voutilainen@qt.io>
Diffstat (limited to 'src/plugins/platforms/android')
-rw-r--r-- | src/plugins/platforms/android/qandroidplatformscreen.cpp | 72 | ||||
-rw-r--r-- | src/plugins/platforms/android/qandroidplatformscreen.h | 8 |
2 files changed, 75 insertions, 5 deletions
diff --git a/src/plugins/platforms/android/qandroidplatformscreen.cpp b/src/plugins/platforms/android/qandroidplatformscreen.cpp index 5f8486a7a2..6a83827262 100644 --- a/src/plugins/platforms/android/qandroidplatformscreen.cpp +++ b/src/plugins/platforms/android/qandroidplatformscreen.cpp @@ -302,7 +302,7 @@ int QAndroidPlatformScreen::rasterSurfaces() return m_rasterSurfaces; } -void QAndroidPlatformScreen::doRedraw() +void QAndroidPlatformScreen::doRedraw(QImage* screenGrabImage) { PROFILE_SCOPE; if (!QtAndroid::activity()) @@ -357,15 +357,14 @@ void QAndroidPlatformScreen::doRedraw() } int bpp = 4; - QImage::Format format = QImage::Format_RGBA8888_Premultiplied; if (nativeWindowBuffer.format == WINDOW_FORMAT_RGB_565) { bpp = 2; - format = QImage::Format_RGB16; + m_pixelFormat = QImage::Format_RGB16; } QImage screenImage(reinterpret_cast<uchar *>(nativeWindowBuffer.bits) , nativeWindowBuffer.width, nativeWindowBuffer.height - , nativeWindowBuffer.stride * bpp , format); + , nativeWindowBuffer.stride * bpp , m_pixelFormat); QPainter compositePainter(&screenImage); compositePainter.setCompositionMode(QPainter::CompositionMode_Source); @@ -398,6 +397,31 @@ void QAndroidPlatformScreen::doRedraw() ret = ANativeWindow_unlockAndPost(m_nativeSurface); if (ret >= 0) m_dirtyRect = QRect(); + + if (screenGrabImage) { + if (screenGrabImage->size() != screenImage.size()) { + uchar* bytes = static_cast<uchar*>(malloc(screenImage.height() * screenImage.bytesPerLine())); + *screenGrabImage = QImage(bytes, screenImage.width(), screenImage.height(), + screenImage.bytesPerLine(), m_pixelFormat, + [](void* ptr){ if (ptr) free (ptr);}); + } + memcpy(screenGrabImage->bits(), + screenImage.bits(), + screenImage.bytesPerLine() * screenImage.height()); + } + m_repaintOccurred = true; +} + +QPixmap QAndroidPlatformScreen::doScreenShot(QRect grabRect) +{ + if (!m_repaintOccurred) + return QPixmap::fromImage(m_lastScreenshot.copy(grabRect)); + QRect tmp = m_dirtyRect; + m_dirtyRect = geometry(); + doRedraw(&m_lastScreenshot); + m_dirtyRect = tmp; + m_repaintOccurred = false; + return QPixmap::fromImage(m_lastScreenshot.copy(grabRect)); } static const int androidLogicalDpi = 72; @@ -445,4 +469,44 @@ void QAndroidPlatformScreen::releaseSurface() } } +/*! + This function is called when Qt needs to be able to grab the content of a window. + + Returns the content of the window specified with the WId handle within the boundaries of + QRect(x, y, width, height). +*/ +QPixmap QAndroidPlatformScreen::grabWindow(WId window, int x, int y, int width, int height) const +{ + QRectF screenshotRect(x, y, width, height); + QWindow* wnd = 0; + if (window) + { + const auto windowList = qApp->allWindows(); + for (QWindow *w : windowList) + if (w->winId() == window) { + wnd = w; + break; + } + } + if (wnd) { + const qreal factor = logicalDpi().first / androidLogicalDpi; //HighDPI factor; + QRectF wndRect = wnd->geometry(); + if (wnd->parent()) + wndRect.moveTopLeft(wnd->parent()->mapToGlobal(wndRect.topLeft().toPoint())); + if (!qFuzzyCompare(factor, 1)) + wndRect = QRectF(wndRect.left() * factor, wndRect.top() * factor, + wndRect.width() * factor, wndRect.height() * factor); + + if (!screenshotRect.isEmpty()) { + screenshotRect.moveTopLeft(wndRect.topLeft() + screenshotRect.topLeft()); + screenshotRect = screenshotRect.intersected(wndRect); + } else { + screenshotRect = wndRect; + } + } else { + screenshotRect = screenshotRect.isValid() ? screenshotRect : geometry(); + } + return const_cast<QAndroidPlatformScreen *>(this)->doScreenShot(screenshotRect.toRect()); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/qandroidplatformscreen.h b/src/plugins/platforms/android/qandroidplatformscreen.h index 4cdb0351bd..edddc9c557 100644 --- a/src/plugins/platforms/android/qandroidplatformscreen.h +++ b/src/plugins/platforms/android/qandroidplatformscreen.h @@ -106,12 +106,14 @@ private: QDpi logicalBaseDpi() const override; Qt::ScreenOrientation orientation() const override; Qt::ScreenOrientation nativeOrientation() const override; + QPixmap grabWindow(WId window, int x, int y, int width, int height) const override; void surfaceChanged(JNIEnv *env, jobject surface, int w, int h) override; void releaseSurface(); void applicationStateChanged(Qt::ApplicationState); + QPixmap doScreenShot(QRect grabRect = QRect()); private slots: - void doRedraw(); + void doRedraw(QImage *screenGrabImage = nullptr); private: int m_id = -1; @@ -119,6 +121,10 @@ private: ANativeWindow* m_nativeSurface = nullptr; QWaitCondition m_surfaceWaitCondition; QSize m_size; + + QImage m_lastScreenshot; + QImage::Format m_pixelFormat = QImage::Format_RGBA8888_Premultiplied; + bool m_repaintOccurred = false; }; QT_END_NAMESPACE |