static TemporaryRef<DataSourceSurface> YInvertImageSurface(DataSourceSurface* aSurf)
{
  RefPtr<DataSourceSurface> temp =
    Factory::CreateDataSourceSurfaceWithStride(aSurf->GetSize(),
                                               aSurf->GetFormat(),
                                               aSurf->Stride());
  RefPtr<DrawTarget> dt =
    Factory::CreateDrawTargetForData(BackendType::CAIRO,
                                     temp->GetData(),
                                     temp->GetSize(),
                                     temp->Stride(),
                                     temp->GetFormat());
  nsRefPtr<gfxContext> ctx = new gfxContext(dt);
  ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
  ctx->Scale(1.0, -1.0);
  ctx->Translate(-gfxPoint(0.0, aSurf->GetSize().height));

  nsRefPtr<gfxImageSurface> thebesSurf =
    new gfxImageSurface(aSurf->GetData(),
                        ThebesIntSize(aSurf->GetSize()),
                        aSurf->Stride(),
                        SurfaceFormatToImageFormat(aSurf->GetFormat()));
  ctx->SetSource(thebesSurf);
  ctx->Paint();
  return temp.forget();
}
Exemplo n.º 2
0
X11TextureData* X11TextureData::Create(gfx::IntSize aSize,
                                       gfx::SurfaceFormat aFormat,
                                       TextureFlags aFlags,
                                       LayersIPCChannel* aAllocator) {
  MOZ_ASSERT(aSize.width >= 0 && aSize.height >= 0);
  if (aSize.width <= 0 || aSize.height <= 0 ||
      aSize.width > XLIB_IMAGE_SIDE_SIZE_LIMIT ||
      aSize.height > XLIB_IMAGE_SIDE_SIZE_LIMIT) {
    gfxDebug() << "Asking for X11 surface of invalid size " << aSize.width
               << "x" << aSize.height;
    return nullptr;
  }
  gfxImageFormat imageFormat = SurfaceFormatToImageFormat(aFormat);
  RefPtr<gfxASurface> surface =
      gfxPlatform::GetPlatform()->CreateOffscreenSurface(aSize, imageFormat);
  if (!surface || surface->GetType() != gfxSurfaceType::Xlib) {
    NS_ERROR("creating Xlib surface failed!");
    return nullptr;
  }

  gfxXlibSurface* xlibSurface = static_cast<gfxXlibSurface*>(surface.get());

  bool crossProcess = !aAllocator->IsSameProcess();
  X11TextureData* texture = new X11TextureData(
      aSize, aFormat, !!(aFlags & TextureFlags::DEALLOCATE_CLIENT),
      crossProcess, xlibSurface);
  if (crossProcess) {
    FinishX(DefaultXDisplay());
  }

  return texture;
}
Exemplo n.º 3
0
void
SharedSurface_EGLImage::Fence()
{
    MutexAutoLock lock(mMutex);
    mGL->MakeCurrent();

    if (!mPipeActive) {
        MOZ_ASSERT(!mSync);
        MOZ_ASSERT(!mPipeComplete);

        if (!mPipeFailed) {
            if (!CreateTexturePipe(mEGL, mGL, mFormats, Size(),
                                   &mProdTexForPipe, &mImage))
            {
                mPipeFailed = true;
            }
        }

        if (!mPixels) {
            SurfaceFormat format =
                  HasAlpha() ? SurfaceFormat::B8G8R8A8
                             : SurfaceFormat::B8G8R8X8;
            mPixels = Factory::CreateDataSourceSurface(Size(), format);
        }

        nsRefPtr<gfxImageSurface> wrappedData =
            new gfxImageSurface(mPixels->GetData(),
                                ThebesIntSize(mPixels->GetSize()),
                                mPixels->Stride(),
                                SurfaceFormatToImageFormat(mPixels->GetFormat()));
        ReadScreenIntoImageSurface(mGL, wrappedData);
        mPixels->MarkDirty();
        return;
    }
    MOZ_ASSERT(mPipeActive);
    MOZ_ASSERT(mCurConsGL);

    if (mEGL->IsExtensionSupported(GLLibraryEGL::KHR_fence_sync) &&
        mGL->IsExtensionSupported(GLContext::OES_EGL_sync))
    {
        if (mSync) {
            MOZ_ALWAYS_TRUE( mEGL->fDestroySync(Display(), mSync) );
            mSync = 0;
        }

        mSync = mEGL->fCreateSync(Display(),
                                  LOCAL_EGL_SYNC_FENCE,
                                  nullptr);
        if (mSync) {
            mGL->fFlush();
            return;
        }
    }

    MOZ_ASSERT(!mSync);
    mGL->fFinish();
}
Exemplo n.º 4
0
bool
TextureImageTextureSourceOGL::Update(gfx::DataSourceSurface* aSurface,
                                     nsIntRegion* aDestRegion,
                                     gfx::IntPoint* aSrcOffset)
{
    MOZ_ASSERT(mGL);
    if (!mGL) {
        NS_WARNING("trying to update TextureImageTextureSourceOGL without a GLContext");
        return false;
    }
    MOZ_ASSERT(aSurface);

    IntSize size = aSurface->GetSize();
    if (!mTexImage ||
            (mTexImage->GetSize() != size && !aSrcOffset) ||
            mTexImage->GetContentType() != gfx::ContentForFormat(aSurface->GetFormat())) {
        if (mFlags & TEXTURE_DISALLOW_BIGIMAGE) {
            mTexImage = CreateBasicTextureImage(mGL, size,
                                                gfx::ContentForFormat(aSurface->GetFormat()),
                                                WrapMode(mGL, mFlags & TEXTURE_ALLOW_REPEAT),
                                                FlagsToGLFlags(mFlags),
                                                SurfaceFormatToImageFormat(aSurface->GetFormat()));
        } else {
            // XXX - clarify which size we want to use. IncrementalContentHost will
            // require the size of the destination surface to be different from
            // the size of aSurface.
            // See bug 893300 (tracks the implementation of ContentHost for new textures).
            mTexImage = CreateTextureImage(mGL,
                                           size,
                                           gfx::ContentForFormat(aSurface->GetFormat()),
                                           WrapMode(mGL, mFlags & TEXTURE_ALLOW_REPEAT),
                                           FlagsToGLFlags(mFlags),
                                           SurfaceFormatToImageFormat(aSurface->GetFormat()));
        }
        ClearCachedFilter();
    }

    mTexImage->UpdateFromDataSource(aSurface, aDestRegion, aSrcOffset);

    if (mTexImage->InUpdate()) {
        mTexImage->EndUpdate();
    }
    return true;
}
Exemplo n.º 5
0
bool
X11DataTextureSourceBasic::Update(gfx::DataSourceSurface* aSurface,
                                  nsIntRegion* aDestRegion,
                                  gfx::IntPoint* aSrcOffset)
{
  // Reallocate our internal X11 surface if we don't have a DrawTarget yet,
  // or if we changed surface size or format since last update.
  if (!mBufferDrawTarget ||
      (aSurface->GetSize() != mBufferDrawTarget->GetSize()) ||
      (aSurface->GetFormat() != mBufferDrawTarget->GetFormat())) {

    nsRefPtr<gfxASurface> surf;
    gfxImageFormat imageFormat = SurfaceFormatToImageFormat(aSurface->GetFormat());
    Display *display = DefaultXDisplay();
    Screen *screen = DefaultScreenOfDisplay(display);
    XRenderPictFormat *xrenderFormat =
      gfxXlibSurface::FindRenderFormat(display, imageFormat);

    if (xrenderFormat) {
      surf = gfxXlibSurface::Create(screen, xrenderFormat,
                                    ThebesIntSize(aSurface->GetSize()));
    }

    if (!surf) {
      NS_WARNING("Couldn't create native surface, fallback to image surface");
      surf = new gfxImageSurface(ThebesIntSize(aSurface->GetSize()), imageFormat);
    }

    mBufferDrawTarget = gfxPlatform::GetPlatform()->
      CreateDrawTargetForSurface(surf, aSurface->GetSize());
  }

  // Image contents have changed, upload to our DrawTarget
  // If aDestRegion is null, means we're updating the whole surface
  // Note : Incremental update with a source offset is only used on Mac.
  NS_ASSERTION(!aSrcOffset, "SrcOffset should not be used with linux OMTC basic");

  if (aDestRegion) {
    nsIntRegionRectIterator iter(*aDestRegion);
    while (const nsIntRect* iterRect = iter.Next()) {
      IntRect srcRect(iterRect->x, iterRect->y, iterRect->width, iterRect->height);
      IntPoint dstPoint(iterRect->x, iterRect->y);

      // We're uploading regions to our buffer, so let's just copy contents over
      mBufferDrawTarget->CopySurface(aSurface, srcRect, dstPoint);
    }
  } else {
    // We're uploading the whole buffer, so let's just copy the full surface
    IntSize size = aSurface->GetSize();
    mBufferDrawTarget->CopySurface(aSurface, IntRect(0, 0, size.width, size.height),
                                   IntPoint(0, 0));
  }

  return true;
}
Exemplo n.º 6
0
DIBTextureData*
MemoryDIBTextureData::Create(gfx::IntSize aSize, gfx::SurfaceFormat aFormat)
{
  RefPtr<gfxWindowsSurface> surface
    = new gfxWindowsSurface(aSize, SurfaceFormatToImageFormat(aFormat));
  if (!surface || surface->CairoStatus()) {
    NS_WARNING("Could not create DIB surface");
    return nullptr;
  }

  return new MemoryDIBTextureData(aSize, aFormat, surface);
}
Exemplo n.º 7
0
void
GLScreenBuffer::Readback(SharedSurface_GL* src, DataSourceSurface* dest)
{
  MOZ_ASSERT(src && dest);
  DataSourceSurface::MappedSurface ms;
  dest->Map(DataSourceSurface::MapType::READ, &ms);
  nsRefPtr<gfxImageSurface> wrappedDest =
    new gfxImageSurface(ms.mData,
                        ThebesIntSize(dest->GetSize()),
                        ms.mStride,
                        SurfaceFormatToImageFormat(dest->GetFormat()));
  DeprecatedReadback(src, wrappedDest);
  dest->Unmap();
}
Exemplo n.º 8
0
// Run the test for a texture client and a surface
void TestTextureClientSurface(TextureClient* texture, gfxImageSurface* surface) {

  // client allocation
  ASSERT_TRUE(texture->CanExposeDrawTarget());

  ASSERT_TRUE(texture->Lock(OpenMode::OPEN_READ_WRITE));
  // client painting
  RefPtr<DrawTarget> dt = texture->BorrowDrawTarget();
  RefPtr<SourceSurface> source =
    gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, surface);
  dt->CopySurface(source, IntRect(IntPoint(), source->GetSize()), IntPoint());

  RefPtr<SourceSurface> snapshot = dt->Snapshot();

  AssertSurfacesEqual(snapshot, source);

  dt = nullptr; // drop reference before calling Unlock()
  texture->Unlock();

  // client serialization
  SurfaceDescriptor descriptor;
  ASSERT_TRUE(texture->ToSurfaceDescriptor(descriptor));

  ASSERT_NE(descriptor.type(), SurfaceDescriptor::Tnull_t);

  // host deserialization
  RefPtr<TextureHost> host = CreateBackendIndependentTextureHost(descriptor, nullptr,
                                                                 texture->GetFlags());

  ASSERT_TRUE(host.get() != nullptr);
  ASSERT_EQ(host->GetFlags(), texture->GetFlags());

  // host read

  // XXX - this can fail because lock tries to upload the texture but it needs a
  // Compositor to do that. We could add a DummyComposior for testing but I am
  // not sure it'll be worth it. Maybe always test against a BasicCompositor,
  // but the latter needs a widget...
  if (host->Lock()) {
    RefPtr<mozilla::gfx::DataSourceSurface> hostDataSurface = host->GetAsSurface();

    RefPtr<gfxImageSurface> hostSurface =
      new gfxImageSurface(hostDataSurface->GetData(),
                          hostDataSurface->GetSize(),
                          hostDataSurface->Stride(),
                          SurfaceFormatToImageFormat(hostDataSurface->GetFormat()));
    AssertSurfacesEqual(surface, hostSurface.get());
    host->Unlock();
  }
}
Exemplo n.º 9
0
void
SharedSurface_Basic::Fence()
{
    mGL->MakeCurrent();

    ScopedBindFramebuffer autoFB(mGL, mFB);

    DataSourceSurface::MappedSurface map;
    mData->Map(DataSourceSurface::MapType::WRITE, &map);
    nsRefPtr<gfxImageSurface> wrappedData =
      new gfxImageSurface(map.mData,
                          ThebesIntSize(mData->GetSize()),
                          map.mStride,
                          SurfaceFormatToImageFormat(mData->GetFormat()));
    ReadPixelsIntoImageSurface(mGL, wrappedData);
    mData->Unmap();
}
Exemplo n.º 10
0
// Run the test for a texture client and a surface
void TestTextureClientSurface(TextureClient* texture, gfxImageSurface* surface) {

    // client allocation
    ASSERT_TRUE(texture->CanExposeDrawTarget());
    texture->AllocateForSurface(ToIntSize(surface->GetSize()));
    ASSERT_TRUE(texture->IsAllocated());

    ASSERT_TRUE(texture->Lock(OPEN_READ_WRITE));
    // client painting
    RefPtr<DrawTarget> dt = texture->GetAsDrawTarget();
    RefPtr<SourceSurface> source =
        gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, surface);
    dt->CopySurface(source, IntRect(IntPoint(), source->GetSize()), IntPoint());

    RefPtr<SourceSurface> snapshot = dt->Snapshot();

    AssertSurfacesEqual(snapshot, source);

    dt = nullptr; // drop reference before calling Unlock()
    texture->Unlock();

    // client serialization
    SurfaceDescriptor descriptor;
    ASSERT_TRUE(texture->ToSurfaceDescriptor(descriptor));

    ASSERT_NE(descriptor.type(), SurfaceDescriptor::Tnull_t);

    // host deserialization
    RefPtr<TextureHost> host = CreateBackendIndependentTextureHost(descriptor, nullptr,
                               texture->GetFlags());

    ASSERT_TRUE(host.get() != nullptr);
    ASSERT_EQ(host->GetFlags(), texture->GetFlags());

    // host read
    ASSERT_TRUE(host->Lock());
    RefPtr<mozilla::gfx::DataSourceSurface> hostDataSurface = host->GetAsSurface();
    host->Unlock();

    nsRefPtr<gfxImageSurface> hostSurface =
        new gfxImageSurface(hostDataSurface->GetData(),
                            ThebesIntSize(hostDataSurface->GetSize()),
                            hostDataSurface->Stride(),
                            SurfaceFormatToImageFormat(hostDataSurface->GetFormat()));
    AssertSurfacesEqual(surface, hostSurface.get());
}
Exemplo n.º 11
0
bool
DIBTextureClient::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlags aFlags)
{
  MOZ_ASSERT(!IsAllocated());
  mSize = aSize;

  mSurface = new gfxWindowsSurface(gfxIntSize(aSize.width, aSize.height),
                                   SurfaceFormatToImageFormat(mFormat));
  if (!mSurface || mSurface->CairoStatus())
  {
    NS_WARNING("Could not create surface");
    mSurface = nullptr;
    return false;
  }

  return true;
}
Exemplo n.º 12
0
void WriteSnapshotToDumpFile_internal(T* aObj, DataSourceSurface* aSurf)
{
  nsRefPtr<gfxImageSurface> deprecatedSurf =
    new gfxImageSurface(aSurf->GetData(),
                        ThebesIntSize(aSurf->GetSize()),
                        aSurf->Stride(),
                        SurfaceFormatToImageFormat(aSurf->GetFormat()));
  nsCString string(aObj->Name());
  string.Append('-');
  string.AppendInt((uint64_t)aObj);
  if (gfxUtils::sDumpPaintFile) {
    fprintf_stderr(gfxUtils::sDumpPaintFile, "array[\"%s\"]=\"", string.BeginReading());
  }
  deprecatedSurf->DumpAsDataURL(gfxUtils::sDumpPaintFile);
  if (gfxUtils::sDumpPaintFile) {
    fprintf_stderr(gfxUtils::sDumpPaintFile, "\";");
  }
}
Exemplo n.º 13
0
bool
TextureImageTextureSourceOGL::Update(gfx::DataSourceSurface* aSurface,
                                     nsIntRegion* aDestRegion,
                                     gfx::IntPoint* aSrcOffset)
{
  GLContext *gl = mCompositor->gl();
  MOZ_ASSERT(gl);
  if (!gl) {
    NS_WARNING("trying to update TextureImageTextureSourceOGL without a GLContext");
    return false;
  }
  if (!aSurface) {
    gfxCriticalError() << "Invalid surface for OGL update";
    return false;
  }
  MOZ_ASSERT(aSurface);

  IntSize size = aSurface->GetSize();
  if (!mTexImage ||
      (mTexImage->GetSize() != size && !aSrcOffset) ||
      mTexImage->GetContentType() != gfx::ContentForFormat(aSurface->GetFormat())) {
    if (mFlags & TextureFlags::DISALLOW_BIGIMAGE) {
      GLint maxTextureSize;
      gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &maxTextureSize);
      if (size.width > maxTextureSize || size.height > maxTextureSize) {
        NS_WARNING("Texture exceeds maximum texture size, refusing upload");
        return false;
      }
      // Explicitly use CreateBasicTextureImage instead of CreateTextureImage,
      // because CreateTextureImage might still choose to create a tiled
      // texture image.
      mTexImage = CreateBasicTextureImage(gl, size,
                                          gfx::ContentForFormat(aSurface->GetFormat()),
                                          LOCAL_GL_CLAMP_TO_EDGE,
                                          FlagsToGLFlags(mFlags),
                                          SurfaceFormatToImageFormat(aSurface->GetFormat()));
    } else {
      // XXX - clarify which size we want to use. IncrementalContentHost will
      // require the size of the destination surface to be different from
      // the size of aSurface.
      // See bug 893300 (tracks the implementation of ContentHost for new textures).
      mTexImage = CreateTextureImage(gl,
                                     size,
                                     gfx::ContentForFormat(aSurface->GetFormat()),
                                     LOCAL_GL_CLAMP_TO_EDGE,
                                     FlagsToGLFlags(mFlags),
                                     SurfaceFormatToImageFormat(aSurface->GetFormat()));
    }
    ClearCachedFilter();

    if (aDestRegion &&
        !aSrcOffset &&
        !aDestRegion->IsEqual(nsIntRect(0, 0, size.width, size.height))) {
      // UpdateFromDataSource will ignore our specified aDestRegion since the texture
      // hasn't been allocated with glTexImage2D yet. Call Resize() to force the
      // allocation (full size, but no upload), and then we'll only upload the pixels
      // we care about below.
      mTexImage->Resize(size);
    }
  }

  mTexImage->UpdateFromDataSource(aSurface, aDestRegion, aSrcOffset);

  if (mTexImage->InUpdate()) {
    mTexImage->EndUpdate();
  }
  return true;
}
Exemplo n.º 14
0
void
CanvasLayerD3D9::UpdateSurface()
{
  if (!IsDirty() && mTexture)
    return;
  Painted();

  if (!mTexture) {
    CreateTexture();

    if (!mTexture) {
      NS_WARNING("CanvasLayerD3D9::Updated called but no texture present and creation failed!");
      return;
    }
  }

  if (mGLContext) {
    SharedSurface* surf = mGLContext->RequestFrame();
    if (!surf)
        return;

    SharedSurface_Basic* shareSurf = SharedSurface_Basic::Cast(surf);

    // WebGL reads entire surface.
    LockTextureRectD3D9 textureLock(mTexture);
    if (!textureLock.HasLock()) {
      NS_WARNING("Failed to lock CanvasLayer texture.");
      return;
    }

    D3DLOCKED_RECT rect = textureLock.GetLockRect();
    
    DataSourceSurface* frameData = shareSurf->GetData();
    // Scope for gfxContext, so it's destroyed early.
    {
      RefPtr<DrawTarget> mapDt = Factory::CreateDrawTargetForData(BACKEND_CAIRO,
                                                                  (uint8_t*)rect.pBits,
                                                                  shareSurf->Size(),
                                                                  rect.Pitch,
                                                                  FORMAT_B8G8R8A8);

      nsRefPtr<gfxImageSurface> thebesFrameData =
          new gfxImageSurface(frameData->GetData(),
                              ThebesIntSize(frameData->GetSize()),
                              frameData->Stride(),
                              SurfaceFormatToImageFormat(frameData->GetFormat()));

      nsRefPtr<gfxContext> ctx = new gfxContext(mapDt);
      ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
      ctx->SetSource(thebesFrameData);
      ctx->Paint();

      mapDt->Flush();
    }
  } else {
    RECT r;
    r.left = mBounds.x;
    r.top = mBounds.y;
    r.right = mBounds.XMost();
    r.bottom = mBounds.YMost();

    LockTextureRectD3D9 textureLock(mTexture);
    if (!textureLock.HasLock()) {
      NS_WARNING("Failed to lock CanvasLayer texture.");
      return;
    }

    D3DLOCKED_RECT lockedRect = textureLock.GetLockRect();

    nsRefPtr<gfxImageSurface> sourceSurface;

    if (mSurface->GetType() == gfxSurfaceTypeWin32) {
      sourceSurface = mSurface->GetAsImageSurface();
    } else if (mSurface->GetType() == gfxSurfaceTypeImage) {
      sourceSurface = static_cast<gfxImageSurface*>(mSurface.get());
      if (sourceSurface->Format() != gfxImageFormatARGB32 &&
          sourceSurface->Format() != gfxImageFormatRGB24)
      {
        return;
      }
    } else {
      sourceSurface = new gfxImageSurface(gfxIntSize(mBounds.width, mBounds.height),
                                          gfxImageFormatARGB32);
      nsRefPtr<gfxContext> ctx = new gfxContext(sourceSurface);
      ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
      ctx->SetSource(mSurface);
      ctx->Paint();
    }

    uint8_t *startBits = sourceSurface->Data();
    uint32_t sourceStride = sourceSurface->Stride();

    if (sourceSurface->Format() != gfxImageFormatARGB32) {
      mHasAlpha = false;
    } else {
      mHasAlpha = true;
    }

    for (int y = 0; y < mBounds.height; y++) {
      memcpy((uint8_t*)lockedRect.pBits + lockedRect.Pitch * y,
             startBits + sourceStride * y,
             mBounds.width * 4);
    }

  }
}
Exemplo n.º 15
0
void
ReadPixelsIntoImageSurface(GLContext* gl, gfxImageSurface* dest) {
    gl->MakeCurrent();
    MOZ_ASSERT(dest->GetSize() != gfxIntSize(0, 0));

    /* gfxImageFormat::ARGB32:
     * RGBA+UByte: be[RGBA], le[ABGR]
     * RGBA+UInt: le[RGBA]
     * BGRA+UInt: le[BGRA]
     * BGRA+UIntRev: le[ARGB]
     *
     * gfxImageFormat::RGB16_565:
     * RGB+UShort: le[rrrrrggg,gggbbbbb]
     */
    bool hasAlpha = dest->Format() == gfxImageFormat::ARGB32;

    int destPixelSize;
    GLenum destFormat;
    GLenum destType;

    switch (dest->Format()) {
        case gfxImageFormat::RGB24: // XRGB
        case gfxImageFormat::ARGB32:
            destPixelSize = 4;
            // Needs host (little) endian ARGB.
            destFormat = LOCAL_GL_BGRA;
            destType = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV;
            break;

        case gfxImageFormat::RGB16_565:
            destPixelSize = 2;
            destFormat = LOCAL_GL_RGB;
            destType = LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV;
            break;

        default:
            MOZ_CRASH("Bad format.");
    }
    MOZ_ASSERT(dest->Stride() == dest->Width() * destPixelSize);

    GLenum readFormat = destFormat;
    GLenum readType = destType;
    bool needsTempSurf = !GetActualReadFormats(gl,
                                               destFormat, destType,
                                               readFormat, readType);

    nsAutoPtr<gfxImageSurface> tempSurf;
    gfxImageSurface* readSurf = nullptr;
    int readPixelSize = 0;
    if (needsTempSurf) {
        if (gl->DebugMode()) {
            NS_WARNING("Needing intermediary surface for ReadPixels. This will be slow!");
        }
        SurfaceFormat readFormatGFX;

        switch (readFormat) {
            case LOCAL_GL_RGBA:
            case LOCAL_GL_BGRA: {
                readFormatGFX = hasAlpha ? SurfaceFormat::B8G8R8A8
                                         : SurfaceFormat::B8G8R8X8;
                break;
            }
            case LOCAL_GL_RGB: {
                MOZ_ASSERT(readPixelSize == 2);
                MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV);
                readFormatGFX = SurfaceFormat::R5G6B5;
                break;
            }
            default: {
                MOZ_CRASH("Bad read format.");
            }
        }

        switch (readType) {
            case LOCAL_GL_UNSIGNED_BYTE: {
                MOZ_ASSERT(readFormat == LOCAL_GL_RGBA);
                readPixelSize = 4;
                break;
            }
            case LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV: {
                MOZ_ASSERT(readFormat == LOCAL_GL_BGRA);
                readPixelSize = 4;
                break;
            }
            case LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV: {
                MOZ_ASSERT(readFormat == LOCAL_GL_RGB);
                readPixelSize = 2;
                break;
            }
            default: {
                MOZ_CRASH("Bad read type.");
            }
        }

        tempSurf = new gfxImageSurface(dest->GetSize(),
                                       SurfaceFormatToImageFormat(readFormatGFX),
                                       false);
        readSurf = tempSurf;
    } else {
        readPixelSize = destPixelSize;
        readSurf = dest;
    }
    MOZ_ASSERT(readPixelSize);

    GLint currentPackAlignment = 0;
    gl->fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, &currentPackAlignment);

    if (currentPackAlignment != readPixelSize)
        gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, readPixelSize);

    GLsizei width = dest->Width();
    GLsizei height = dest->Height();

    readSurf->Flush();
    gl->fReadPixels(0, 0,
                    width, height,
                    readFormat, readType,
                    readSurf->Data());
    readSurf->MarkDirty();

    if (currentPackAlignment != readPixelSize)
        gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, currentPackAlignment);

    if (readSurf != dest) {
        MOZ_ASSERT(readFormat == LOCAL_GL_RGBA);
        MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_BYTE);
        // So we just copied in RGBA in big endian, or le: 0xAABBGGRR.
        // We want 0xAARRGGBB, so swap R and B:
        dest->Flush();
        RefPtr<DataSourceSurface> readDSurf =
            Factory::CreateWrappingDataSourceSurface(readSurf->Data(),
                                                     readSurf->Stride(),
                                                     ToIntSize(readSurf->GetSize()),
                                                     ImageFormatToSurfaceFormat(readSurf->Format()));
        SwapRAndBComponents(readDSurf);
        dest->MarkDirty();

        gfxContext ctx(dest);
        ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
        ctx.SetSource(readSurf);
        ctx.Paint();
    }

    // Check if GL is giving back 1.0 alpha for
    // RGBA reads to RGBA images from no-alpha buffers.
