Merge "rework screenshot API and implementation" into jb-mr2-dev
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index 1b8f755..9a1839d 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -25,7 +25,7 @@
 #include <sys/time.h>
 #include <sys/wait.h>
 #include <unistd.h>
-#include <linux/capability.h>
+#include <sys/capability.h>
 #include <linux/prctl.h>
 
 #include <cutils/properties.h>
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index c272e47..a58eca8 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -14,7 +14,7 @@
 ** limitations under the License.
 */
 
-#include <linux/capability.h>
+#include <sys/capability.h>
 #include "installd.h"
 #include <diskusage/dirsize.h>
 #include <selinux/android.h>
diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c
index 2285e79..f81dfe5 100644
--- a/cmds/installd/installd.c
+++ b/cmds/installd/installd.c
@@ -14,7 +14,7 @@
 ** limitations under the License.
 */
 
-#include <linux/capability.h>
+#include <sys/capability.h>
 #include <linux/prctl.h>
 
 #include "installd.h"
diff --git a/include/gui/SurfaceControl.h b/include/gui/SurfaceControl.h
index 9268e7d..f70888d 100644
--- a/include/gui/SurfaceControl.h
+++ b/include/gui/SurfaceControl.h
@@ -57,7 +57,7 @@
     
     status_t    setLayerStack(int32_t layerStack);
     status_t    setLayer(int32_t layer);
-    status_t    setPosition(float x, float y);
+    status_t    setPosition(int32_t x, int32_t y);
     status_t    setSize(uint32_t w, uint32_t h);
     status_t    hide();
     status_t    show();
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 410ad5d..950d16a 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -735,7 +735,7 @@
 sp<Surface> Surface::readFromParcel(const Parcel& data) {
     sp<IBinder> binder(data.readStrongBinder());
     sp<IGraphicBufferProducer> bp(interface_cast<IGraphicBufferProducer>(binder));
-    return new Surface(bp);
+    return bp != NULL ? new Surface(bp): NULL;
 }
 
 // ----------------------------------------------------------------------------
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index e621b22..ef52269 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -106,7 +106,7 @@
     const sp<SurfaceComposerClient>& client(mClient);
     return client->setLayer(mSurface, layer);
 }
