Merge change Ieab4c75b into eclair

* changes:
  Fix type in Java enums.  Not currently used, easier to fix now than when apps are using it.
diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp
index 6880144..29531ca 100644
--- a/camera/libcameraservice/CameraService.cpp
+++ b/camera/libcameraservice/CameraService.cpp
@@ -865,7 +865,11 @@
 }
 
 // snapshot taken
-void CameraService::Client::handleShutter()
+void CameraService::Client::handleShutter(
+    image_rect_type *size // The width and height of yuv picture for
+                          // registerBuffer. If this is NULL, use the picture
+                          // size from parameters.
+)
 {
     // Play shutter sound.
     if (mMediaPlayerClick.get() != NULL) {
@@ -889,12 +893,21 @@
     if (mSurface != 0 && !mUseOverlay) {
         int w, h;
         CameraParameters params(mHardware->getParameters());
-        params.getPictureSize(&w, &h);
         uint32_t transform = 0;
         if (params.getOrientation() == CameraParameters::CAMERA_ORIENTATION_PORTRAIT) {
             LOGV("portrait mode");
             transform = ISurface::BufferHeap::ROT_90;
         }
+
+        if (size == NULL) {
+            params.getPictureSize(&w, &h);
+        } else {
+            w = size->width;
+            h = size->height;
+            w &= ~1;
+            h &= ~1;
+            LOGD("Snapshot image width=%d, height=%d", w, h);
+        }
         ISurface::BufferHeap buffers(w, h, w, h,
             PIXEL_FORMAT_YCbCr_420_SP, transform, 0, mHardware->getRawHeap());
 
@@ -1048,7 +1061,8 @@
 
     switch (msgType) {
         case CAMERA_MSG_SHUTTER:
-            client->handleShutter();
+            // ext1 is the dimension of the yuv picture.
+            client->handleShutter((image_rect_type *)ext1);
             break;
         default:
             sp<ICameraClient> c = client->mCameraClient;
diff --git a/camera/libcameraservice/CameraService.h b/camera/libcameraservice/CameraService.h
index 2fcf839..41c5d99 100644
--- a/camera/libcameraservice/CameraService.h
+++ b/camera/libcameraservice/CameraService.h
@@ -145,7 +145,7 @@
         static      sp<Client>  getClientFromCookie(void* user);
 
                     void        handlePreviewData(const sp<IMemory>&);
-                    void        handleShutter();
+                    void        handleShutter(image_rect_type *image);
                     void        handlePostview(const sp<IMemory>&);
                     void        handleRawPicture(const sp<IMemory>&);
                     void        handleCompressedPicture(const sp<IMemory>&);
diff --git a/include/ui/CameraHardwareInterface.h b/include/ui/CameraHardwareInterface.h
index af40f31..240c134 100644
--- a/include/ui/CameraHardwareInterface.h
+++ b/include/ui/CameraHardwareInterface.h
@@ -25,6 +25,15 @@
 #include <ui/Overlay.h>
 
 namespace android {
+/**
+ *  The size of image for display.
+ */
+typedef struct image_rect_struct
+{
+  uint32_t width;      /* Image width */
+  uint32_t height;     /* Image height */
+} image_rect_type;
+
 
 typedef void (*notify_callback)(int32_t msgType,
                                 int32_t ext1,
diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h
index 8897f03..2172536 100644
--- a/include/ui/GraphicBuffer.h
+++ b/include/ui/GraphicBuffer.h
@@ -66,7 +66,11 @@
     GraphicBuffer();
 
     // creates w * h buffer
-    GraphicBuffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t ssage);
+    GraphicBuffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t usage);
+
+    // create a buffer from an existing handle
+    GraphicBuffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t usage,
+            uint32_t stride, native_handle_t* handle, bool keepOwnership);
 
     // return status
     status_t initCheck() const;
@@ -94,9 +98,15 @@
     GraphicBuffer(const Parcel& reply);
     virtual ~GraphicBuffer();
 
+    enum {
+        ownNone   = 0,
+        ownHandle = 1,
+        ownData   = 2,
+    };
+
     inline const GraphicBufferMapper& getBufferMapper() const { return mBufferMapper; }
     inline GraphicBufferMapper& getBufferMapper() { return mBufferMapper; }
-    bool mOwner;
+    uint8_t mOwner;
 
 private:
     friend class Surface;
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index f84933e..1abfd68 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -256,12 +256,16 @@
     if (strstr(gl_extensions, "GL_OES_draw_texture")) {
         mFlags |= DRAW_TEXTURE_EXTENSION;
     }
+#ifdef EGL_ANDROID_image_native_buffer
     if (strstr( gl_extensions, "GL_OES_EGL_image") &&
         (strstr(egl_extensions, "EGL_KHR_image_base") || 
                 strstr(egl_extensions, "EGL_KHR_image")) &&
         strstr(egl_extensions, "EGL_ANDROID_image_native_buffer")) {
         mFlags |= DIRECT_TEXTURE;
     }
+#else
+#warning "EGL_ANDROID_image_native_buffer not supported"
+#endif
 
     // Unbind the context from this thread
     eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp
index 2bb1e12..f5a5a0b 100644
--- a/libs/surfaceflinger/Layer.cpp
+++ b/libs/surfaceflinger/Layer.cpp
@@ -130,62 +130,6 @@
     return NO_ERROR;
 }
 
-status_t Layer::initializeEglImageLocked(
-        const sp<GraphicBuffer>& buffer, Texture* texture)
-{
-    status_t err = NO_ERROR;
-
-    // we need to recreate the texture
-    EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
-
-    // free the previous image
-    if (texture->image != EGL_NO_IMAGE_KHR) {
-        eglDestroyImageKHR(dpy, texture->image);
-        texture->image = EGL_NO_IMAGE_KHR;
-    }
-
-    // construct an EGL_NATIVE_BUFFER_ANDROID
-    android_native_buffer_t* clientBuf = buffer->getNativeBuffer();
-
-    // create the new EGLImageKHR
-    const EGLint attrs[] = {
-            EGL_IMAGE_PRESERVED_KHR,    EGL_TRUE,
-            EGL_NONE,                   EGL_NONE
-    };
-    texture->image = eglCreateImageKHR(
-            dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
-            (EGLClientBuffer)clientBuf, attrs);
-
-    LOGE_IF(texture->image == EGL_NO_IMAGE_KHR,
-            "eglCreateImageKHR() failed. err=0x%4x",
-            eglGetError());
-
-    if (texture->image != EGL_NO_IMAGE_KHR) {
-        glBindTexture(GL_TEXTURE_2D, texture->name);
-        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
-                (GLeglImageOES)texture->image);
-        GLint error = glGetError();
-        if (UNLIKELY(error != GL_NO_ERROR)) {
-            // this failed, for instance, because we don't support NPOT.
-            // FIXME: do something!
-            LOGE("layer=%p, glEGLImageTargetTexture2DOES(%p) "
-                 "failed err=0x%04x",
-                 this, texture->image, error);
-            mFlags &= ~DisplayHardware::DIRECT_TEXTURE;
-            err = INVALID_OPERATION;
-        } else {
-            // Everything went okay!
-            texture->NPOTAdjust = false;
-            texture->dirty  = false;
-            texture->width  = clientBuf->width;
-            texture->height = clientBuf->height;
-        }
-    } else {
-        err = INVALID_OPERATION;
-    }
-    return err;
-}
-
 void Layer::reloadTexture(const Region& dirty)
 {
     Mutex::Autolock _l(mLock);
@@ -199,10 +143,11 @@
         mTextures[index].height = 0;
     }
 
+#ifdef EGL_ANDROID_image_native_buffer
     if (mFlags & DisplayHardware::DIRECT_TEXTURE) {
         if (buffer->usage & GraphicBuffer::USAGE_HW_TEXTURE) {
             if (mTextures[index].dirty) {
-                initializeEglImageLocked(buffer, &mTextures[index]);
+                initializeEglImage(buffer, &mTextures[index]);
             }
         } else {
             if (mHybridBuffer==0 || (mHybridBuffer->width != buffer->width ||
@@ -212,7 +157,7 @@
                         buffer->width, buffer->height, buffer->format,
                         GraphicBuffer::USAGE_SW_WRITE_OFTEN |
                         GraphicBuffer::USAGE_HW_TEXTURE);
-                initializeEglImageLocked(
+                initializeEglImage(
                         mHybridBuffer, &mTextures[0]);
             }
 
@@ -279,7 +224,9 @@
                 buffer->unlock();
             }
         }
-    } else {
+    } else
+#endif
+    {
         for (size_t i=0 ; i<NUM_BUFFERS ; i++) {
             mTextures[i].image = EGL_NO_IMAGE_KHR;
         }
diff --git a/libs/surfaceflinger/Layer.h b/libs/surfaceflinger/Layer.h
index 57b3dfa..1310ecc 100644
--- a/libs/surfaceflinger/Layer.h
+++ b/libs/surfaceflinger/Layer.h
@@ -85,8 +85,6 @@
     }
  
     void reloadTexture(const Region& dirty);
-    status_t initializeEglImageLocked(
-            const sp<GraphicBuffer>& buffer, Texture* texture);
 
     uint32_t getEffectiveUsage(uint32_t usage) const;
 
diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp
index ecc7894..8003d22 100644
--- a/libs/surfaceflinger/LayerBase.cpp
+++ b/libs/surfaceflinger/LayerBase.cpp
@@ -617,6 +617,63 @@
     }
 }
 