#ifdef XP_MACOSX
    if (gl->WorkAroundDriverBugs() &&
        gl->Vendor() == gl::GLVendor::NVIDIA &&
        dest->Format() == gfxImageFormat::ARGB32 &&
        width && height)
    {
        GLint alphaBits = 0;
        gl->fGetIntegerv(LOCAL_GL_ALPHA_BITS, &alphaBits);
        if (!alphaBits) {
            const uint32_t alphaMask = gfxPackedPixelNoPreMultiply(0xff,0,0,0);

            dest->Flush();
            uint32_t* itr = (uint32_t*)dest->Data();
            uint32_t testPixel = *itr;
            if ((testPixel & alphaMask) != alphaMask) {
                // We need to set the alpha channel to 1.0 manually.
                uint32_t* itrEnd = itr + width*height;  // Stride is guaranteed to be width*4.

                for (; itr != itrEnd; itr++) {
                    *itr |= alphaMask;
                }
            }
            dest->MarkDirty();
        }
    }
#endif
}
Exemplo n.º 16
0
void
CopyableCanvasLayer::UpdateSurface(gfxASurface* aDestSurface, Layer* aMaskLayer)
{
  if (!IsDirty())
    return;
  Painted();

  if (mDrawTarget) {
    mDrawTarget->Flush();
    mSurface =
      gfxPlatform::GetPlatform()->CreateThebesSurfaceAliasForDrawTarget_hack(mDrawTarget);
  }

  if (!mGLContext && aDestSurface) {
    nsRefPtr<gfxContext> tmpCtx = new gfxContext(aDestSurface);
    tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
    CopyableCanvasLayer::PaintWithOpacity(tmpCtx, 1.0f, aMaskLayer);
    return;
  }

  if (mGLContext) {
    nsRefPtr<gfxImageSurface> readSurf;
    RefPtr<DataSourceSurface> readDSurf;
    nsRefPtr<gfxASurface> resultSurf;

    SharedSurface* sharedSurf = mGLContext->RequestFrame();
    if (!sharedSurf) {
      NS_WARNING("Null frame received.");
      return;
    }

    IntSize readSize(sharedSurf->Size());
    gfxImageFormat format = (GetContentFlags() & CONTENT_OPAQUE)
                            ? gfxImageFormat::RGB24
                            : gfxImageFormat::ARGB32;

    if (aDestSurface) {
      resultSurf = aDestSurface;
    } else {
      resultSurf = GetTempSurface(readSize, format);
    }
    MOZ_ASSERT(resultSurf);
    if (resultSurf->CairoStatus() != 0) {
      MOZ_ASSERT(false, "Bad resultSurf->CairoStatus().");
      return;
    }

    MOZ_ASSERT(sharedSurf->APIType() == APITypeT::OpenGL);
    SharedSurface_GL* surfGL = SharedSurface_GL::Cast(sharedSurf);

    if (surfGL->Type() == SharedSurfaceType::Basic) {
      // sharedSurf_Basic->mData must outlive readSurf and readDSurf. Alas,
      // readSurf and readDSurf may not leave the scope they were declared in.
      SharedSurface_Basic* sharedSurf_Basic = SharedSurface_Basic::Cast(surfGL);
      readDSurf = sharedSurf_Basic->GetData();
      readSurf = new gfxImageSurface(readDSurf->GetData(),
                                     ThebesIntSize(readDSurf->GetSize()),
                                     readDSurf->Stride(),
                                     SurfaceFormatToImageFormat(readDSurf->GetFormat()));
    } else {
      if (ToIntSize(resultSurf->GetSize()) != readSize ||
          !(readSurf = resultSurf->GetAsImageSurface()) ||
          readSurf->Format() != format)
      {
        readSurf = GetTempSurface(readSize, format);
      }

      // Readback handles Flush/MarkDirty.
      mGLContext->Screen()->Readback(surfGL, readSurf);
    }
    MOZ_ASSERT(readSurf);

    bool needsPremult = surfGL->HasAlpha() && !mIsGLAlphaPremult;
    if (needsPremult) {
      readSurf->Flush();
      gfxUtils::PremultiplyImageSurface(readSurf);
      readSurf->MarkDirty();
    }
    
    if (readSurf != resultSurf) {
      readSurf->Flush();
      nsRefPtr<gfxContext> ctx = new gfxContext(resultSurf);
      ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
      ctx->SetSource(readSurf);
      ctx->Paint();
    }

    // If !aDestSurface then we will end up painting using mSurface, so
    // stick our surface into mSurface, so that the Paint() path is the same.
    if (!aDestSurface) {
      mSurface = resultSurf;
    }
  }
}