-status_t SurfaceControl::setPosition(float x, float y) {
+status_t SurfaceControl::setPosition(int32_t x, int32_t y) {
     status_t err = validate();
     if (err < 0) return err;
     const sp<SurfaceComposerClient>& client(mClient);
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 9466944..ed2768c 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -89,7 +89,7 @@
       mIsSecure(isSecure),
       mSecureLayerVisible(false),
       mScreenAcquired(false),
-      mLayerStack(0),
+      mLayerStack(NO_LAYER_STACK),
       mOrientation()
 {
     init(config);
@@ -196,13 +196,13 @@
     EGLDisplay dpy = mDisplay;
     EGLSurface surface = mSurface;
 
-#ifdef EGL_ANDROID_swap_rectangle    
+#ifdef EGL_ANDROID_swap_rectangle
     if (mFlags & SWAP_RECTANGLE) {
         const Region newDirty(dirty.intersect(bounds()));
         const Rect b(newDirty.getBounds());
         eglSetSwapRectangleANDROID(dpy, surface,
                 b.left, b.top, b.width(), b.height());
-    } 
+    }
 #endif
 
     mPageFlipCount++;
@@ -287,7 +287,8 @@
     mSecureLayerVisible = false;
     size_t count = layers.size();
     for (size_t i=0 ; i<count ; i++) {
-        if (layers[i]->isSecure()) {
+        const sp<LayerBase>& layer(layers[i]);
+        if (layer->isSecure()) {
             mSecureLayerVisible = true;
         }
     }
@@ -365,74 +366,72 @@
 }
 
 void DisplayDevice::setProjection(int orientation,
-        const Rect& viewport, const Rect& frame) {
+        const Rect& newViewport, const Rect& newFrame) {
+    Rect viewport(newViewport);
+    Rect frame(newFrame);
+
+    const int w = mDisplayWidth;
+    const int h = mDisplayHeight;
+
+    Transform R;
+    DisplayDevice::orientationToTransfrom(orientation, w, h, &R);
+
+    if (!frame.isValid()) {
+        // the destination frame can be invalid if it has never been set,
+        // in that case we assume the whole display frame.
+        frame = Rect(w, h);
+    }
+
+    if (viewport.isEmpty()) {
+        // viewport can be invalid if it has never been set, in that case
+        // we assume the whole display size.
+        // it's also invalid to have an empty viewport, so we handle that
+        // case in the same way.
+        viewport = Rect(w, h);
+        if (R.getOrientation() & Transform::ROT_90) {
+            // viewport is always specified in the logical orientation
+            // of the display (ie: post-rotation).
+            swap(viewport.right, viewport.bottom);
+        }
+    }
+
+    dirtyRegion.set(getBounds());
+
+    Transform TL, TP, S;
+    float src_width  = viewport.width();
+    float src_height = viewport.height();
+    float dst_width  = frame.width();
+    float dst_height = frame.height();
+    if (src_width != dst_width || src_height != dst_height) {
+        float sx = dst_width  / src_width;
+        float sy = dst_height / src_height;
+        S.set(sx, 0, 0, sy);
+    }
+
+    float src_x = viewport.left;
+    float src_y = viewport.top;
+    float dst_x = frame.left;
+    float dst_y = frame.top;
+    TL.set(-src_x, -src_y);
+    TP.set(dst_x, dst_y);
+
+    // The viewport and frame are both in the logical orientation.
+    // Apply the logical translation, scale to physical size, apply the
+    // physical translation and finally rotate to the physical orientation.
+    mGlobalTransform = R * TP * S * TL;
+
+    const uint8_t type = mGlobalTransform.getType();
+    mNeedsFiltering = (!mGlobalTransform.preserveRects() ||
+            (type >= Transform::SCALE));
+
+    mScissor = mGlobalTransform.transform(viewport);
+    if (mScissor.isEmpty()) {
+        mScissor.set(getBounds());
+    }
+
     mOrientation = orientation;
     mViewport = viewport;
     mFrame = frame;
-    updateGeometryTransform();
-}
-
-void DisplayDevice::updateGeometryTransform() {
-    int w = mDisplayWidth;
-    int h = mDisplayHeight;
-    Transform TL, TP, R, S;
-    if (DisplayDevice::orientationToTransfrom(
-            mOrientation, w, h, &R) == NO_ERROR) {
-        dirtyRegion.set(bounds());
-
-        Rect viewport(mViewport);
-        Rect frame(mFrame);
-
-        if (!frame.isValid()) {
-            // the destination frame can be invalid if it has never been set,
-            // in that case we assume the whole display frame.
-            frame = Rect(w, h);
-        }
-
-        if (viewport.isEmpty()) {
-            // viewport can be invalid if it has never been set, in that case
-            // we assume the whole display size.
-            // it's also invalid to have an empty viewport, so we handle that
-            // case in the same way.
-            viewport = Rect(w, h);
-            if (R.getOrientation() & Transform::ROT_90) {
-                // viewport is always specified in the logical orientation
-                // of the display (ie: post-rotation).
-                swap(viewport.right, viewport.bottom);
-            }
-        }
-
-        float src_width  = viewport.width();
-        float src_height = viewport.height();
-        float dst_width  = frame.width();
-        float dst_height = frame.height();
-        if (src_width != dst_width || src_height != dst_height) {
-            float sx = dst_width  / src_width;
-            float sy = dst_height / src_height;
-            S.set(sx, 0, 0, sy);
-        }
-
-        float src_x = viewport.left;
-        float src_y = viewport.top;
-        float dst_x = frame.left;
-        float dst_y = frame.top;
-        TL.set(-src_x, -src_y);
-        TP.set(dst_x, dst_y);
-
-        // The viewport and frame are both in the logical orientation.
-        // Apply the logical translation, scale to physical size, apply the
-        // physical translation and finally rotate to the physical orientation.
-        mGlobalTransform = R * TP * S * TL;
-
-        const uint8_t type = mGlobalTransform.getType();
-        mNeedsFiltering = (!mGlobalTransform.preserveRects() ||
-                (type >= Transform::SCALE));
-
-        mScissor = mGlobalTransform.transform(mViewport);
-        if (mScissor.isEmpty()) {
-            mScissor.set(getBounds());
-        }
-    }
 }
 
 void DisplayDevice::dump(String8& result, char* buffer, size_t SIZE) const {
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index bb6eb70..91f34db 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -65,6 +65,10 @@
         SWAP_RECTANGLE  = 0x00080000,
     };
 
+    enum {
+        NO_LAYER_STACK = 0xFFFFFFFF,
+    };
+
     DisplayDevice(
             const sp<SurfaceFlinger>& flinger,
             DisplayType type,
@@ -105,8 +109,8 @@
 
     int                     getOrientation() const { return mOrientation; }
     const Transform&        getTransform() const { return mGlobalTransform; }
-    const Rect&             getViewport() const { return mViewport; }
-    const Rect&             getFrame() const { return mFrame; }
+    const Rect              getViewport() const { return mViewport; }
+    const Rect              getFrame() const { return mFrame; }
     const Rect&             getScissor() const { return mScissor; }
     bool                    needsFiltering() const { return mNeedsFiltering; }
 
@@ -117,7 +121,7 @@
 
     void swapBuffers(HWComposer& hwc) const;
     status_t compositionComplete() const;
-    
+
     // called after h/w composer has completed its set() call
     void onSwapBuffersCompleted(HWComposer& hwc) const;
 
@@ -197,8 +201,6 @@
     static status_t orientationToTransfrom(int orientation,
             int w, int h, Transform* tr);
 
-    void updateGeometryTransform();
-
     uint32_t mLayerStack;
     int mOrientation;
     // user-provided visible area of the layer stack
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 439acb5..c9f1eb5 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -19,7 +19,6 @@
 #include <stdlib.h>
 #include <stdint.h>
 #include <sys/types.h>
-#include <math.h>
 
 #include <cutils/compiler.h>
 #include <cutils/native_handle.h>
@@ -200,48 +199,27 @@
     return NO_ERROR;
 }
 
-Rect Layer::computeBufferCrop() const {
-    // Start with the SurfaceFlingerConsumer's buffer crop...
+Rect Layer::getContentCrop() const {
+    // this is the crop rectangle that applies to the buffer
+    // itself (as opposed to the window)
     Rect crop;
     if (!mCurrentCrop.isEmpty()) {
+        // if the buffer crop is defined, we use that
         crop = mCurrentCrop;
-    } else  if (mActiveBuffer != NULL){
-        crop = Rect(mActiveBuffer->getWidth(), mActiveBuffer->getHeight());
+    } else if (mActiveBuffer != NULL) {
+        // otherwise we use the whole buffer
+        crop = mActiveBuffer->getBounds();
     } else {
+        // if we don't have a buffer yet, we use an empty/invalid crop
         crop.makeInvalid();
-        return crop;
     }
-
-    // ... then reduce that in the same proportions as the window crop reduces
-    // the window size.
-    const State& s(drawingState());
-    if (!s.active.crop.isEmpty()) {
-        // Transform the window crop to match the buffer coordinate system,
-        // which means using the inverse of the current transform set on the
-        // SurfaceFlingerConsumer.
-        uint32_t invTransform = mCurrentTransform;
-        int winWidth = s.active.w;
-        int winHeight = s.active.h;
-        if (invTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
-            invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V |
-                    NATIVE_WINDOW_TRANSFORM_FLIP_H;
-            winWidth = s.active.h;
-            winHeight = s.active.w;
-        }
-        Rect winCrop = s.active.crop.transform(invTransform,
-                s.active.w, s.active.h);
-
-        float xScale = float(crop.width()) / float(winWidth);
-        float yScale = float(crop.height()) / float(winHeight);
-        crop.left += int(ceilf(float(winCrop.left) * xScale));
-        crop.top += int(ceilf(float(winCrop.top) * yScale));
-        crop.right -= int(ceilf(float(winWidth - winCrop.right) * xScale));
-        crop.bottom -= int(ceilf(float(winHeight - winCrop.bottom) * yScale));
-    }
-
     return crop;
 }
 
+uint32_t Layer::getContentTransform() const {
+    return mCurrentTransform;
+}
+
 void Layer::setGeometry(
     const sp<const DisplayDevice>& hw,
         HWComposer::HWCLayerInterface& layer)
@@ -278,7 +256,6 @@
     } else {
         layer.setTransform(finalTransform);
     }
-    layer.setCrop(computeBufferCrop());
 }
 
 void Layer::setPerFrameData(const sp<const DisplayDevice>& hw,
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 5fd7e59..e57fb59 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -103,6 +103,9 @@
     // the current orientation of the display device.
     virtual void updateTransformHint(const sp<const DisplayDevice>& hw) const;
 
+    virtual Rect getContentCrop() const;
+    virtual uint32_t getContentTransform() const;
+
 protected:
     virtual void onFirstRef();
     virtual void dump(String8& result, char* scratch, size_t size) const;
@@ -119,7 +122,6 @@
 
     uint32_t getEffectiveUsage(uint32_t usage) const;
     bool isCropped() const;
-    Rect computeBufferCrop() const;
     static bool getOpacityForFormat(uint32_t format);
 
     // Interface implementation for SurfaceFlingerConsumer::FrameAvailableListener
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index dfdbf30..db2b20e 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -17,6 +17,7 @@
 #include <stdlib.h>
 #include <stdint.h>
 #include <sys/types.h>
+#include <math.h>
 
 #include <utils/Errors.h>
 #include <utils/Log.h>
@@ -259,7 +260,7 @@
     if (!s.active.crop.isEmpty()) {
         win.intersect(s.active.crop, &win);
     }
-    return s.transform.transform(win);
+    return win;
 }
 
 Region LayerBase::latchBuffer(bool& recomputeVisibleRegions) {
@@ -267,6 +268,83 @@
     return result;
 }
 
+
+Rect LayerBase::getContentCrop() const {
+    // regular layers just use their active area as the content crop
+    const State& s(drawingState());
+    return Rect(s.active.w, s.active.h);
+}
+
+uint32_t LayerBase::getContentTransform() const {
+    // regular layers don't have a content transform
+    return 0;
+}
+
+Rect LayerBase::computeCrop(const sp<const DisplayDevice>& hw) const {
+    /*
+     * The way we compute the crop (aka. texture coordinates when we have a
+     * Layer) produces a different output from the GL code in
+     * drawWithOpenGL() due to HWC being limited to integers. The difference
+     * can be large if getContentTransform() contains a large scale factor.
+     * See comments in drawWithOpenGL() for more details.
+     */
+
+    // the content crop is the area of the content that gets scaled to the
+    // layer's size.
+    Rect crop(getContentCrop());
+
+    // the active.crop is the area of the window that gets cropped, but not
+    // scaled in any ways.
+    const State& s(drawingState());
+
+    // apply the projection's clipping to the window crop in
+    // layerstack space, and convert-back to layer space.
+    // if there are no window scaling (or content scaling) involved,
+    // this operation will map to full pixels in the buffer.
+    // NOTE: should we revert to GL composition if a scaling is involved
+    // since it cannot be represented in the HWC API?
+    Rect activeCrop(s.transform.transform(s.active.crop));
+    activeCrop.intersect(hw->getViewport(), &activeCrop);
+    activeCrop = s.transform.inverse().transform(activeCrop);
+
+    // paranoia: make sure the window-crop is constrained in the
+    // window's bounds
+    activeCrop.intersect(Rect(s.active.w, s.active.h), &activeCrop);
+
+    if (!activeCrop.isEmpty()) {
+        // Transform the window crop to match the buffer coordinate system,
+        // which means using the inverse of the current transform set on the
+        // SurfaceFlingerConsumer.
+        uint32_t invTransform = getContentTransform();
+        int winWidth = s.active.w;
+        int winHeight = s.active.h;
+        if (invTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+            invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V |
+                    NATIVE_WINDOW_TRANSFORM_FLIP_H;
+            winWidth = s.active.h;
+            winHeight = s.active.w;
+        }
+        const Rect winCrop = activeCrop.transform(
+                invTransform, s.active.w, s.active.h);
+
+        // the code below essentially performs a scaled intersection
+        // of crop and winCrop
+        float xScale = float(crop.width()) / float(winWidth);
+        float yScale = float(crop.height()) / float(winHeight);
+
+        int insetL = int(ceilf( winCrop.left                * xScale));
+        int insetT = int(ceilf( winCrop.top                 * yScale));
+        int insetR = int(ceilf((winWidth  - winCrop.right ) * xScale));
+        int insetB = int(ceilf((winHeight - winCrop.bottom) * yScale));
+
+        crop.left   += insetL;
+        crop.top    += insetT;
+        crop.right  -= insetR;
+        crop.bottom -= insetB;
+    }
+    return crop;
+}
+
 void LayerBase::setGeometry(
     const sp<const DisplayDevice>& hw,
         HWComposer::HWCLayerInterface& layer)
@@ -289,13 +367,15 @@
                 HWC_BLENDING_COVERAGE);
     }
 