+status_t LayerBase::initializeEglImage(
+        const sp<GraphicBuffer>& buffer, Texture* texture)
+{
+    status_t err = NO_ERROR;
+
+    // we need to recreate the texture
+    EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
+
+    // free the previous image
+    if (texture->image != EGL_NO_IMAGE_KHR) {
+        eglDestroyImageKHR(dpy, texture->image);
+        texture->image = EGL_NO_IMAGE_KHR;
+    }
+
+    // construct an EGL_NATIVE_BUFFER_ANDROID
+    android_native_buffer_t* clientBuf = buffer->getNativeBuffer();
+
+    // create the new EGLImageKHR
+    const EGLint attrs[] = {
+            EGL_IMAGE_PRESERVED_KHR,    EGL_TRUE,
+            EGL_NONE,                   EGL_NONE
+    };
+    texture->image = eglCreateImageKHR(
+            dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+            (EGLClientBuffer)clientBuf, attrs);
+
+    LOGE_IF(texture->image == EGL_NO_IMAGE_KHR,
+            "eglCreateImageKHR() failed. err=0x%4x",
+            eglGetError());
+
+    if (texture->image != EGL_NO_IMAGE_KHR) {
+        glBindTexture(GL_TEXTURE_2D, texture->name);
+        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
+                (GLeglImageOES)texture->image);
+        GLint error = glGetError();
+        if (UNLIKELY(error != GL_NO_ERROR)) {
+            // this failed, for instance, because we don't support NPOT.
+            // FIXME: do something!
+            LOGE("layer=%p, glEGLImageTargetTexture2DOES(%p) "
+                 "failed err=0x%04x",
+                 this, texture->image, error);
+            mFlags &= ~DisplayHardware::DIRECT_TEXTURE;
+            err = INVALID_OPERATION;
+        } else {
+            // Everything went okay!
+            texture->NPOTAdjust = false;
+            texture->dirty  = false;
+            texture->width  = clientBuf->width;
+            texture->height = clientBuf->height;
+        }
+    } else {
+        err = INVALID_OPERATION;
+    }
+    return err;
+}
+
+
 // ---------------------------------------------------------------------------
 
 int32_t LayerBaseClient::sIdentity = 0;
diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h
index efa4f8c..ed07b3f 100644
--- a/libs/surfaceflinger/LayerBase.h
+++ b/libs/surfaceflinger/LayerBase.h
@@ -261,6 +261,8 @@
           void drawWithOpenGL(const Region& clip, const Texture& texture) const;
           void loadTexture(Texture* texture, 
                   const Region& dirty, const GGLSurface& t) const;
+          status_t initializeEglImage(
+                  const sp<GraphicBuffer>& buffer, Texture* texture);
 
           
                 sp<SurfaceFlinger> mFlinger;
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp
index 7e27a02..6590503 100644
--- a/libs/surfaceflinger/LayerBuffer.cpp
+++ b/libs/surfaceflinger/LayerBuffer.cpp
@@ -339,12 +339,6 @@
     mLayer.setNeedsBlending((info.h_alpha - info.l_alpha) > 0);    
     mBufferSize = info.getScanlineSize(buffers.hor_stride)*buffers.ver_stride;
     mLayer.forceVisibilityTransaction();
-
-    hw_module_t const* module;
-    mBlitEngine = NULL;
-    if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
-        copybit_open(module, &mBlitEngine);
-    }
 }
 
 LayerBuffer::BufferSource::~BufferSource()
@@ -352,8 +346,9 @@
     if (mTexture.name != -1U) {
         glDeleteTextures(1, &mTexture.name);
     }
-    if (mBlitEngine) {
-        copybit_close(mBlitEngine);
+    if (mTexture.image != EGL_NO_IMAGE_KHR) {
+        EGLDisplay dpy(mLayer.mFlinger->graphicPlane(0).getEGLDisplay());
+        eglDestroyImageKHR(dpy, mTexture.image);
     }
 }
 
@@ -421,122 +416,28 @@
     status_t err = NO_ERROR;
     NativeBuffer src(ourBuffer->getBuffer());
     const Rect transformedBounds(mLayer.getTransformedBounds());
-    copybit_device_t* copybit = mBlitEngine;
 
