Bug 803471 - Part 5a - Split GonkNativeWindow to GonkNativeWindow and GonkNativeWindowClient. r=kchen, a=leo+
authorSotaro Ikeda <sikeda@mozilla.com>
Fri, 08 Mar 2013 14:43:32 -0500
changeset 118720 46283b144f446cdf38b72e7ddffb7ae85fc5f4d6
parent 118719 24505d927c2eeb6635f4de800cfd1e0a2c6909da
child 118721 ea270327e0fb88a9adf69de8168f761a2e4949b2
push id540
push userryanvm@gmail.com
push dateTue, 12 Mar 2013 01:17:01 +0000
reviewerskchen, leo
bugs803471
milestone18.0
Bug 803471 - Part 5a - Split GonkNativeWindow to GonkNativeWindow and GonkNativeWindowClient. r=kchen, a=leo+
dom/camera/GonkNativeWindow.cpp
dom/camera/GonkNativeWindow.h
dom/camera/GonkNativeWindowClient.cpp
dom/camera/GonkNativeWindowClient.h
--- a/dom/camera/GonkNativeWindow.cpp
+++ b/dom/camera/GonkNativeWindow.cpp
@@ -1,10 +1,8 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* vim: set ts=4 et sw=4 tw=80: */
 /*
  * Copyright (C) 2010 The Android Open Source Project
  * Copyright (C) 2012 Mozilla Foundation
  *
  * 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
  *
@@ -32,120 +30,49 @@
  * CNW_LOGE() is always enabled.
  */
 #define CNW_LOGD(...)   DOM_CAMERA_LOGI(__VA_ARGS__)
 #define CNW_LOGE(...)   {(void)printf_stderr(__VA_ARGS__);}
 
 using namespace android;
 using namespace mozilla::layers;
 
-GonkNativeWindow::GonkNativeWindow(GonkNativeWindowNewFrameCallback* aCallback)
-  : mNewFrameCallback(aCallback)
-{
-    GonkNativeWindow::init();
+GonkNativeWindow::GonkNativeWindow() :
+    mDefaultWidth(1),
+    mDefaultHeight(1),
+    mPixelFormat(PIXEL_FORMAT_RGBA_8888),
+    mBufferCount(MIN_BUFFER_SLOTS + 1),
+    mConnectedApi(NO_CONNECTED_API),
+    mAbandoned(false),
+    mFrameCounter(0),
+    mGeneration(0),
+    mNewFrameCallback(nullptr) {
 }
 
-GonkNativeWindow::GonkNativeWindow()
-  : mNewFrameCallback(nullptr)
-{
-    GonkNativeWindow::init();
-}
-
-GonkNativeWindow::~GonkNativeWindow()
-{
+GonkNativeWindow::~GonkNativeWindow() {
     nsAutoTArray<SurfaceDescriptor, NUM_BUFFER_SLOTS> freeList;
     freeAllBuffersLocked(freeList);
     releaseBufferFreeListUnlocked(freeList);
 }
 
 void GonkNativeWindow::abandon()
 {
+    CNW_LOGD("abandon");
     nsAutoTArray<SurfaceDescriptor, NUM_BUFFER_SLOTS> freeList;
     {
         Mutex::Autolock lock(mMutex);
+        mQueue.clear();
         mAbandoned = true;
         freeAllBuffersLocked(freeList);
     }
 
     releaseBufferFreeListUnlocked(freeList);
     mDequeueCondition.signal();
 }
 
-void GonkNativeWindow::init()
-{
-    // Initialize the ANativeWindow function pointers.
-    ANativeWindow::setSwapInterval  = hook_setSwapInterval;
-    ANativeWindow::dequeueBuffer    = hook_dequeueBuffer;
-    ANativeWindow::cancelBuffer     = hook_cancelBuffer;
-    ANativeWindow::lockBuffer       = hook_lockBuffer;
-    ANativeWindow::queueBuffer      = hook_queueBuffer;
-    ANativeWindow::query            = hook_query;
-    ANativeWindow::perform          = hook_perform;
-
-    mDefaultWidth = 0;
-    mDefaultHeight = 0;
-    mPixelFormat = 0;
-    mUsage = 0;
-    mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
-    mBufferCount = MIN_BUFFER_SLOTS;
-    mFrameCounter = 0;
-    mGeneration = 0;
-    mAbandoned =false;
-}
-
-
-int GonkNativeWindow::hook_setSwapInterval(ANativeWindow* window, int interval)
-{
-    GonkNativeWindow* c = getSelf(window);
-    return c->setSwapInterval(interval);
-}
-
-int GonkNativeWindow::hook_dequeueBuffer(ANativeWindow* window,
-        ANativeWindowBuffer** buffer)
-{
-    GonkNativeWindow* c = getSelf(window);
-    return c->dequeueBuffer(buffer);
-}
-
-int GonkNativeWindow::hook_cancelBuffer(ANativeWindow* window,
-        ANativeWindowBuffer* buffer)
-{
-    GonkNativeWindow* c = getSelf(window);
-    return c->cancelBuffer(buffer);
-}
-
-int GonkNativeWindow::hook_lockBuffer(ANativeWindow* window,
-        ANativeWindowBuffer* buffer)
-{
-    GonkNativeWindow* c = getSelf(window);
-    return c->lockBuffer(buffer);
-}
-
-int GonkNativeWindow::hook_queueBuffer(ANativeWindow* window,
-        ANativeWindowBuffer* buffer)
-{
-    GonkNativeWindow* c = getSelf(window);
-    return c->queueBuffer(buffer);
-}
-
-int GonkNativeWindow::hook_query(const ANativeWindow* window,
-                                int what, int* value)
-{
-    const GonkNativeWindow* c = getSelf(window);
-    return c->query(what, value);
-}
-
-int GonkNativeWindow::hook_perform(ANativeWindow* window, int operation, ...)
-{
-    va_list args;
-    va_start(args, operation);
-    GonkNativeWindow* c = getSelf(window);
-    return c->perform(operation, args);
-}
-
 void GonkNativeWindow::freeAllBuffersLocked(nsTArray<SurfaceDescriptor>& freeList)
 {
     CNW_LOGD("freeAllBuffersLocked: from generation %d", mGeneration);
     ++mGeneration;
 
     for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
         if (mSlots[i].mGraphicBuffer != NULL) {
             // Don't try to destroy the gralloc buffer if it is still in the
@@ -189,17 +116,17 @@ void GonkNativeWindow::clearRenderingSta
                 mSlots[i].mGraphicBuffer = NULL;
                 mSlots[i].mBufferState = BufferSlot::FREE;
                 mSlots[i].mFrameNumber = 0;
             }
         }
     }
 }
 
-int GonkNativeWindow::setBufferCount(int bufferCount)
+status_t GonkNativeWindow::setBufferCount(int bufferCount)
 {
     CNW_LOGD("setBufferCount: count=%d", bufferCount);
     nsAutoTArray<SurfaceDescriptor, NUM_BUFFER_SLOTS> freeList;
 
     {
         Mutex::Autolock lock(mMutex);
 
         if (mAbandoned) {
@@ -225,38 +152,76 @@ int GonkNativeWindow::setBufferCount(int
                 return -EINVAL;
             }
         }
 
         if (bufferCount >= mBufferCount) {
             mBufferCount = bufferCount;
             //clear only buffers in RENDERING state.
             clearRenderingStateBuffersLocked();
+            mQueue.clear();
             mDequeueCondition.signal();
             return OK;
         }
 
-        // reducing the number of buffers
         // here we're guaranteed that the client doesn't have dequeued buffers
         // and will release all of its buffer references.
         freeAllBuffersLocked(freeList);
         mBufferCount = bufferCount;
+        mQueue.clear();
         mDequeueCondition.signal();
     }
 
     releaseBufferFreeListUnlocked(freeList);
     return OK;
 }
 