-    const Transform& tr = hw->getTransform();
-    Rect transformedBounds(computeBounds());
-    transformedBounds = tr.transform(transformedBounds);
 
-    // scaling is already applied in transformedBounds
-    layer.setFrame(transformedBounds);
-    layer.setCrop(transformedBounds.getBounds());
+    // apply the layer's transform, followed by the display's global transform
+    // here we're guaranteed that the layer's transform preserves rects
+
+    Rect frame(s.transform.transform(computeBounds()));
+    frame.intersect(hw->getViewport(), &frame);
+    const Transform& tr(hw->getTransform());
+    layer.setFrame(tr.transform(frame));
+    layer.setCrop(computeCrop(hw));
 }
 
 void LayerBase::setPerFrameData(const sp<const DisplayDevice>& hw,
@@ -303,8 +383,11 @@
     // we have to set the visible region on every frame because
     // we currently free it during onLayerDisplayed(), which is called
     // after HWComposer::commit() -- every frame.
+    // Apply this display's projection's viewport to the visible region
+    // before giving it to the HWC HAL.
     const Transform& tr = hw->getTransform();
-    layer.setVisibleRegionScreen(tr.transform(visibleRegion));
+    Region visible = tr.transform(visibleRegion.intersect(hw->getViewport()));
+    layer.setVisibleRegionScreen(visible);
 }
 
 void LayerBase::setAcquireFence(const sp<const DisplayDevice>& hw,
@@ -404,10 +487,22 @@
         GLfloat v;
     };
 