-    if (copybit)  {
-        const int src_width  = src.crop.r - src.crop.l;
-        const int src_height = src.crop.b - src.crop.t;
-        int W = transformedBounds.width();
-        int H = transformedBounds.height();
-        if (mLayer.getOrientation() & Transform::ROT_90) {
-            int t(W); W=H; H=t;
-        }
+    if (UNLIKELY(mTexture.name == -1LU)) {
+        mTexture.name = mLayer.createTexture();
+    }
 
-#ifdef EGL_ANDROID_get_render_buffer
-        EGLDisplay dpy = eglGetCurrentDisplay();
-        EGLSurface draw = eglGetCurrentSurface(EGL_DRAW); 
-        EGLClientBuffer clientBuf = eglGetRenderBufferANDROID(dpy, draw);
-        android_native_buffer_t* nb = (android_native_buffer_t*)clientBuf;
-        if (nb == 0) {
-            err = BAD_VALUE;
-        } else {
-            copybit_image_t dst;
-            dst.w       = nb->width;
-            dst.h       = nb->height;
-            dst.format  = nb->format;
-            dst.base    = NULL; // unused by copybit on msm7k
-            dst.handle  = (native_handle_t *)nb->handle;
+#if defined(EGL_ANDROID_image_native_buffer)
+    if (mLayer.mFlags & DisplayHardware::DIRECT_TEXTURE) {
+         // NOTE: Assume the buffer is  allocated with the proper USAGE flags
+        sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
+                src.crop.r, src.crop.b, src.img.format, 
+                GraphicBuffer::USAGE_HW_TEXTURE,
+                src.img.w, src.img.handle, false);
 
-            /* With LayerBuffer, it is likely that we'll have to rescale the
-             * surface, because this is often used for video playback or
-             * camera-preview. Since we want these operation as fast as possible
-             * we make sure we can use the 2D H/W even if it doesn't support
-             * the requested scale factor, in which case we perform the scaling
-             * in several passes. */
-
-            const float min = copybit->get(copybit, COPYBIT_MINIFICATION_LIMIT);
-            const float mag = copybit->get(copybit, COPYBIT_MAGNIFICATION_LIMIT);
-
-            float xscale = 1.0f;
-            if (src_width > W*min)          xscale = 1.0f / min;
-            else if (src_width*mag < W)     xscale = mag;
-
-            float yscale = 1.0f;
-            if (src_height > H*min)         yscale = 1.0f / min;
-            else if (src_height*mag < H)    yscale = mag;
-
-            if (UNLIKELY(xscale!=1.0f || yscale!=1.0f)) {
-                const int tmp_w = floorf(src_width  * xscale);
-                const int tmp_h = floorf(src_height * yscale);
-                
-                if (mTempBitmap==0 || 
-                        mTempBitmap->getWidth() < size_t(tmp_w) || 
-                        mTempBitmap->getHeight() < size_t(tmp_h)) {
-                    mTempBitmap.clear();
-                    mTempBitmap = new GraphicBuffer(
-                            tmp_w, tmp_h, src.img.format, 
-                            GraphicBuffer::USAGE_HW_2D);
-                    err = mTempBitmap->initCheck();
-                }
-
-                if (LIKELY(err == NO_ERROR)) {
-                    NativeBuffer tmp;
-                    tmp.img.w = tmp_w;
-                    tmp.img.h = tmp_h;
-                    tmp.img.format = src.img.format;
-                    tmp.img.handle = (native_handle_t*)mTempBitmap->getNativeBuffer()->handle;
-                    tmp.crop.l = 0;
-                    tmp.crop.t = 0;
-                    tmp.crop.r = tmp.img.w;
-                    tmp.crop.b = tmp.img.h;
-
-                    region_iterator tmp_it(Region(Rect(tmp.crop.r, tmp.crop.b)));
-                    copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
-                    copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
-                    copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
-                    err = copybit->stretch(copybit,
-                            &tmp.img, &src.img, &tmp.crop, &src.crop, &tmp_it);
-                    src = tmp;
-                }
-            }
-
-            const Rect transformedBounds(mLayer.getTransformedBounds());
-            const copybit_rect_t& drect =
-                reinterpret_cast<const copybit_rect_t&>(transformedBounds);
-            const State& s(mLayer.drawingState());
-            region_iterator it(clip);
-
-            // pick the right orientation for this buffer
-            int orientation = mLayer.getOrientation();
-            if (UNLIKELY(mBufferHeap.transform)) {
-                Transform rot90;
-                GraphicPlane::orientationToTransfrom(
-                        ISurfaceComposer::eOrientation90, 0, 0, &rot90);
-                const Transform& planeTransform(mLayer.graphicPlane(0).transform());
-                const Layer::State& s(mLayer.drawingState());
-                Transform tr(planeTransform * s.transform * rot90);
-                orientation = tr.getOrientation();
-            }
-
-            copybit->set_parameter(copybit, COPYBIT_TRANSFORM, orientation);
-            copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
-            copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
-
-            err = copybit->stretch(copybit,
-                    &dst, &src.img, &drect, &src.crop, &it);
-            if (err != NO_ERROR) {
-                LOGE("copybit failed (%s)", strerror(err));
-            }
-        }
+        err = mLayer.initializeEglImage(graphicBuffer, &mTexture);
     }
 #endif
-    
-    if (!copybit || err) 
-    {
+    else {
+        err = INVALID_OPERATION;
+    }
+
+    if (err != NO_ERROR) {
         // OpenGL fall-back
-        if (UNLIKELY(mTexture.name == -1LU)) {
-            mTexture.name = mLayer.createTexture();
-        }
         GLuint w = 0;
         GLuint h = 0;
         GGLSurface t;
@@ -549,11 +450,11 @@
         t.data = (GGLubyte*)src.img.base;
         const Region dirty(Rect(t.width, t.height));
         mLayer.loadTexture(&mTexture, dirty, t);
-        mTexture.transform = mBufferHeap.transform;
-        mLayer.drawWithOpenGL(clip, mTexture);
     }
-}
 
+    mTexture.transform = mBufferHeap.transform;
+    mLayer.drawWithOpenGL(clip, mTexture);
+}
 
 // ---------------------------------------------------------------------------
 