-int GonkNativeWindow::dequeueBuffer(android_native_buffer_t** buffer)
+status_t GonkNativeWindow::setDefaultBufferSize(uint32_t w, uint32_t h)
+{
+    CNW_LOGD("setDefaultBufferSize: w=%d, h=%d", w, h);
+    if (!w || !h) {
+        CNW_LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)",
+                w, h);
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock lock(mMutex);
+    mDefaultWidth = w;
+    mDefaultHeight = h;
+    return OK;
+}
+
+status_t GonkNativeWindow::requestBuffer(int slot, sp<GraphicBuffer>* buf)
 {
-    uint32_t defaultWidth;
-    uint32_t defaultHeight;
-    uint32_t pixelFormat;
-    uint32_t usage;
+    CNW_LOGD("requestBuffer: slot=%d", slot);
+    Mutex::Autolock lock(mMutex);
+    if (mAbandoned) {
+        CNW_LOGE("requestBuffer: GonkNativeWindow has been abandoned!");
+        return NO_INIT;
+    }
+    if (slot < 0 || mBufferCount <= slot) {
+        CNW_LOGE("requestBuffer: slot index out of range [0, %d]: %d",
+                mBufferCount, slot);
+        return BAD_VALUE;
+    }
+    mSlots[slot].mRequestBufferCalled = true;
+    *buf = mSlots[slot].mGraphicBuffer;
+    return NO_ERROR;
+}
+
+status_t GonkNativeWindow::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
+        uint32_t format, uint32_t usage)
+{
+    if ((w && !h) || (!w && h)) {
+        CNW_LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h);
+        return BAD_VALUE;
+    }
+
+    status_t returnFlags(OK);
+    bool updateFormat = false;
     uint32_t generation;
     bool alloc = false;
     int buf = INVALID_BUFFER_SLOT;
     SurfaceDescriptor descOld;
 
     {
         Mutex::Autolock lock(mMutex);
         generation = mGeneration;
@@ -325,56 +290,62 @@ int GonkNativeWindow::dequeueBuffer(andr
 
         if (found == INVALID_BUFFER_SLOT) {
             // This should not happen.
             CNW_LOGE("dequeueBuffer: no available buffer slots");
             return -EBUSY;
         }
 
         buf = found;
+        *outBuf = found;
 
-        // buffer is now in DEQUEUED
+        const bool useDefaultSize = !w && !h;
+        if (useDefaultSize) {
+            // use the default size
+            w = mDefaultWidth;
+            h = mDefaultHeight;
+        }
+
+        updateFormat = (format != 0);
+        if (!updateFormat) {
+            // keep the current (or default) format
+            format = mPixelFormat;
+        }
+
         mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
 
         const sp<GraphicBuffer>& gbuf(mSlots[buf].mGraphicBuffer);
         alloc = (gbuf == NULL);
         if ((gbuf!=NULL) &&
-           ((uint32_t(gbuf->width)  != mDefaultWidth) ||
-            (uint32_t(gbuf->height) != mDefaultHeight) ||
-            (uint32_t(gbuf->format) != mPixelFormat) ||
-            ((uint32_t(gbuf->usage) & mUsage) != mUsage))) {
+           ((uint32_t(gbuf->width)  != w) ||
+            (uint32_t(gbuf->height) != h) ||
+            (uint32_t(gbuf->format) != format) ||
+            ((uint32_t(gbuf->usage) & usage) != usage))) {
             alloc = true;
             descOld = mSlots[buf].mSurfaceDescriptor;
         }
-
-        if (alloc) {
-            // get local copies for graphics buffer allocations
-            defaultWidth = mDefaultWidth;
-            defaultHeight = mDefaultHeight;
-            pixelFormat = mPixelFormat;
-            usage = mUsage;
-        }
     }
     
     // At this point, the buffer is now marked DEQUEUED, and no one else
     // should touch it, except for freeAllBuffersLocked(); we handle that
     // after trying to create the surface descriptor below.
     //
     // So we don't need mMutex locked, which would otherwise run the risk
     // of a deadlock on calling AllocSurfaceDescriptorGralloc().    
 
     SurfaceDescriptor desc;
     ImageBridgeChild* ibc;
     sp<GraphicBuffer> graphicBuffer;
     if (alloc) {
+        usage |= GraphicBuffer::USAGE_HW_TEXTURE;
         status_t error;
         ibc = ImageBridgeChild::GetSingleton();
         CNW_LOGD("dequeueBuffer: about to alloc surface descriptor");
-        ibc->AllocSurfaceDescriptorGralloc(gfxIntSize(defaultWidth, defaultHeight),
-                                           pixelFormat,
+        ibc->AllocSurfaceDescriptorGralloc(gfxIntSize(w, h),
+                                           format,
                                            usage,
                                            &desc);
         // We can only use a gralloc buffer here.  If we didn't get
         // one back, something went wrong.
         CNW_LOGD("dequeueBuffer: got surface descriptor");
         if (SurfaceDescriptor::TSurfaceDescriptorGralloc != desc.type()) {
             MOZ_ASSERT(SurfaceDescriptor::T__None == desc.type());
             CNW_LOGE("dequeueBuffer: failed to alloc gralloc buffer");
@@ -387,40 +358,51 @@ int GonkNativeWindow::dequeueBuffer(andr
             return error;
         }
     }
 
     bool tooOld = false;
     {
         Mutex::Autolock lock(mMutex);
         if (generation == mGeneration) {
+            if (updateFormat) {
+                mPixelFormat = format;
+            }
             if (alloc) {
                 mSlots[buf].mGraphicBuffer = graphicBuffer;
                 mSlots[buf].mSurfaceDescriptor = desc;
                 mSlots[buf].mSurfaceDescriptor.get_SurfaceDescriptorGralloc().external() = true;
+                mSlots[buf].mRequestBufferCalled = false;
+
+                returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
             }
-            *buffer = mSlots[buf].mGraphicBuffer.get();
-
             CNW_LOGD("dequeueBuffer: returning slot=%d buf=%p ", buf,
                     mSlots[buf].mGraphicBuffer->handle);
         } else {
-            *buffer = nullptr;
             tooOld = true;
         }
     }
 
     if (alloc && IsSurfaceDescriptorValid(descOld)) {
         ibc->DeallocSurfaceDescriptorGralloc(descOld);
     }
 
     if (alloc && tooOld) {
         ibc->DeallocSurfaceDescriptorGralloc(desc);
     }
 
+    CNW_LOGD("dequeueBuffer: returning slot=%d buf=%p ", buf,
+            mSlots[buf].mGraphicBuffer->handle );
+
     CNW_LOGD("dequeueBuffer: X");
+    return returnFlags;
+}
+
+status_t GonkNativeWindow::setSynchronousMode(bool enabled)
+{
     return NO_ERROR;
 }
 
 int GonkNativeWindow::getSlotFromBufferLocked(
         android_native_buffer_t* buffer) const
 {
     if (buffer == NULL) {
         CNW_LOGE("getSlotFromBufferLocked: encountered NULL buffer");
@@ -443,52 +425,53 @@ GonkNativeWindow::getSurfaceDescriptorFr
   if (buf < 0 || buf >= mBufferCount ||
       mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
     return nullptr;
   }
 
   return &mSlots[buf].mSurfaceDescriptor;
 }
 
-int GonkNativeWindow::queueBuffer(ANativeWindowBuffer* buffer)
+status_t GonkNativeWindow::queueBuffer(int buf, int64_t timestamp,
+        uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform)
 {
     {
         Mutex::Autolock lock(mMutex);
         CNW_LOGD("queueBuffer: E");
 
         if (mAbandoned) {
             CNW_LOGE("queueBuffer: GonkNativeWindow has been abandoned!");
             return NO_INIT;
         }
-
-        int buf = getSlotFromBufferLocked(buffer);
-
         if (buf < 0 || buf >= mBufferCount) {
             CNW_LOGE("queueBuffer: slot index out of range [0, %d]: %d",
                      mBufferCount, buf);
             return -EINVAL;
         } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
             CNW_LOGE("queueBuffer: slot %d is not owned by the client "
                      "(state=%d)", buf, mSlots[buf].mBufferState);
             return -EINVAL;
+        } else if (!mSlots[buf].mRequestBufferCalled) {
+            CNW_LOGE("queueBuffer: slot %d was enqueued without requesting a "
+                    "buffer", buf);
+            return -EINVAL;
         }
 
-        int64_t timestamp;
-        if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) {
-            timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
-        } else {
-            timestamp = mTimestamp;
-        }
+        mQueue.push_back(buf);
 
         mSlots[buf].mBufferState = BufferSlot::QUEUED;
         mSlots[buf].mTimestamp = timestamp;
         mFrameCounter++;
         mSlots[buf].mFrameNumber = mFrameCounter;
 
         mDequeueCondition.signal();
+
+        *outWidth = mDefaultWidth;
+        *outHeight = mDefaultHeight;
+        *outTransform = 0;
     }
 
     // OnNewFrame might call lockCurrentBuffer so we must release the
     // mutex first.
     if (mNewFrameCallback) {
       mNewFrameCallback->OnNewFrame();
     }
     CNW_LOGD("queueBuffer: X");
@@ -502,36 +485,29 @@ GonkNativeWindow::getCurrentBuffer()
   CNW_LOGD("GonkNativeWindow::getCurrentBuffer");
   Mutex::Autolock lock(mMutex);
 
   if (mAbandoned) {
     CNW_LOGE("getCurrentBuffer: GonkNativeWindow has been abandoned!");
     return NULL;
   }
 
-  int found = -1;
-  for (int i = 0; i < mBufferCount; i++) {
-    const int state = mSlots[i].mBufferState;
-    if (state == BufferSlot::QUEUED) {
-      if (found < 0 ||
-          mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) {
-        found = i;
-      }
-    }
+  if(mQueue.empty()) {
+    mDequeueCondition.signal();
+    return nullptr;
   }
 
-  if (found < 0) {
-    mDequeueCondition.signal();
-    return NULL;
-  }
+  Fifo::iterator front(mQueue.begin());
+  int buf = *front;
 
-  mSlots[found].mBufferState = BufferSlot::RENDERING;
+  mSlots[buf].mBufferState = BufferSlot::RENDERING;
 
   nsRefPtr<GraphicBufferLocked> ret =
-    new CameraGraphicBuffer(this, found, mGeneration, mSlots[found].mSurfaceDescriptor);
+    new CameraGraphicBuffer(this, buf, mGeneration, mSlots[buf].mSurfaceDescriptor);
+  mQueue.erase(front);
   mDequeueCondition.signal();
   return ret.forget();
 }
 
 bool
 GonkNativeWindow::returnBuffer(uint32_t aIndex, uint32_t aGeneration)
 {
   CNW_LOGD("GonkNativeWindow::returnBuffer: slot=%d (generation=%d)", aIndex, aGeneration);
@@ -558,88 +534,133 @@ GonkNativeWindow::returnBuffer(uint32_t 
     return false;
   }
 
   mSlots[aIndex].mBufferState = BufferSlot::FREE;
   mDequeueCondition.signal();
   return true;
 }
 
-int GonkNativeWindow::lockBuffer(ANativeWindowBuffer* buffer)
-{
-    CNW_LOGD("GonkNativeWindow::lockBuffer");
-    Mutex::Autolock lock(mMutex);
-
-    if (mAbandoned) {
-        CNW_LOGE("lockBuffer: GonkNativeWindow has been abandoned!");
-        return NO_INIT;
-    }
-    return OK;
-}
-
-int GonkNativeWindow::cancelBuffer(ANativeWindowBuffer* buffer)
-{
+void GonkNativeWindow::cancelBuffer(int buf) {
+    CNW_LOGD("cancelBuffer: slot=%d", buf);
     Mutex::Autolock lock(mMutex);
 
     if (mAbandoned) {
         CNW_LOGD("cancelBuffer: GonkNativeWindow has been abandoned!");
-        return NO_INIT;
+        return;
     }
-    int buf = getSlotFromBufferLocked(buffer);
 
-    CNW_LOGD("cancelBuffer: slot=%d", buf);
     if (buf < 0 || buf >= mBufferCount) {
         CNW_LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
                 mBufferCount, buf);
-        return -EINVAL;
+        return;
     } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
         CNW_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)",
                 buf, mSlots[buf].mBufferState);
-        return -EINVAL;
+        return;
     }
     mSlots[buf].mBufferState = BufferSlot::FREE;
     mSlots[buf].mFrameNumber = 0;
     mDequeueCondition.signal();
