iOS: Implement support for QScreen::grabWindow()

Only windows that are part of the application can be grabbed. This
excludes the system statusbar and other system overlays, as well
as windows of other applications. This is a limitation due to the
security model of iOS.

There exists APIs to grab a snapshot of the complete screen, but
these APIs return a view that can be used as a placeholder e.g.
during view transformations, and doesn't match our API that require
reading of pixels.

Task-number: QTBUG-49944
Change-Id: I8fd5b4c2777be1486f0ff22762d5e9b64c927e70
Reviewed-by: Jake Petroules <jake.petroules@qt.io>
This commit is contained in:
Tor Arne Vestbø 2015-12-16 15:27:21 +01:00
parent 5ad8b3aa32
commit dc3af6a164
3 changed files with 39 additions and 0 deletions

View File

@ -667,6 +667,10 @@ void QScreenPrivate::updatePrimaryOrientation()
that are not part of the application, window system frames, and so
on.
\warning Grabbing windows that are not part of the application is
not supported on systems such as iOS, where sandboxing/security
prevents reading pixels of windows not owned by the application.
The grabWindow() function grabs pixels from the screen, not from
the window, i.e. if there is another window partially or entirely
over the one you grab, you get pixels from the overlying window,

View File

@ -68,6 +68,8 @@ public:
Qt::ScreenOrientation orientation() const Q_DECL_OVERRIDE;
void setOrientationUpdateMask(Qt::ScreenOrientations mask) Q_DECL_OVERRIDE;
QPixmap grabWindow(WId window, int x, int y, int width, int height) const override;
UIScreen *uiScreen() const;
UIWindow *uiWindow() const;

View File

@ -47,6 +47,7 @@
#include "quiview.h"
#include <QtGui/private/qwindow_p.h>
#include <private/qcoregraphics_p.h>
#include <sys/sysctl.h>
@ -457,6 +458,38 @@ void QIOSScreen::setOrientationUpdateMask(Qt::ScreenOrientations mask)
}
}
QPixmap QIOSScreen::grabWindow(WId window, int x, int y, int width, int height) const
{
if (window && ![reinterpret_cast<id>(window) isKindOfClass:[UIView class]])
return QPixmap();
UIView *view = window ? reinterpret_cast<UIView *>(window) : m_uiWindow;
if (width < 0)
width = qMax(view.bounds.size.width - x, CGFloat(0));
if (height < 0)
height = qMax(view.bounds.size.height - y, CGFloat(0));
CGRect captureRect = [m_uiWindow convertRect:CGRectMake(x, y, width, height) fromView:view];
captureRect = CGRectIntersection(captureRect, m_uiWindow.bounds);
UIGraphicsBeginImageContextWithOptions(captureRect.size, NO, 0.0);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, -captureRect.origin.x, -captureRect.origin.y);
// Draws the complete view hierarchy of m_uiWindow into the given rect, which
// needs to be the same aspect ratio as the m_uiWindow's size. Since we've
// translated the graphics context, and are potentially drawing into a smaller
// context than the full window, the resulting image will be a subsection of the
// full screen.
[m_uiWindow drawViewHierarchyInRect:m_uiWindow.bounds afterScreenUpdates:NO];
UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return QPixmap::fromImage(qt_mac_toQImage(screenshot.CGImage));
}
UIScreen *QIOSScreen::uiScreen() const
{
return m_uiScreen;