SurfaceFlinger: Add sourceCrop to screenshot
Adds a sourceCrop Rect parameter to screenshot commands, which allows
clients to capture only a portion of the screen instead of the whole
screen.
Bug: 15137922
Change-Id: I629447573cd34ffb96334cde7ba02490b9ea06d8
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 59afa66..7152f93 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2790,7 +2790,7 @@
status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
const sp<IGraphicBufferProducer>& producer,
- uint32_t reqWidth, uint32_t reqHeight,
+ Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ,
bool useIdentityTransform) {
@@ -2816,6 +2816,7 @@
SurfaceFlinger* flinger;
sp<IBinder> display;
sp<IGraphicBufferProducer> producer;
+ Rect sourceCrop;
uint32_t reqWidth, reqHeight;
uint32_t minLayerZ,maxLayerZ;
bool useIdentityTransform;
@@ -2824,11 +2825,11 @@
MessageCaptureScreen(SurfaceFlinger* flinger,
const sp<IBinder>& display,
const sp<IGraphicBufferProducer>& producer,
- uint32_t reqWidth, uint32_t reqHeight,
+ Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ,
bool useIdentityTransform)
: flinger(flinger), display(display), producer(producer),
- reqWidth(reqWidth), reqHeight(reqHeight),
+ sourceCrop(sourceCrop), reqWidth(reqWidth), reqHeight(reqHeight),
minLayerZ(minLayerZ), maxLayerZ(maxLayerZ),
useIdentityTransform(useIdentityTransform),
result(PERMISSION_DENIED)
@@ -2841,7 +2842,7 @@
Mutex::Autolock _l(flinger->mStateLock);
sp<const DisplayDevice> hw(flinger->getDisplayDevice(display));
result = flinger->captureScreenImplLocked(hw, producer,
- reqWidth, reqHeight, minLayerZ, maxLayerZ,
+ sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
useIdentityTransform);
static_cast<GraphicProducerWrapper*>(producer->asBinder().get())->exit(result);
return true;
@@ -2864,7 +2865,8 @@
// which does the marshaling work forwards to our "fake remote" above.
sp<MessageBase> msg = new MessageCaptureScreen(this,
display, IGraphicBufferProducer::asInterface( wrapper ),
- reqWidth, reqHeight, minLayerZ, maxLayerZ, useIdentityTransform);
+ sourceCrop, reqWidth, reqHeight, minLayerZ, maxLayerZ,
+ useIdentityTransform);
status_t res = postMessageAsync(msg);
if (res == NO_ERROR) {
@@ -2876,7 +2878,7 @@
void SurfaceFlinger::renderScreenImplLocked(
const sp<const DisplayDevice>& hw,
- uint32_t reqWidth, uint32_t reqHeight,
+ Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ,
bool yswap, bool useIdentityTransform)
{
@@ -2888,11 +2890,32 @@
const uint32_t hw_h = hw->getHeight();
const bool filtering = reqWidth != hw_w || reqWidth != hw_h;
+ // if a default or invalid sourceCrop is passed in, set reasonable values
+ if (sourceCrop.width() == 0 || sourceCrop.height() == 0 ||
+ !sourceCrop.isValid()) {
+ sourceCrop.setLeftTop(Point(0, 0));
+ sourceCrop.setRightBottom(Point(hw_w, hw_h));
+ }
+
+ // ensure that sourceCrop is inside screen
+ if (sourceCrop.left < 0) {
+ ALOGE("Invalid crop rect: l = %d (< 0)", sourceCrop.left);
+ }
+ if (sourceCrop.right >= hw_w) {
+ ALOGE("Invalid crop rect: r = %d (>= %d)", sourceCrop.right, hw_w);
+ }
+ if (sourceCrop.top < 0) {
+ ALOGE("Invalid crop rect: t = %d (< 0)", sourceCrop.top);
+ }
+ if (sourceCrop.bottom >= hw_h) {
+ ALOGE("Invalid crop rect: b = %d (>= %d)", sourceCrop.bottom, hw_h);
+ }
+
// make sure to clear all GL error flags
engine.checkErrors();
// set-up our viewport
- engine.setViewportAndProjection(reqWidth, reqHeight, hw_w, hw_h, yswap);
+ engine.setViewportAndProjection(reqWidth, reqHeight, sourceCrop, hw_h, yswap);
engine.disableTexturing();
// redraw the screen entirely...
@@ -2923,7 +2946,7 @@
status_t SurfaceFlinger::captureScreenImplLocked(
const sp<const DisplayDevice>& hw,
const sp<IGraphicBufferProducer>& producer,
- uint32_t reqWidth, uint32_t reqHeight,
+ Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ,
bool useIdentityTransform)
{
@@ -2978,7 +3001,7 @@
// via an FBO, which means we didn't have to create
// an EGLSurface and therefore we're not
// dependent on the context's EGLConfig.
- renderScreenImplLocked(hw, reqWidth, reqHeight,
+ renderScreenImplLocked(hw, sourceCrop, reqWidth, reqHeight,
minLayerZ, maxLayerZ, true, useIdentityTransform);
// Create a sync point and wait on it, so we know the buffer is