-    Rect win(s.active.w, s.active.h);
-    if (!s.active.crop.isEmpty()) {
-        win.intersect(s.active.crop, &win);
-    }
+
+    /*
+     * NOTE: the way we compute the texture coordinates here produces
+     * different results than when we take the HWC path -- in the later case
+     * the "source crop" is rounded to texel boundaries.
+     * This can produce significantly different results when the texture
+     * is scaled by a large amount.
+     *
+     * The GL code below is more logical (imho), and the difference with
+     * HWC is due to a limitation of the HWC API to integers -- a question
+     * is suspend is wether we should ignore this problem or revert to
+     * GL composition when a buffer scaling is applied (maybe with some
+     * minimal value)? Or, we could make GL behave like HWC -- but this feel
+     * like more of a hack.
+     */
+    const Rect win(computeBounds());
 
     GLfloat left   = GLfloat(win.left)   / GLfloat(s.active.w);
     GLfloat top    = GLfloat(win.top)    / GLfloat(s.active.h);
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index c2624df..ecae2d9 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -260,6 +260,18 @@
      */
     virtual void updateTransformHint(const sp<const DisplayDevice>& hw) const { }
 
+    /**
+     * returns the rectangle that crops the content of the layer and scales it
+     * to the layer's size.
+     */
+    virtual Rect getContentCrop() const;
+
+    /*
+     * returns the transform bits (90 rotation / h-flip / v-flip) of the
+     * layer's content
+     */
+    virtual uint32_t getContentTransform() const;
+
     /** always call base class first */
     virtual void dump(String8& result, char* scratch, size_t size) const;
     virtual void shortDump(String8& result, char* scratch, size_t size) const;