+}
+
+status_t GonkNativeWindow::setCrop(const Rect& crop) {
+    return OK;
+}
+
+status_t GonkNativeWindow::setTransform(uint32_t transform) {
     return OK;
 }
 
-int GonkNativeWindow::perform(int operation, va_list args)
-{
-    switch (operation) {
-        case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
-        case NATIVE_WINDOW_SET_BUFFERS_SIZE:
-        case NATIVE_WINDOW_SET_SCALING_MODE:
-        case NATIVE_WINDOW_SET_CROP:
-        case NATIVE_WINDOW_CONNECT:
-        case NATIVE_WINDOW_DISCONNECT:
-            // deprecated. must return NO_ERROR.
-            return NO_ERROR;
-        case NATIVE_WINDOW_SET_USAGE:
-            return dispatchSetUsage(args);
-        case NATIVE_WINDOW_SET_BUFFER_COUNT:
-            return dispatchSetBufferCount(args);
-        case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
-            return dispatchSetBuffersGeometry(args);
-        case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
-            return dispatchSetBuffersTimestamp(args);
-        case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
-            return dispatchSetBuffersDimensions(args);
-        case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
-            return dispatchSetBuffersFormat(args);
-        case NATIVE_WINDOW_LOCK:
-        case NATIVE_WINDOW_UNLOCK_AND_POST:
-        case NATIVE_WINDOW_API_CONNECT:
-        case NATIVE_WINDOW_API_DISCONNECT:
+status_t GonkNativeWindow::connect(int api,
+        uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
+    CNW_LOGD("connect: api=%d", api);
+    Mutex::Autolock lock(mMutex);
+
+    if (mAbandoned) {
+        CNW_LOGE("connect: GonkNativeWindow has been abandoned!");
+        return NO_INIT;
+    }
+
+    int err = NO_ERROR;
+    switch (api) {
+        case NATIVE_WINDOW_API_EGL:
+        case NATIVE_WINDOW_API_CPU:
+        case NATIVE_WINDOW_API_MEDIA:
+        case NATIVE_WINDOW_API_CAMERA:
+            if (mConnectedApi != NO_CONNECTED_API) {
+                CNW_LOGE("connect: already connected (cur=%d, req=%d)",
+                        mConnectedApi, api);
+                err = -EINVAL;
+            } else {
+                mConnectedApi = api;
+                *outWidth = mDefaultWidth;
+                *outHeight = mDefaultHeight;
+                *outTransform = 0;
+            }
+            break;
         default:
-            NS_WARNING("Unsupported operation");
-            return INVALID_OPERATION;
+            err = -EINVAL;
+            break;
     }
+    return err;
 }
 
-int GonkNativeWindow::query(int what, int* outValue) const
+status_t GonkNativeWindow::disconnect(int api) {
+    CNW_LOGD("disconnect: api=%d", api);
+
+    int err = NO_ERROR;
+    nsAutoTArray<SurfaceDescriptor, NUM_BUFFER_SLOTS> freeList;
+    {
+        Mutex::Autolock lock(mMutex);
+
+        if (mAbandoned) {
+            // it is not really an error to disconnect after the surface
+            // has been abandoned, it should just be a no-op.
+            return NO_ERROR;
+        }
+
+        switch (api) {
+            case NATIVE_WINDOW_API_EGL:
+            case NATIVE_WINDOW_API_CPU:
+            case NATIVE_WINDOW_API_MEDIA:
+            case NATIVE_WINDOW_API_CAMERA:
+                if (mConnectedApi == api) {
+                    mQueue.clear();
+                    freeAllBuffersLocked(freeList);
+                    mConnectedApi = NO_CONNECTED_API;
+                    mDequeueCondition.signal();
+                } else {
+                    CNW_LOGE("disconnect: connected to another api (cur=%d, req=%d)",
+                            mConnectedApi, api);
+                    err = -EINVAL;
+                }
+                break;
+            default:
+                CNW_LOGE("disconnect: unknown API %d", api);
+                err = -EINVAL;
+                break;
+        }
+    }
+    releaseBufferFreeListUnlocked(freeList);
+    return err;
+}
+
+status_t GonkNativeWindow::setScalingMode(int mode) {
+    return OK;
+}
+
+void GonkNativeWindow::setNewFrameCallback(
+        GonkNativeWindowNewFrameCallback* aCallback) {
+    CNW_LOGD("setNewFrameCallback");
+    Mutex::Autolock lock(mMutex);
+    mNewFrameCallback = aCallback;
+}
+
+int GonkNativeWindow::query(int what, int* outValue)
 {
     Mutex::Autolock lock(mMutex);
 
     if (mAbandoned) {
         CNW_LOGE("query: GonkNativeWindow has been abandoned!");
         return NO_INIT;
     }
 
@@ -658,123 +679,8 @@ int GonkNativeWindow::query(int what, in
         value = MIN_UNDEQUEUED_BUFFERS;
         break;
     default:
         return BAD_VALUE;
     }
     outValue[0] = value;
     return NO_ERROR;
 }
-
-int GonkNativeWindow::setSwapInterval(int interval)
-{
-    return NO_ERROR;
-}
-
-int GonkNativeWindow::dispatchSetUsage(va_list args)
-{
-    int usage = va_arg(args, int);
-    return setUsage(usage);
-}
-
-int GonkNativeWindow::dispatchSetBufferCount(va_list args)
-{
-    size_t bufferCount = va_arg(args, size_t);
-    return setBufferCount(bufferCount);
-}
-
-int GonkNativeWindow::dispatchSetBuffersGeometry(va_list args)
-{
-    int w = va_arg(args, int);
-    int h = va_arg(args, int);
-    int f = va_arg(args, int);
-    int err = setBuffersDimensions(w, h);
-    if (err != 0) {
-        return err;
-    }
-    return setBuffersFormat(f);
-}
-
-int GonkNativeWindow::dispatchSetBuffersDimensions(va_list args)
-{
-    int w = va_arg(args, int);
-    int h = va_arg(args, int);
-    return setBuffersDimensions(w, h);
-}
-
-int GonkNativeWindow::dispatchSetBuffersFormat(va_list args)
-{
-    int f = va_arg(args, int);
-    return setBuffersFormat(f);
-}
-
-int GonkNativeWindow::dispatchSetBuffersTimestamp(va_list args)
-{
-    int64_t timestamp = va_arg(args, int64_t);
-    return setBuffersTimestamp(timestamp);
-}
-
-int GonkNativeWindow::setUsage(uint32_t reqUsage)
-{
-    CNW_LOGD("GonkNativeWindow::setUsage");
-    Mutex::Autolock lock(mMutex);
-
-    if (mAbandoned) {
-        CNW_LOGE("setUsage: GonkNativeWindow has been abandoned!");
-        return NO_INIT;
-    }
-    mUsage = reqUsage;
-    return OK;
-}
-
-int GonkNativeWindow::setBuffersDimensions(int w, int h)
-{
-    CNW_LOGD("GonkNativeWindow::setBuffersDimensions");
-    Mutex::Autolock lock(mMutex);
-
-    if (mAbandoned) {
-        CNW_LOGE("setBuffersDimensions: GonkNativeWindow has been abandoned!");
-        return NO_INIT;
-    }
-
-    if (w<0 || h<0)
-        return BAD_VALUE;
-
-    if ((w && !h) || (!w && h))
-        return BAD_VALUE;
-
-    mDefaultWidth = w;
-    mDefaultHeight = h;
-
-    return OK;
-}
-
-int GonkNativeWindow::setBuffersFormat(int format)
-{
-    CNW_LOGD("GonkNativeWindow::setBuffersFormat");
-    Mutex::Autolock lock(mMutex);
-
-    if (mAbandoned) {
-        CNW_LOGE("setBuffersFormat: GonkNativeWindow has been abandoned!");
-        return NO_INIT;
-    }
-
-    if (format<0)
-        return BAD_VALUE;
-
-    mPixelFormat = format;
-
-    return NO_ERROR;
-}
-
-int GonkNativeWindow::setBuffersTimestamp(int64_t timestamp)
-{
-    CNW_LOGD("GonkNativeWindow::setBuffersTimestamp");
-    Mutex::Autolock lock(mMutex);
-
-    if (mAbandoned) {
-        CNW_LOGE("setBuffersTimestamp: GonkNativeWindow has been abandoned!");
-        return NO_INIT;
-    }
-
-    mTimestamp = timestamp;
-    return OK;
-}
--- a/dom/camera/GonkNativeWindow.h
+++ b/dom/camera/GonkNativeWindow.h
@@ -1,10 +1,8 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* vim: set ts=4 et sw=4 tw=80: */
 /*
  * Copyright (C) 2010 The Android Open Source Project
  * Copyright (C) 2012 Mozilla Foundation
  *
  * 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
  *
@@ -18,23 +16,22 @@
  */
 
 #ifndef DOM_CAMERA_GONKNATIVEWINDOW_H
 #define DOM_CAMERA_GONKNATIVEWINDOW_H
 
 #include <stdint.h>
 #include <sys/types.h>
 
+#include <gui/ISurfaceTexture.h>
 #include <ui/egl/android_natives.h>
-
+#include <ui/GraphicBuffer.h>
+#include <ui/Rect.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
-
-#include <ui/GraphicBuffer.h>
-#include <ui/Rect.h>
 #include <utils/String8.h>
 #include <utils/threads.h>
 
 #include "mozilla/layers/LayersSurfaces.h"
 #include "mozilla/layers/ImageBridgeChild.h"
 #include "GonkIOSurfaceImage.h"
 #include "CameraCommon.h"
 
@@ -42,67 +39,114 @@ namespace android {
 
 // The user of GonkNativeWindow who wants to receive notification of
 // new frames should implement this interface.
 class GonkNativeWindowNewFrameCallback {
 public:
     virtual void OnNewFrame() = 0;
 };
 
-class GonkNativeWindow : public EGLNativeBase<ANativeWindow, GonkNativeWindow, RefBase>
+class GonkNativeWindow : public BnSurfaceTexture
 {
+    friend class GonkNativeWindowClient;
+
     typedef mozilla::layers::SurfaceDescriptor SurfaceDescriptor;
     typedef mozilla::layers::GraphicBufferLocked GraphicBufferLocked;
 
 public:
     enum { MIN_UNDEQUEUED_BUFFERS = 2 };
     enum { MIN_BUFFER_SLOTS = MIN_UNDEQUEUED_BUFFERS };
     enum { NUM_BUFFER_SLOTS = 32 };
+    enum { NO_CONNECTED_API = 0 };
     enum { NATIVE_WINDOW_SET_BUFFERS_SIZE = 0x10000000 };
 
     GonkNativeWindow();
-    GonkNativeWindow(GonkNativeWindowNewFrameCallback* aCallback);
     ~GonkNativeWindow(); // this class cannot be overloaded
 
-    // ANativeWindow hooks
-    static int hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
-    static int hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
-    static int hook_lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
-    static int hook_perform(ANativeWindow* window, int operation, ...);
-    static int hook_query(const ANativeWindow* window, int what, int* value);
-    static int hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
-    static int hook_setSwapInterval(ANativeWindow* window, int interval);
-
     // Get next frame from the queue and mark it as RENDERING, caller
     // owns the returned buffer.
     already_AddRefed<GraphicBufferLocked> getCurrentBuffer();
 
     // Return the buffer to the queue and mark it as FREE. After that
     // the buffer is useable again for the decoder.
     bool returnBuffer(uint32_t index, uint32_t generation);
 
-    // Release all internal buffers
+    // setBufferCount updates the number of available buffer slots.  After
+    // calling this all buffer slots are owned by the GonkNativeWindow object
+    // (i.e. they are not owned by the client).
+    virtual status_t setBufferCount(int bufferCount);
+
+    // requestBuffer requests a new buffer for the given index.
+    virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf);
+
+    // dequeueBuffer gets the next buffer slot index for the client to use. If a
+    // buffer slot is available then that slot index is written to the location
+    // pointed to by the buf argument and a status of OK is returned.  If no
+    // slot is available then a status of -EBUSY is returned and buf is
+    // unmodified.
+    virtual status_t dequeueBuffer(int *buf, uint32_t width, uint32_t height,
+            uint32_t format, uint32_t usage);
+
+    // queueBuffer returns a filled buffer to the GonkNativeWindow. In addition,
+    // a timestamp must be provided for the buffer. The timestamp is in
+    // nanoseconds, and must be monotonically increasing. Its other semantics
+    // (zero point, etc) are client-dependent and should be documented by the
+    // client.
+    virtual status_t queueBuffer(int buf, int64_t timestamp,
+            uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform);
+    virtual void cancelBuffer(int buf);
+    virtual status_t setCrop(const Rect& reg);
+    virtual status_t setTransform(uint32_t transform);
+    virtual status_t setScalingMode(int mode);
+
+    virtual int query(int what, int* value);
+
+    // Qcom specific function
+    virtual int performQcomOperation(int operation, int arg1, int arg2, int arg3) {
+        return OK;
+    }
+
+    // GonkNativeWindow do not implement the function and always works in
+    // synchronous mode.
+    virtual status_t setSynchronousMode(bool enabled);
+
+    // connect attempts to connect a client API to the GonkNativeWindow.
+    //
+    // This method will fail if the connect was previously called on the
+    // GonkNativeWindow and no corresponding disconnect call was made.
+    virtual status_t connect(int api,
+            uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform);
+
+    // disconnect attempts to disconnect a client API from the GonkNativeWindow.
+    // This method will fail if the the GonkNativeWindow is not currently
+    // connected to the specified client API.
+    virtual status_t disconnect(int api);
+
+    void setNewFrameCallback(GonkNativeWindowNewFrameCallback* aCallback);
+
+    // setDefaultBufferSize is used to set the size of buffers returned by
+    // requestBuffers when a with and height of zero is requested.
+    // A call to setDefaultBufferSize() may trigger requestBuffers() to
+    // be called from the client.
+    status_t setDefaultBufferSize(uint32_t width, uint32_t height);
+
+    // abandon frees all the buffers and puts the GonkNativeWindow into the
+    // 'abandoned' state.  Once put in this state the GonkNativeWindow can never
+    // leave it.  When in the 'abandoned' state, all methods of the
+    // ISurfaceTexture interface will fail with the NO_INIT error.
+    //
+    // Note that while calling this method causes all the buffers to be freed
+    // from the perspective of the the GonkNativeWindow, if there are additional
+    // references on the buffers (e.g. if a buffer is referenced by a client)
+    // then those buffer will remain allocated.
     void abandon();
 
     SurfaceDescriptor *getSurfaceDescriptorFromBuffer(ANativeWindowBuffer* buffer);
 
 protected:
-    virtual int cancelBuffer(ANativeWindowBuffer* buffer);
-    virtual int dequeueBuffer(ANativeWindowBuffer** buffer);
-    virtual int lockBuffer(ANativeWindowBuffer* buffer);
-    virtual int perform(int operation, va_list args);
-    virtual int query(int what, int* value) const;
-    virtual int queueBuffer(ANativeWindowBuffer* buffer);
-    virtual int setSwapInterval(int interval);
-
-    virtual int setBufferCount(int bufferCount);
-    virtual int setBuffersDimensions(int w, int h);
-    virtual int setBuffersFormat(int format);
-    virtual int setBuffersTimestamp(int64_t timestamp);
-    virtual int setUsage(uint32_t reqUsage);
 
     // freeAllBuffersLocked frees the resources (both GraphicBuffer and
     // EGLImage) for all slots by removing them from the slots and appending
     // then to the freeList.  This must be called with mMutex locked.
     void freeAllBuffersLocked(nsTArray<SurfaceDescriptor>& freeList);
 
     // releaseBufferFreeListUnlocked releases the resources in the freeList;
     // this must be called with mMutex unlocked.
@@ -112,33 +156,24 @@ protected:
     // But do not destroy the gralloc buffer. It is still in the video stream
     // awaiting rendering.
     // this must be called with mMutex locked.
     void clearRenderingStateBuffersLocked();
 
 private:
     void init();
 
-    int dispatchSetBufferCount(va_list args);
-    int dispatchSetBuffersGeometry(va_list args);
-    int dispatchSetBuffersDimensions(va_list args);
-    int dispatchSetBuffersFormat(va_list args);
-    int dispatchSetBuffersTimestamp(va_list args);
-    int dispatchSetUsage(va_list args);
-
     int getSlotFromBufferLocked(android_native_buffer_t* buffer) const;
 
-private:
     enum { INVALID_BUFFER_SLOT = -1 };
 
     struct BufferSlot {
 
         BufferSlot()
-            : mGraphicBuffer(0),
-              mBufferState(BufferSlot::FREE),
+            : mBufferState(BufferSlot::FREE),
               mTimestamp(0),
               mFrameNumber(0){
         }
 
         // mGraphicBuffer points to the buffer allocated for this slot or is NULL
         // if no buffer has been allocated.
         sp<GraphicBuffer> mGraphicBuffer;
 
@@ -179,16 +214,21 @@ private:
             // client to dequeue. When the compositor has finished its
             // job, the buffer will be returned to FREE state.
             RENDERING = 3,
         };
 
         // mBufferState is the current state of this buffer slot.
         BufferState mBufferState;
 
+        // mRequestBufferCalled is used for validating that the client did
+        // call requestBuffer() when told to do so. Technically this is not
+        // needed but useful for debugging and catching client bugs.
+        bool mRequestBufferCalled;
+
         // mTimestamp is the current timestamp for this buffer slot. This gets
         // to set by queueBuffer each time this slot is queued.
         int64_t mTimestamp;
 
         // mFrameNumber is the number of the queued frame for this slot.
         uint64_t mFrameNumber;
     };
 
@@ -221,26 +261,34 @@ private:
     // mDefaultHeight holds the default height of allocated buffers. It is used
     // in requestBuffers() if a width and height of zero is specified.
     uint32_t mDefaultHeight;
 
     // mPixelFormat holds the pixel format of allocated buffers. It is used
     // in requestBuffers() if a format of zero is specified.
     uint32_t mPixelFormat;
 
-    // usage flag
-    uint32_t mUsage;
-
     // mBufferCount is the number of buffer slots that the client and server
-    // must maintain. It defaults to MIN_ASYNC_BUFFER_SLOTS and can be changed
+    // must maintain. It defaults to MIN_BUFFER_SLOTS + 1 and can be changed
     // by calling setBufferCount or setBufferCountServer
     int mBufferCount;
 
+    // mConnectedApi indicates the API that is currently connected to this
+    // GonkNativeWindow.  It defaults to NO_CONNECTED_API (= 0), and gets updated
+    // by the connect and disconnect methods.
+    int mConnectedApi;
+
+    // mQueue is a FIFO of queued buffers used in synchronous mode
+    // GonkNativeWindow always works in synchronous mode
+    typedef Vector<int> Fifo;
+    Fifo mQueue;
+
     // mMutex is the mutex used to prevent concurrent access to the member
-    // variables. It must be locked whenever the member variables are accessed.
+    // variables of GonkNativeWindow objects. It must be locked whenever the
+    // member variables are accessed.
     mutable Mutex mMutex;
 
     // mFrameCounter is the free running counter, incremented for every buffer queued
     uint64_t mFrameCounter;
 
     // mGeneration is the current generation of buffer slots
     uint32_t mGeneration;
 
new file mode 100644
--- /dev/null
+++ b/dom/camera/GonkNativeWindowClient.cpp
@@ -0,0 +1,446 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2012 Mozilla Foundation
+ *
+ * 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.
+ */
+
+#include "base/basictypes.h"
+
+#include "CameraCommon.h"
+#include "GonkNativeWindow.h"
+#include "GonkNativeWindowClient.h"
+#include "nsDebug.h"
+
+/**
+ * DOM_CAMERA_LOGI() is enabled in debug builds, and turned on by setting
+ * NSPR_LOG_MODULES=Camera:N environment variable, where N >= 3.
+ *
+ * CNW_LOGE() is always enabled.
+ */
+#define CNW_LOGD(...)   DOM_CAMERA_LOGI(__VA_ARGS__)
+#define CNW_LOGE(...)   {(void)printf_stderr(__VA_ARGS__);}
+
+using namespace android;
+using namespace mozilla::layers;
+
+GonkNativeWindowClient::GonkNativeWindowClient(const sp<GonkNativeWindow>& window)
+  : mNativeWindow(window) {
+    GonkNativeWindowClient::init();
+}
+
+GonkNativeWindowClient::~GonkNativeWindowClient() {
+    if (mConnectedToCpu) {
+        GonkNativeWindowClient::disconnect(NATIVE_WINDOW_API_CPU);
+    }
+}
+
+void GonkNativeWindowClient::init() {
+    // Initialize the ANativeWindow function pointers.
+    ANativeWindow::setSwapInterval  = hook_setSwapInterval;
+    ANativeWindow::dequeueBuffer    = hook_dequeueBuffer;
+    ANativeWindow::cancelBuffer     = hook_cancelBuffer;
+    ANativeWindow::lockBuffer       = hook_lockBuffer;
+    ANativeWindow::queueBuffer      = hook_queueBuffer;
+    ANativeWindow::query            = hook_query;
+    ANativeWindow::perform          = hook_perform;
+
+    mReqWidth = 0;
+    mReqHeight = 0;
+    mReqFormat = 0;
+    mReqUsage = 0;
+    mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
+    mDefaultWidth = 0;
+    mDefaultHeight = 0;
+    mTransformHint = 0;
+    mConnectedToCpu = false;
+}
+
+
+int GonkNativeWindowClient::hook_setSwapInterval(ANativeWindow* window, int interval) {
+    GonkNativeWindowClient* c = getSelf(window);
+    return c->setSwapInterval(interval);
+}
+
+int GonkNativeWindowClient::hook_dequeueBuffer(ANativeWindow* window,
+        ANativeWindowBuffer** buffer) {
+    GonkNativeWindowClient* c = getSelf(window);
+    return c->dequeueBuffer(buffer);
+}
+
+int GonkNativeWindowClient::hook_cancelBuffer(ANativeWindow* window,
+        ANativeWindowBuffer* buffer) {
+    GonkNativeWindowClient* c = getSelf(window);
+    return c->cancelBuffer(buffer);
+}
+
+int GonkNativeWindowClient::hook_lockBuffer(ANativeWindow* window,
+        ANativeWindowBuffer* buffer) {
+    GonkNativeWindowClient* c = getSelf(window);
+    return c->lockBuffer(buffer);
+}
+
+int GonkNativeWindowClient::hook_queueBuffer(ANativeWindow* window,
+        ANativeWindowBuffer* buffer) {
+    GonkNativeWindowClient* c = getSelf(window);
+    return c->queueBuffer(buffer);
+}
+
+int GonkNativeWindowClient::hook_query(const ANativeWindow* window,
+                                int what, int* value) {
+    const GonkNativeWindowClient* c = getSelf(window);
+    return c->query(what, value);
+}
+
+int GonkNativeWindowClient::hook_perform(ANativeWindow* window, int operation, ...) {
+    va_list args;
+    va_start(args, operation);
+    GonkNativeWindowClient* c = getSelf(window);
+    return c->perform(operation, args);
+}
+
+int GonkNativeWindowClient::setSwapInterval(int interval) {
+    return NO_ERROR;
+}
+
+int GonkNativeWindowClient::dequeueBuffer(android_native_buffer_t** buffer) {
+    CNW_LOGD("GonkNativeWindowClient::dequeueBuffer");
+    Mutex::Autolock lock(mMutex);
+    int buf = -1;
+    status_t result = mNativeWindow->dequeueBuffer(&buf, mReqWidth, mReqHeight,
+            mReqFormat, mReqUsage);
+    if (result < 0) {
+        CNW_LOGD("dequeueBuffer: ISurfaceTexture::dequeueBuffer(%d, %d, %d, %d)"
+             "failed: %d", mReqWidth, mReqHeight, mReqFormat, mReqUsage,
+             result);
+        return result;
+    }
+    sp<GraphicBuffer>& gbuf(mSlots[buf]);
+    if (result & ISurfaceTexture::RELEASE_ALL_BUFFERS) {
+        freeAllBuffers();
+    }
+
+    if ((result & ISurfaceTexture::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {
+        result = mNativeWindow->requestBuffer(buf, &gbuf);
+        if (result != NO_ERROR) {
+            CNW_LOGE("dequeueBuffer: ISurfaceTexture::requestBuffer failed: %d",
+                    result);
+            return result;
+        }
+    }
+    *buffer = gbuf.get();
+    return OK;
+}
+
+int GonkNativeWindowClient::cancelBuffer(ANativeWindowBuffer* buffer) {
+    CNW_LOGD("GonkNativeWindowClient::cancelBuffer");
+    Mutex::Autolock lock(mMutex);
+    int i = getSlotFromBufferLocked(buffer);
+    if (i < 0) {
+        return i;
+    }
+    mNativeWindow->cancelBuffer(i);
+    return OK;
+}
+
+int GonkNativeWindowClient::getSlotFromBufferLocked(
+        android_native_buffer_t* buffer) const {
+    bool dumpedState = false;
+    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+        // XXX: Dump the slots whenever we hit a NULL entry while searching for
+        // a buffer.
+        if (mSlots[i] == NULL) {
+            if (!dumpedState) {
+                CNW_LOGD("getSlotFromBufferLocked: encountered NULL buffer in slot %d "
+                        "looking for buffer %p", i, buffer->handle);
+                for (int j = 0; j < NUM_BUFFER_SLOTS; j++) {
+                    if (mSlots[j] == NULL) {
+                        CNW_LOGD("getSlotFromBufferLocked:   %02d: NULL", j);
+                    } else {
+                        CNW_LOGD("getSlotFromBufferLocked:   %02d: %p", j, mSlots[j]->handle);
+                    }
+                }
+                dumpedState = true;
+            }
+        }
+
+        if (mSlots[i] != NULL && mSlots[i]->handle == buffer->handle) {
+            return i;
+        }
+    }
+    CNW_LOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle);
+    return BAD_VALUE;
+}
+
+
+int GonkNativeWindowClient::lockBuffer(android_native_buffer_t* buffer) {
+    CNW_LOGD("GonkNativeWindowClient::lockBuffer");
+    Mutex::Autolock lock(mMutex);
+    return OK;
+}
+
+int GonkNativeWindowClient::queueBuffer(android_native_buffer_t* buffer) {
+    CNW_LOGD("GonkNativeWindowClient::queueBuffer");
+    Mutex::Autolock lock(mMutex);
+    int64_t timestamp;
+    if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) {
+        timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
+        CNW_LOGD("GonkNativeWindowClient::queueBuffer making up timestamp: %.2f ms",
+             timestamp / 1000000.f);
+    } else {
+        timestamp = mTimestamp;
+    }
+    int i = getSlotFromBufferLocked(buffer);
+    if (i < 0) {
+        return i;
+    }
+    status_t err = mNativeWindow->queueBuffer(i, timestamp,
+            &mDefaultWidth, &mDefaultHeight, &mTransformHint);
+    if (err != OK)  {
+        CNW_LOGE("queueBuffer: error queuing buffer to GonkNativeWindow, %d", err);
+    }
+    return err;
+}
+
+int GonkNativeWindowClient::query(int what, int* value) const {
+    CNW_LOGD("query");
+    { // scope for the lock
+        Mutex::Autolock lock(mMutex);
+        switch (what) {
+            case NATIVE_WINDOW_FORMAT:
+                if (mReqFormat) {
+                    *value = mReqFormat;
+                    return NO_ERROR;
+                }
+                break;
+            case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
+                *value = 0;
+                return NO_ERROR;
+            case NATIVE_WINDOW_CONCRETE_TYPE:
+                *value = NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT;
+                return NO_ERROR;
+            case NATIVE_WINDOW_DEFAULT_WIDTH:
+                *value = mDefaultWidth;
+                return NO_ERROR;
+            case NATIVE_WINDOW_DEFAULT_HEIGHT:
+                *value = mDefaultHeight;
+                return NO_ERROR;
+            case NATIVE_WINDOW_TRANSFORM_HINT:
+                *value = mTransformHint;
+                return NO_ERROR;
+        }
+    }
+    return mNativeWindow->query(what, value);
+}
+
+int GonkNativeWindowClient::perform(int operation, va_list args)
+{
+    int res = NO_ERROR;
+    switch (operation) {
+    case NATIVE_WINDOW_CONNECT:
+        // deprecated. must return NO_ERROR.
+        break;
+    case NATIVE_WINDOW_DISCONNECT:
+        // deprecated. must return NO_ERROR.
+        break;
+    case NATIVE_WINDOW_SET_SCALING_MODE:
+        return NO_ERROR;
+    case NATIVE_WINDOW_SET_USAGE:
+        res = dispatchSetUsage(args);
+        break;
+    case NATIVE_WINDOW_SET_CROP:
+        //not implemented
+        break;
+    case NATIVE_WINDOW_SET_BUFFER_COUNT:
+        res = dispatchSetBufferCount(args);
+        break;
+    case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
+        res = dispatchSetBuffersGeometry(args);
+        break;
+    case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
+        //not implemented
+        break;
+    case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
+        res = dispatchSetBuffersTimestamp(args);
+        break;
+    case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
+        res = dispatchSetBuffersDimensions(args);
+        break;
+    case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
+        res = dispatchSetBuffersFormat(args);
+        break;
+    case NATIVE_WINDOW_LOCK:
+        res = INVALID_OPERATION;// not supported
+        break;
+    case NATIVE_WINDOW_UNLOCK_AND_POST:
+        res = INVALID_OPERATION;// not supported
+        break;
+    case NATIVE_WINDOW_API_CONNECT:
+        res = dispatchConnect(args);
+        break;
+    case NATIVE_WINDOW_API_DISCONNECT:
+        res = dispatchDisconnect(args);
+        break;
+    case NATIVE_WINDOW_SET_BUFFERS_SIZE:
+        //not implemented
+        break;
+    default:
+        res = NAME_NOT_FOUND;
+        break;
+    }
+    return res;
+}
+
+int GonkNativeWindowClient::dispatchConnect(va_list args) {
+    int api = va_arg(args, int);
+    return connect(api);
+}
+
+int GonkNativeWindowClient::dispatchDisconnect(va_list args) {
+    int api = va_arg(args, int);
+    return disconnect(api);
+}
+
+int GonkNativeWindowClient::dispatchSetUsage(va_list args) {
+    int usage = va_arg(args, int);
+    return setUsage(usage);
+}
+
+int GonkNativeWindowClient::dispatchSetBufferCount(va_list args) {
+    size_t bufferCount = va_arg(args, size_t);
+    return setBufferCount(bufferCount);
+}
+
+int GonkNativeWindowClient::dispatchSetBuffersGeometry(va_list args) {
+    int w = va_arg(args, int);
+    int h = va_arg(args, int);
+    int f = va_arg(args, int);
+    int err = setBuffersDimensions(w, h);
+    if (err != 0) {
+        return err;
+    }
+    return setBuffersFormat(f);
+}
+
+int GonkNativeWindowClient::dispatchSetBuffersDimensions(va_list args) {
+    int w = va_arg(args, int);
+    int h = va_arg(args, int);
+    return setBuffersDimensions(w, h);
+}
+
+int GonkNativeWindowClient::dispatchSetBuffersFormat(va_list args) {
+    int f = va_arg(args, int);
+    return setBuffersFormat(f);
+}
+
+int GonkNativeWindowClient::dispatchSetBuffersTimestamp(va_list args) {
+    int64_t timestamp = va_arg(args, int64_t);
+    return setBuffersTimestamp(timestamp);
+}
+
+int GonkNativeWindowClient::connect(int api) {
+    CNW_LOGD("GonkNativeWindowClient::connect");
+    Mutex::Autolock lock(mMutex);
+    int err = mNativeWindow->connect(api,
+            &mDefaultWidth, &mDefaultHeight, &mTransformHint);
+    if (!err && api == NATIVE_WINDOW_API_CPU) {
+        mConnectedToCpu = true;
+    }
+    return err;
+}
+
+int GonkNativeWindowClient::disconnect(int api) {
+    CNW_LOGD("GonkNativeWindowClient::disconnect");
+    Mutex::Autolock lock(mMutex);
+    freeAllBuffers();
+    int err = mNativeWindow->disconnect(api);
+    if (!err) {
+        mReqFormat = 0;
+        mReqWidth = 0;
+        mReqHeight = 0;
+        mReqUsage = 0;
+        if (api == NATIVE_WINDOW_API_CPU) {
+            mConnectedToCpu = false;
+        }
+    }
+    return err;
+}
+
+int GonkNativeWindowClient::setUsage(uint32_t reqUsage)
+{
+    CNW_LOGD("GonkNativeWindowClient::setUsage");
+    Mutex::Autolock lock(mMutex);
+    mReqUsage = reqUsage;
+    return OK;
+}
+
+int GonkNativeWindowClient::setBufferCount(int bufferCount)
+{
+    CNW_LOGD("GonkNativeWindowClient::setBufferCount");
+    Mutex::Autolock lock(mMutex);
+
+    status_t err = mNativeWindow->setBufferCount(bufferCount);
+    if (err == NO_ERROR) {
+        freeAllBuffers();
+    }
+
+    return err;
+}
+
+int GonkNativeWindowClient::setBuffersDimensions(int w, int h)
+{
+    CNW_LOGD("GonkNativeWindowClient::setBuffersDimensions");
+    Mutex::Autolock lock(mMutex);
+
+    if (w<0 || h<0)
+        return BAD_VALUE;
+
+    if ((w && !h) || (!w && h))
+        return BAD_VALUE;
+
+    mReqWidth = w;
+    mReqHeight = h;
+
+    status_t err = OK;
+
+    return err;
+}
+
+int GonkNativeWindowClient::setBuffersFormat(int format)
+{
+    CNW_LOGD("GonkNativeWindowClient::setBuffersFormat");
+    Mutex::Autolock lock(mMutex);
+
+    if (format<0)
+        return BAD_VALUE;
+
+    mReqFormat = format;
+
+    return NO_ERROR;
+}
+
+
+int GonkNativeWindowClient::setBuffersTimestamp(int64_t timestamp)
+{
+    CNW_LOGD("GonkNativeWindowClient::setBuffersTimestamp");
+    Mutex::Autolock lock(mMutex);
+    mTimestamp = timestamp;
+    return NO_ERROR;
+}
+
+void GonkNativeWindowClient::freeAllBuffers() {
+    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+        mSlots[i] = 0;
+    }
+}
+
new file mode 100644
--- /dev/null
+++ b/dom/camera/GonkNativeWindowClient.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2012 Mozilla Foundation
+ *
+ * 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.
+ */
+
+#ifndef DOM_CAMERA_GONKNATIVEWINDOWCLIENT_H
+#define DOM_CAMERA_GONKNATIVEWINDOWCLIENT_H
+
+#include <ui/egl/android_natives.h>
+
+#include "GonkNativeWindow.h"
+
+namespace android {
+
+class GonkNativeWindowClient : public EGLNativeBase<ANativeWindow, GonkNativeWindowClient, RefBase>
+{
+public:
+    GonkNativeWindowClient(const sp<GonkNativeWindow>& window);
+    ~GonkNativeWindowClient(); // this class cannot be overloaded
+
+private:
+    void init();
+
+    // ANativeWindow hooks
+    static int hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+    static int hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer);
+    static int hook_lockBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+    static int hook_perform(ANativeWindow* window, int operation, ...);
+    static int hook_query(const ANativeWindow* window, int what, int* value);
+    static int hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer);
+    static int hook_setSwapInterval(ANativeWindow* window, int interval);
+
+    int dispatchConnect(va_list args);
+    int dispatchDisconnect(va_list args);
+    int dispatchSetBufferCount(va_list args);
+    int dispatchSetBuffersGeometry(va_list args);
+    int dispatchSetBuffersDimensions(va_list args);
+    int dispatchSetBuffersFormat(va_list args);
+    int dispatchSetBuffersTimestamp(va_list args);
+    int dispatchSetUsage(va_list args);
+
+protected:
+    virtual int cancelBuffer(ANativeWindowBuffer* buffer);
+    virtual int dequeueBuffer(ANativeWindowBuffer** buffer);
+    virtual int lockBuffer(ANativeWindowBuffer* buffer);
+    virtual int perform(int operation, va_list args);
+    virtual int query(int what, int* value) const;
+    virtual int queueBuffer(ANativeWindowBuffer* buffer);
+    virtual int setSwapInterval(int interval);
+
+    virtual int connect(int api);
+    virtual int disconnect(int api);
+    virtual int setBufferCount(int bufferCount);
+    virtual int setBuffersDimensions(int w, int h);
+    virtual int setBuffersFormat(int format);
+    virtual int setBuffersTimestamp(int64_t timestamp);
+    virtual int setUsage(uint32_t reqUsage);
+
+    int getNumberOfArgsForOperation(int operation);
+
+    enum { MIN_UNDEQUEUED_BUFFERS = GonkNativeWindow::MIN_UNDEQUEUED_BUFFERS };
+    enum { NUM_BUFFER_SLOTS = GonkNativeWindow::NUM_BUFFER_SLOTS };
+    enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };
+    enum { NATIVE_WINDOW_SET_BUFFERS_SIZE = 0x10000000 };
+
+private:
+    void freeAllBuffers();
+    int getSlotFromBufferLocked(android_native_buffer_t* buffer) const;
+
+    sp<GonkNativeWindow> mNativeWindow;
+
+    // mSlots stores the buffers that have been allocated for each buffer slot.
+    // It is initialized to null pointers, and gets filled in with the result of
+    // ISurfaceTexture::requestBuffer when the client dequeues a buffer from a
+    // slot that has not yet been used. The buffer allocated to a slot will also
+    // be replaced if the requested buffer usage or geometry differs from that
+    // of the buffer allocated to a slot.
+    sp<GraphicBuffer> mSlots[NUM_BUFFER_SLOTS];
+
+    // mReqWidth is the buffer width that will be requested at the next dequeue
+    // operation. It is initialized to 1.
+    uint32_t mReqWidth;
+
+    // mReqHeight is the buffer height that will be requested at the next deuque
+    // operation. It is initialized to 1.
+    uint32_t mReqHeight;
+
+    // mReqFormat is the buffer pixel format that will be requested at the next
+    // deuque operation. It is initialized to PIXEL_FORMAT_RGBA_8888.
+    uint32_t mReqFormat;
+
+    // mReqUsage is the set of buffer usage flags that will be requested
+    // at the next deuque operation. It is initialized to 0.
+    uint32_t mReqUsage;
+
+    // mTimestamp is the timestamp that will be used for the next buffer queue
+    // operation. It defaults to NATIVE_WINDOW_TIMESTAMP_AUTO, which means that
+    // a timestamp is auto-generated when queueBuffer is called.
+    int64_t mTimestamp;
+
+    // mDefaultWidth is default width of the window, regardless of the
+    // native_window_set_buffers_dimensions call
+    uint32_t mDefaultWidth;
+
+    // mDefaultHeight is default width of the window, regardless of the
+    // native_window_set_buffers_dimensions call
+    uint32_t mDefaultHeight;
+
+    // mTransformHint is the transform probably applied to buffers of this
+    // window. this is only a hint, actual transform may differ.
+    uint32_t mTransformHint;
+
+    // mMutex is the mutex used to prevent concurrent access to the member
+    // variables of GonkNativeWindow objects. It must be locked whenever the
+    // member variables are accessed.
+    mutable Mutex mMutex;
+
+    bool                        mConnectedToCpu;
+};
+
+
+}; // namespace android
+
+#endif // DOM_CAMERA_GONKNATIVEWINDOWCLIENT_H