diff --git a/libs/surfaceflinger/LayerBuffer.h b/libs/surfaceflinger/LayerBuffer.h
index 5eb472c..438b711 100644
--- a/libs/surfaceflinger/LayerBuffer.h
+++ b/libs/surfaceflinger/LayerBuffer.h
@@ -132,7 +132,6 @@
         size_t                          mBufferSize;
         mutable sp<GraphicBuffer>       mTempBitmap;
         mutable LayerBase::Texture      mTexture;
-        copybit_device_t*               mBlitEngine;
     };
     
     class OverlaySource : public Source {
diff --git a/libs/surfaceflinger/LayerDim.cpp b/libs/surfaceflinger/LayerDim.cpp
index 538dc77..fd61e30 100644
--- a/libs/surfaceflinger/LayerDim.cpp
+++ b/libs/surfaceflinger/LayerDim.cpp
@@ -55,8 +55,8 @@
     sHeight = h;
     sUseTexture = false;
     
-#ifdef DIM_WITH_TEXTURE
-    
+#if defined(DIM_WITH_TEXTURE) && defined(EGL_ANDROID_image_native_buffer)
+
 #warning "using a texture to implement LayerDim"
     
     /* On some h/w like msm7K, it is faster to use a texture because the
@@ -69,7 +69,6 @@
     uint32_t flags = hw.getFlags();
 
     if (LIKELY(flags & DisplayHardware::DIRECT_TEXTURE)) {
-        // TODO: api to pass the usage flags
         sp<GraphicBuffer> buffer = new GraphicBuffer(w, h, PIXEL_FORMAT_RGB_565,
                  GraphicBuffer::USAGE_SW_WRITE_OFTEN |
                  GraphicBuffer::USAGE_HW_TEXTURE);
@@ -123,7 +122,7 @@
         glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
         glColor4x(0, 0, 0, alpha);
         
-#ifdef DIM_WITH_TEXTURE
+#if defined(DIM_WITH_TEXTURE) && defined(EGL_ANDROID_image_native_buffer)
         if (sUseTexture) {
             glBindTexture(GL_TEXTURE_2D, sTexId);
             glEnable(GL_TEXTURE_2D);
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 1cf20d7..efe2d78 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -37,7 +37,7 @@
 // ===========================================================================
 
 GraphicBuffer::GraphicBuffer()
-    : BASE(), mOwner(false), mBufferMapper(GraphicBufferMapper::get()),
+    : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
       mInitCheck(NO_ERROR),  mVStride(0), mIndex(-1)
 {
     width  = 
@@ -50,7 +50,7 @@
 
 GraphicBuffer::GraphicBuffer(uint32_t w, uint32_t h, 
         PixelFormat reqFormat, uint32_t reqUsage)
-    : BASE(), mOwner(false), mBufferMapper(GraphicBufferMapper::get()),
+    : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
       mInitCheck(NO_ERROR),  mVStride(0), mIndex(-1)
 {
     width  = 
@@ -62,8 +62,23 @@
     mInitCheck = initSize(w, h, reqFormat, reqUsage);
 }
 
+GraphicBuffer::GraphicBuffer(uint32_t w, uint32_t h,
+        PixelFormat inFormat, uint32_t inUsage,
+        uint32_t inStride, native_handle_t* inHandle, bool keepOwnership)
+    : BASE(), mOwner(keepOwnership ? ownHandle : ownNone),
+      mBufferMapper(GraphicBufferMapper::get()),
+      mInitCheck(NO_ERROR),  mVStride(0), mIndex(-1)
+{
+    width  = w;
+    height = h;
+    stride = inStride;
+    format = inFormat;
+    usage  = inUsage;
+    handle = inHandle;
+}
+
 GraphicBuffer::GraphicBuffer(const Parcel& data) 
-    : BASE(), mOwner(true), mBufferMapper(GraphicBufferMapper::get()),
+    : BASE(), mOwner(ownHandle), mBufferMapper(GraphicBufferMapper::get()),
       mInitCheck(NO_ERROR),  mVStride(0), mIndex(-1)
 {
     // we own the handle in this case
@@ -83,10 +98,10 @@
 GraphicBuffer::~GraphicBuffer()
 {
     if (handle) {
-        if (mOwner) {
+        if (mOwner == ownHandle) {
             native_handle_close(handle);
             native_handle_delete(const_cast<native_handle*>(handle));
-        } else {
+        } else if (mOwner == ownData) {
             GraphicBufferAllocator& allocator(GraphicBufferAllocator::get());
             allocator.free(handle);
         }
@@ -106,6 +121,9 @@
 status_t GraphicBuffer::reallocate(uint32_t w, uint32_t h, PixelFormat f,
         uint32_t reqUsage)
 {
+    if (mOwner != ownData)
+        return INVALID_OPERATION;
+
     if (handle) {
         GraphicBufferAllocator& allocator(GraphicBufferAllocator::get());
         allocator.free(handle);
diff --git a/opengl/libagl/Android.mk b/opengl/libagl/Android.mk
index 2522656..9837845 100644
--- a/opengl/libagl/Android.mk
+++ b/opengl/libagl/Android.mk
@@ -25,6 +25,13 @@
 	primitives.cpp.arm	        \
 	vertex.cpp.arm
 
+LOCAL_CFLAGS += -DLOG_TAG=\"libagl\"
+LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+LOCAL_CFLAGS += -fvisibility=hidden
+
+LOCAL_SHARED_LIBRARIES := libcutils libhardware libutils libpixelflinger
+LOCAL_LDLIBS := -lpthread -ldl
+
 ifeq ($(TARGET_ARCH),arm)
 	LOCAL_SRC_FILES += fixed_asm.S iterators.S
 	LOCAL_CFLAGS += -fstrict-aliasing
@@ -38,15 +45,9 @@
 ifeq ($(LIBAGL_USE_GRALLOC_COPYBITS),1)
     LOCAL_CFLAGS += -DLIBAGL_USE_GRALLOC_COPYBITS
     LOCAL_SRC_FILES += copybit.cpp
+    LOCAL_SHARED_LIBRARIES += libui
 endif
 
-LOCAL_CFLAGS += -DLOG_TAG=\"libagl\"
-LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-
-LOCAL_SHARED_LIBRARIES := libcutils libhardware libutils libpixelflinger
-LOCAL_CFLAGS += -fvisibility=hidden
-
-LOCAL_LDLIBS := -lpthread -ldl
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/egl
 LOCAL_MODULE:= libGLES_android
diff --git a/opengl/libagl/copybit.cpp b/opengl/libagl/copybit.cpp
index 73b2355..4b9e59b 100644
--- a/opengl/libagl/copybit.cpp
+++ b/opengl/libagl/copybit.cpp
@@ -33,6 +33,10 @@
 #include <hardware/copybit.h>
 #include <private/ui/android_natives_priv.h>
 
+#include <ui/GraphicBuffer.h>
+#include <ui/Region.h>
+#include <ui/Rect.h>
+
 
 #define DEBUG_COPYBIT true
 
@@ -150,6 +154,8 @@
         int transform,
         ogles_context_t* c)
 {
+    status_t err = NO_ERROR;
+
     // We assume checkContext has already been called and has already
     // returned true.
 
@@ -175,16 +181,6 @@
         dtdy /= screen_h;
     }
     dtdy = -dtdy; // see equation of dtdy above
-    if (dsdx < c->copybits.minScale || dsdx > c->copybits.maxScale
-            || dtdy < c->copybits.minScale || dtdy > c->copybits.maxScale) {
-        // The requested scale is out of the range the hardware
-        // can support.
-        LOGD_IF(DEBUG_COPYBIT,
-                "scale out of range dsdx=%08x (Wcr=%d / w=%d), "
-                "dtdy=%08x (Hcr=%d / h=%d), Ucr=%d, Vcr=%d", 
-                dsdx, Wcr, w, dtdy, Hcr, h, Ucr, Vcr);
-        return false;
-    }
 
     // copybit doesn't say anything about filtering, so we can't
     // discriminate. On msm7k, copybit will always filter.
@@ -206,6 +202,7 @@
     
     const uint32_t enables = c->rasterizer.state.enables;
     int planeAlpha = 255;
+    bool alphaPlaneWorkaround = false;
     static const int tmu = 0;
     texture_t& tev(c->rasterizer.state.texture[tmu]);
     int32_t opFormat = textureObject->surface.format;
@@ -265,9 +262,10 @@
             if (c->currentColorClamped.r == c->currentColorClamped.a &&
                 c->currentColorClamped.g == c->currentColorClamped.a &&
                 c->currentColorClamped.b == c->currentColorClamped.a) {
-                // TODO: Need to emulate: RGBA source, color={a,a,a,a} / premult
-                // and RGBA source, color={1,1,1,a} / regular-blending
-                // (both are equivalent)
+                // TODO: RGBA source, color={1,1,1,a} / regular-blending
+                // is equivalent
+                alphaPlaneWorkaround = true;
+                break;
             }
         }
         LOGD_IF(DEBUG_COPYBIT, "GGL_MODULATE");
@@ -278,28 +276,153 @@
         return false;
     }
 
-
-    // LOGW("calling copybits");
-
     copybit_device_t* copybit = c->copybits.blitEngine;
+    copybit_image_t src;
+    buffer_handle_t source_hnd = textureObject->buffer->handle;
+    textureToCopyBitImage(&textureObject->surface, opFormat, source_hnd, &src);
+    copybit_rect_t srect = { Ucr, Vcr + Hcr, Ucr + Wcr, Vcr };
+
+    /*
+     *  Below we perform extra passes needed to emulate things the h/w
+     * cannot do.
+     */
+
+    const GLfixed minScaleInv = gglDivQ(0x10000, c->copybits.minScale, 16);
+    const GLfixed maxScaleInv = gglDivQ(0x10000, c->copybits.maxScale, 16);
+
+    sp<GraphicBuffer> tempBitmap;
+
+    if (dsdx < maxScaleInv || dsdx > minScaleInv ||
+        dtdy < maxScaleInv || dtdy > minScaleInv)
+    {
+        // The requested scale is out of the range the hardware
+        // can support.
+        LOGD_IF(DEBUG_COPYBIT,
+                "scale out of range dsdx=%08x (Wcr=%d / w=%d), "
+                "dtdy=%08x (Hcr=%d / h=%d), Ucr=%d, Vcr=%d",
+                dsdx, Wcr, w, dtdy, Hcr, h, Ucr, Vcr);
+
+        int32_t xscale=0x10000, yscale=0x10000;
+        if (dsdx > minScaleInv)         xscale = c->copybits.minScale;
+        else if (dsdx < maxScaleInv)    xscale = c->copybits.maxScale;
+        if (dtdy > minScaleInv)         yscale = c->copybits.minScale;
+        else if (dtdy < maxScaleInv)    yscale = c->copybits.maxScale;
+        dsdx = gglMulx(dsdx, xscale);
+        dtdy = gglMulx(dtdy, yscale);
+
+        /* we handle only one step of resizing below. Handling an arbitrary
+         * number is relatively easy (replace "if" above by "while"), but requires
+         * two intermediate buffers and so far we never had the need.
+         */
+
+        if (dsdx < maxScaleInv || dsdx > minScaleInv ||
+            dtdy < maxScaleInv || dtdy > minScaleInv) {
+            LOGD_IF(DEBUG_COPYBIT,
+                    "scale out of range dsdx=%08x (Wcr=%d / w=%d), "
+                    "dtdy=%08x (Hcr=%d / h=%d), Ucr=%d, Vcr=%d",
+                    dsdx, Wcr, w, dtdy, Hcr, h, Ucr, Vcr);
+            return false;
+        }
+
+        const int tmp_w = gglMulx(srect.r - srect.l, xscale, 16);
+        const int tmp_h = gglMulx(srect.b - srect.t, yscale, 16);
+
+        LOGD_IF(DEBUG_COPYBIT,
+                "xscale=%08x, yscale=%08x, dsdx=%08x, dtdy=%08x, tmp_w=%d, tmp_h=%d",
+                xscale, yscale, dsdx, dtdy, tmp_w, tmp_h);
+
+        tempBitmap = new GraphicBuffer(
+                    tmp_w, tmp_h, src.format,
+                    GraphicBuffer::USAGE_HW_2D);
+
+        err = tempBitmap->initCheck();
+        if (err == NO_ERROR) {
+            copybit_image_t tmp_dst;
+            copybit_rect_t tmp_rect;
+            tmp_dst.w = tmp_w;
+            tmp_dst.h = tmp_h;
+            tmp_dst.format = tempBitmap->format;
+            tmp_dst.handle = (native_handle_t*)tempBitmap->getNativeBuffer()->handle;
+            tmp_rect.l = 0;
+            tmp_rect.t = 0;
+            tmp_rect.r = tmp_dst.w;
+            tmp_rect.b = tmp_dst.h;
+            region_iterator tmp_it(Region(Rect(tmp_rect.r, tmp_rect.b)));
+            copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
+            copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
+            copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
+            err = copybit->stretch(copybit,
+                    &tmp_dst, &src, &tmp_rect, &srect, &tmp_it);
+            src = tmp_dst;
+            srect = tmp_rect;
+        }
+    }
 
     copybit_image_t dst;
     buffer_handle_t target_hnd = c->copybits.drawSurfaceBuffer;
     textureToCopyBitImage(&cbSurface, cbSurface.format, target_hnd, &dst);
     copybit_rect_t drect = {x, y, x+w, y+h};
 
-    copybit_image_t src;
-    buffer_handle_t source_hnd = textureObject->buffer->handle;
-    textureToCopyBitImage(&textureObject->surface, opFormat, source_hnd, &src);
-    copybit_rect_t srect = { Ucr, Vcr + Hcr, Ucr + Wcr, Vcr };
 
-    copybit->set_parameter(copybit, COPYBIT_TRANSFORM, transform);
-    copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, planeAlpha);
-    copybit->set_parameter(copybit, COPYBIT_DITHER,
-            (enables & GGL_ENABLE_DITHER) ? COPYBIT_ENABLE : COPYBIT_DISABLE);
+    /* and now the alpha-plane hack. This handles the "Fade" case of a
+     * texture with an alpha channel.
+     */
+    if (alphaPlaneWorkaround) {
+        sp<GraphicBuffer> tempCb = new GraphicBuffer(
+                    w, h, COPYBIT_FORMAT_RGB_565,
+                    GraphicBuffer::USAGE_HW_2D);
 
-    clipRectRegion it(c);
-    status_t err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
+        err = tempCb->initCheck();
+
+        copybit_image_t tmpCbImg;
+        copybit_rect_t tmpCbRect;
+        tmpCbImg.w = w;
+        tmpCbImg.h = h;
+        tmpCbImg.format = tempCb->format;
+        tmpCbImg.handle = (native_handle_t*)tempCb->getNativeBuffer()->handle;
+        tmpCbRect.l = 0;
+        tmpCbRect.t = 0;
+        tmpCbRect.r = w;
+        tmpCbRect.b = h;
+
+        if (!err) {
+            // first make a copy of the destination buffer
+            region_iterator tmp_it(Region(Rect(w, h)));
+            copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
+            copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
+            copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
+            err = copybit->stretch(copybit,
+                    &tmpCbImg, &dst, &tmpCbRect, &drect, &tmp_it);
+        }
+        if (!err) {
+            // then proceed as usual, but without the alpha plane
+            copybit->set_parameter(copybit, COPYBIT_TRANSFORM, transform);
+            copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
+            copybit->set_parameter(copybit, COPYBIT_DITHER,
+                    (enables & GGL_ENABLE_DITHER) ?
+                            COPYBIT_ENABLE : COPYBIT_DISABLE);
+            clipRectRegion it(c);
+            err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
+        }
+        if (!err) {
+            // finally copy back the destination on top with 1-alphaplane
+            int invPlaneAlpha = 0xFF - fixedToByte(c->currentColorClamped.a);
+            clipRectRegion it(c);
+            copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
+            copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, invPlaneAlpha);
+            copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
+            err = copybit->stretch(copybit,
+                    &dst, &tmpCbImg, &drect, &tmpCbRect, &it);
+        }
+    } else {
+        copybit->set_parameter(copybit, COPYBIT_TRANSFORM, transform);
+        copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, planeAlpha);
+        copybit->set_parameter(copybit, COPYBIT_DITHER,
+                (enables & GGL_ENABLE_DITHER) ?
+                        COPYBIT_ENABLE : COPYBIT_DISABLE);
+        clipRectRegion it(c);
+        err = copybit->stretch(copybit, &dst, &src, &drect, &srect, &it);
+    }
     if (err != NO_ERROR) {
         c->textures.tmu[0].texture->try_copybit = false;
     }