@@ -282,6 +294,9 @@
     void setFiltering(bool filtering);
     bool getFiltering() const;
 
+private:
+    Rect computeCrop(const sp<const DisplayDevice>& hw) const;
+
 protected:
           void clearWithOpenGL(const sp<const DisplayDevice>& hw, const Region& clip,
                   GLclampf r, GLclampf g, GLclampf b, GLclampf alpha) const;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 0971faa..8fa0800 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1347,7 +1347,7 @@
         // start with the whole surface at its current location
         const Layer::State& s(layer->drawingState());
 
-        // only consider the layers on the given later stack
+        // only consider the layers on the given layer stack
         if (s.layerStack != layerStack)
             continue;
 
@@ -1384,7 +1384,7 @@
         // handle hidden surfaces by setting the visible region to empty
         if (CC_LIKELY(layer->isVisible())) {
             const bool translucent = !layer->isOpaque();
-            Rect bounds(layer->computeBounds());
+            Rect bounds(s.transform.transform(layer->computeBounds()));
             visibleRegion.set(bounds);
             if (!visibleRegion.isEmpty()) {
                 // Remove the transparent area from the visible region
@@ -2073,12 +2073,14 @@
 // ---------------------------------------------------------------------------
 
 void SurfaceFlinger::onInitializeDisplays() {
-    // reset screen orientation
+    // reset screen orientation and use primary layer stack
     Vector<ComposerState> state;
     Vector<DisplayState> displays;
     DisplayState d;
-    d.what = DisplayState::eDisplayProjectionChanged;
+    d.what = DisplayState::eDisplayProjectionChanged |
+             DisplayState::eLayerStackChanged;
     d.token = mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY];
+    d.layerStack = 0;
     d.orientation = DisplayState::eOrientationDefault;
     d.frame.makeInvalid();
     d.viewport.makeInvalid();
@@ -2922,7 +2924,7 @@
 }
 
 SurfaceFlinger::DisplayDeviceState::DisplayDeviceState(DisplayDevice::DisplayType type)
-    : type(type), layerStack(0), orientation(0) {
+    : type(type), layerStack(DisplayDevice::NO_LAYER_STACK), orientation(0) {
     viewport.makeInvalid();
     frame.makeInvalid();
 }
diff --git a/services/surfaceflinger/Transform.cpp b/services/surfaceflinger/Transform.cpp
index aca90e0..315720e 100644
--- a/services/surfaceflinger/Transform.cpp
+++ b/services/surfaceflinger/Transform.cpp
@@ -298,6 +298,44 @@
     return mType;
 }
 
+Transform Transform::inverse() const {
+    // our 3x3 matrix is always of the form of a 2x2 transformation
+    // followed by a translation: T*M, therefore:
+    // (T*M)^-1 = M^-1 * T^-1
+    Transform result;
+    if (mType <= TRANSLATE) {
+        // 1 0 x
+        // 0 1 y
+        // 0 0 1
+        result = *this;
+        result.mMatrix[2][0] = -result.mMatrix[2][0];
+        result.mMatrix[2][1] = -result.mMatrix[2][1];
+    } else {
+        // a c x
+        // b d y
+        // 0 0 1
+        const mat33& M(mMatrix);
+        const float a = M[0][0];
+        const float b = M[1][0];
+        const float c = M[0][1];
+        const float d = M[1][1];
+        const float x = M[2][0];
+        const float y = M[2][1];
+
+        Transform R, T;
+        const float idet = 1.0 / (a*d - b*c);
+        R.mMatrix[0][0] =  d*idet;    R.mMatrix[0][1] = -c*idet;
+        R.mMatrix[1][0] = -b*idet;    R.mMatrix[1][1] =  a*idet;
+        R.mType = mType &= ~TRANSLATE;
+
+        T.mMatrix[2][0] = -x;
+        T.mMatrix[2][1] = -y;
+        T.mType = TRANSLATE;
+        result =  R * T;
+    }
+    return result;
+}
+
 uint32_t Transform::getType() const {
     return type() & 0xFF;
 }
diff --git a/services/surfaceflinger/Transform.h b/services/surfaceflinger/Transform.h
index 4fe261a..c4efade 100644
--- a/services/surfaceflinger/Transform.h
+++ b/services/surfaceflinger/Transform.h
@@ -80,6 +80,8 @@
             Rect    transform(const Rect& bounds) const;
             Transform operator * (const Transform& rhs) const;
 
+            Transform inverse() const;
+
             // for debugging
             void dump(const char* name) const;