static already_AddRefed<TextureClient>
TexClientFromReadback(SharedSurface* src, ISurfaceAllocator* allocator,
                      TextureFlags baseFlags, LayersBackend layersBackend)
{
  auto backendType = gfx::BackendType::CAIRO;
  TexClientFactory factory(allocator, src->mHasAlpha, src->mSize, backendType,
                           baseFlags, layersBackend);

  RefPtr<TextureClient> texClient;

  {
    gl::ScopedReadbackFB autoReadback(src);

    // We have a source FB, now we need a format.
    GLenum destFormat = LOCAL_GL_BGRA;
    GLenum destType = LOCAL_GL_UNSIGNED_BYTE;
    GLenum readFormat;
    GLenum readType;

    // We actually don't care if they match, since we can handle
    // any read{Format,Type} we get.
    auto gl = src->mGL;
    GetActualReadFormats(gl, destFormat, destType, &readFormat, &readType);

    MOZ_ASSERT(readFormat == LOCAL_GL_RGBA ||
               readFormat == LOCAL_GL_BGRA);
    MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_BYTE);

    // With a format and type, we can create texClient.
    if (readFormat == LOCAL_GL_BGRA &&
        readType == LOCAL_GL_UNSIGNED_BYTE)
    {
      // 0xAARRGGBB
      // In Lendian: [BB, GG, RR, AA]
      texClient = factory.CreateB8G8R8AX8();

    } else if (readFormat == LOCAL_GL_RGBA &&
               readType == LOCAL_GL_UNSIGNED_BYTE)
    {
      // [RR, GG, BB, AA]
      texClient = factory.CreateR8G8B8AX8();
    } else {
      MOZ_CRASH("GFX: Bad `read{Format,Type}`.");
    }

    MOZ_ASSERT(texClient);
    if (!texClient)
        return nullptr;

    // With a texClient, we can lock for writing.
    TextureClientAutoLock autoLock(texClient, OpenMode::OPEN_WRITE);
    DebugOnly<bool> succeeded = autoLock.Succeeded();
    MOZ_ASSERT(succeeded, "texture should have locked");

    MappedTextureData mapped;
    texClient->BorrowMappedData(mapped);

    // ReadPixels from the current FB into mapped.data.
    auto width = src->mSize.width;
    auto height = src->mSize.height;

    {
      ScopedPackAlignment autoAlign(gl, 4);

      MOZ_ASSERT(mapped.stride/4 == mapped.size.width);
      gl->raw_fReadPixels(0, 0, width, height, readFormat, readType, mapped.data);
    }

    // RB_SWAPPED doesn't work with D3D11. (bug 1051010)
    // RB_SWAPPED doesn't work with Basic. (bug ???????)
    // RB_SWAPPED doesn't work with D3D9. (bug ???????)
    bool layersNeedsManualSwap = layersBackend == LayersBackend::LAYERS_BASIC ||
                                 layersBackend == LayersBackend::LAYERS_D3D9 ||
                                 layersBackend == LayersBackend::LAYERS_D3D11;
    if (texClient->HasFlags(TextureFlags::RB_SWAPPED) &&
        layersNeedsManualSwap)
    {
      size_t pixels = width * height;
      uint8_t* itr = mapped.data;
      for (size_t i = 0; i < pixels; i++) {
        SwapRB_R8G8B8A8(itr);
        itr += 4;
      }

      texClient->RemoveFlags(TextureFlags::RB_SWAPPED);
    }
  }

  return texClient.forget();
}
bool
ReadbackSharedSurface(SharedSurface* src, gfx::DrawTarget* dst)
{
    AutoLockBits lock(dst);

    uint8_t* dstBytes;
    gfx::IntSize dstSize;
    int32_t dstStride;
    gfx::SurfaceFormat dstFormat;
    if (!lock.Lock(&dstBytes, &dstSize, &dstStride, &dstFormat))
        return false;

    const bool isDstRGBA = (dstFormat == gfx::SurfaceFormat::R8G8B8A8 ||
                            dstFormat == gfx::SurfaceFormat::R8G8B8X8);
    MOZ_ASSERT_IF(!isDstRGBA, dstFormat == gfx::SurfaceFormat::B8G8R8A8 ||
                              dstFormat == gfx::SurfaceFormat::B8G8R8X8);

    size_t width = src->mSize.width;
    size_t height = src->mSize.height;
    MOZ_ASSERT(width == (size_t)dstSize.width);
    MOZ_ASSERT(height == (size_t)dstSize.height);

    GLenum readGLFormat;
    GLenum readType;

    {
        ScopedReadbackFB autoReadback(src);


        // We have a source FB, now we need a format.
        GLenum dstGLFormat = isDstRGBA ? LOCAL_GL_BGRA : LOCAL_GL_RGBA;
        GLenum dstType = LOCAL_GL_UNSIGNED_BYTE;

        // We actually don't care if they match, since we can handle
        // any read{Format,Type} we get.
        GLContext* gl = src->mGL;
        GetActualReadFormats(gl, dstGLFormat, dstType, &readGLFormat,
                             &readType);

        MOZ_ASSERT(readGLFormat == LOCAL_GL_RGBA ||
                   readGLFormat == LOCAL_GL_BGRA);
        MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_BYTE);

        // ReadPixels from the current FB into lockedBits.
        {
            size_t alignment = 8;
            if (dstStride % 4 == 0)
                alignment = 4;
            ScopedPackAlignment autoAlign(gl, alignment);

            gl->raw_fReadPixels(0, 0, width, height, readGLFormat, readType,
                                dstBytes);
        }
    }

    const bool isReadRGBA = readGLFormat == LOCAL_GL_RGBA;

    if (isReadRGBA != isDstRGBA) {
        for (size_t j = 0; j < height; ++j) {
            uint8_t* rowItr = dstBytes + j*dstStride;
            uint8_t* rowEnd = rowItr + 4*width;
            while (rowItr != rowEnd) {
                Swap(rowItr[0], rowItr[2]);
                rowItr += 4;
            }
        }
    }

    return true;
}