diff --git a/opengl/tests/linetex/Android.mk b/opengl/tests/linetex/Android.mk
new file mode 100644
index 0000000..6ff248d
--- /dev/null
+++ b/opengl/tests/linetex/Android.mk
@@ -0,0 +1,17 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	linetex.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils \
+    libEGL \
+    libGLESv1_CM \
+    libui
+
+LOCAL_MODULE:= test-opengl-linetex
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/linetex/linetex.cpp b/opengl/tests/linetex/linetex.cpp
new file mode 100644
index 0000000..e62fe03
--- /dev/null
+++ b/opengl/tests/linetex/linetex.cpp
@@ -0,0 +1,117 @@
+/*
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#define LOG_TAG "fillrate"
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <utils/StopWatch.h>
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+using namespace android;
+
+int main(int argc, char** argv)
+{
+    EGLint configAttribs[] = {
+         EGL_DEPTH_SIZE, 0,
+         EGL_NONE
+     };
+     
+     EGLint majorVersion;
+     EGLint minorVersion;
+     EGLContext context;
+     EGLConfig config;
+     EGLSurface surface;
+     EGLint w, h;
+     EGLDisplay dpy;
+
+     EGLNativeWindowType window = android_createDisplaySurface();
+     
+     dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+     eglInitialize(dpy, &majorVersion, &minorVersion);
+          
+     status_t err = EGLUtils::selectConfigForNativeWindow(
+             dpy, configAttribs, window, &config);
+     if (err) {
+         fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n");
+         return 0;
+     }
+
+     surface = eglCreateWindowSurface(dpy, config, window, NULL);
+     context = eglCreateContext(dpy, config, NULL, NULL);
+     eglMakeCurrent(dpy, surface, surface, context);   
+     eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
+     eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
+     
+     printf("w=%d, h=%d\n", w, h);
+     
+     glBindTexture(GL_TEXTURE_2D, 0);
+     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+     glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+     glDisable(GL_DITHER);
+     glDisable(GL_BLEND);
+     glEnable(GL_TEXTURE_2D);
+     glColor4f(1,1,1,1);
+
+     const uint32_t t32[] = {
+             0xFFFFFFFF, 0xFF0000FF, 0xFF00FF00, 0xFFFF0000,
+             0xFFFFFF00, 0xFFFF00FF, 0xFF00FFFF, 0xFF000000
+     };
+
+     const GLfloat vertices[4][2] = {
+             { 0,  0 },
+             { w,  h }
+     };
+
+     const GLfloat texCoords[4][2] = {
+             { 0,  0 },
+             { 1,  0 }
+     };
+
+     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 8, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, t32);
+
+     glViewport(0, 0, w, h);
+     glMatrixMode(GL_PROJECTION);
+     glLoadIdentity();
+     glOrthof(0, w, 0, h, 0, 1);
+
+     glEnableClientState(GL_VERTEX_ARRAY);
+     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+     glVertexPointer(2, GL_FLOAT, 0, vertices);
+     glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
+
+     glClearColor(0,0,0,0);
+     glClear(GL_COLOR_BUFFER_BIT);
+     glDrawArrays(GL_LINES, 0, 2);
+     eglSwapBuffers(dpy, surface);
+
+     usleep(5*1000000);
+
+     eglTerminate(dpy);
+     
+     return 0;
+}