void
ClientCanvasLayer::RenderLayer()
{
    PROFILER_LABEL("ClientCanvasLayer", "RenderLayer",
                   js::ProfileEntry::Category::GRAPHICS);

    RenderMaskLayers(this);

    if (!mCanvasClient) {
        TextureFlags flags = TextureFlags::IMMEDIATE_UPLOAD;
        if (mOriginPos == gl::OriginPos::BottomLeft) {
            flags |= TextureFlags::ORIGIN_BOTTOM_LEFT;
        }

        if (!mGLContext) {
            // We don't support locking for buffer surfaces currently
            flags |= TextureFlags::IMMEDIATE_UPLOAD;
        }

        if (!mIsAlphaPremultiplied) {
            flags |= TextureFlags::NON_PREMULTIPLIED;
        }

        mCanvasClient = CanvasClient::CreateCanvasClient(GetCanvasClientType(),
                        ClientManager()->AsShadowForwarder(),
                        flags);
        if (!mCanvasClient) {
            return;
        }
        if (HasShadow()) {
            if (mAsyncRenderer) {
                static_cast<CanvasClientBridge*>(mCanvasClient.get())->SetLayer(this);
            } else {
                mCanvasClient->Connect();
                ClientManager()->AsShadowForwarder()->Attach(mCanvasClient, this);
            }
        }
    }

    if (mCanvasClient && mAsyncRenderer) {
        mCanvasClient->UpdateAsync(mAsyncRenderer);
    }

    if (!IsDirty()) {
        return;
    }
    Painted();

    FirePreTransactionCallback();
    if (mBufferProvider && mBufferProvider->GetTextureClient()) {
        mCanvasClient->UpdateFromTexture(mBufferProvider->GetTextureClient());
    } else {
        mCanvasClient->Update(gfx::IntSize(mBounds.width, mBounds.height), this);
    }

    FireDidTransactionCallback();

    ClientManager()->Hold(this);
    mCanvasClient->Updated();
}
示例#2
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;
    }
  }

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

  D3DLOCKED_RECT rect = textureLock.GetLockRect();
  IntSize boundsSize(mBounds.width, mBounds.height);
  RefPtr<DrawTarget> rectDt = Factory::CreateDrawTargetForData(BackendType::CAIRO,
                                                               (uint8_t*)rect.pBits,
                                                               boundsSize,
                                                               rect.Pitch,
                                                               SurfaceFormat::B8G8R8A8);

  if (mGLContext) {
    auto screen = mGLContext->Screen();
    MOZ_ASSERT(screen);

    SharedSurface* surf = screen->Front()->Surf();
    if (!surf)
      return;
    surf->WaitSync();

    if (!ReadbackSharedSurface(surf, rectDt)) {
      NS_WARNING("Failed to readback into texture.");
    }
  } else {
    RefPtr<SourceSurface> surface = mDrawTarget->Snapshot();

    Rect drawRect(0, 0, surface->GetSize().width, surface->GetSize().height);
    rectDt->DrawSurface(surface, drawRect, drawRect,
                        DrawSurfaceOptions(),  DrawOptions(1.0F, CompositionOp::OP_SOURCE));

    rectDt->Flush();
  }
}
示例#3
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;
    }
  }

  RefPtr<SourceSurface> surface;

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

    SharedSurface_Basic* shareSurf = SharedSurface_Basic::Cast(surf);
    surface = shareSurf->GetData();
  } else {
    surface = mDrawTarget->Snapshot();
  }

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

  D3DLOCKED_RECT rect = textureLock.GetLockRect();
  RefPtr<DrawTarget> rectDt = Factory::CreateDrawTargetForData(BackendType::CAIRO,
                                                               (uint8_t*)rect.pBits,
                                                               surface->GetSize(),
                                                               rect.Pitch,
                                                               SurfaceFormat::B8G8R8A8);

  Rect drawRect(0, 0, surface->GetSize().width, surface->GetSize().height);
  rectDt->DrawSurface(surface, drawRect, drawRect,
                      DrawSurfaceOptions(),  DrawOptions(1.0F, CompositionOp::OP_SOURCE));
  rectDt->Flush();
}
示例#4
0
void
BasicCanvasLayer::Paint(DrawTarget* aDT,
                        const Point& aDeviceOffset,
                        Layer* aMaskLayer)
{
  if (IsHidden())
    return;

  if (IsDirty()) {
    Painted();

    FirePreTransactionCallback();
    UpdateTarget();
    FireDidTransactionCallback();
  }

  if (!mSurface) {
    return;
  }

  const bool needsYFlip = (mOriginPos == gl::OriginPos::BottomLeft);

  Matrix oldTM;
  if (needsYFlip) {
    oldTM = aDT->GetTransform();
    aDT->SetTransform(Matrix(oldTM).
                        PreTranslate(0.0f, mBounds.height).
                        PreScale(1.0f, -1.0f));
  }

  FillRectWithMask(aDT, aDeviceOffset,
                   Rect(0, 0, mBounds.width, mBounds.height),
                   mSurface, ToFilter(mFilter),
                   DrawOptions(GetEffectiveOpacity(), GetEffectiveOperator(this)),
                   aMaskLayer);

  if (needsYFlip) {
    aDT->SetTransform(oldTM);
  }
}
void
CopyableCanvasLayer::UpdateSurface(gfxASurface* aDestSurface, Layer* aMaskLayer)
{
  if (!IsDirty())
    return;
  Painted();

  if (mDrawTarget) {
    mDrawTarget->Flush();
    if (mDrawTarget->GetType() == BACKEND_COREGRAPHICS_ACCELERATED) {
      // We have an accelerated CG context which has changed, unlike a bitmap surface
      // where we can alias the bits on initializing the mDrawTarget, we need to readback
      // and copy the accelerated surface each frame. We want to support this for quick
      // thumbnail but if we're going to be doing this every frame it likely is better
      // to use a non accelerated (bitmap) canvas.
      mSurface = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mDrawTarget);
    }
  }

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

  if (mGLContext) {
    if (aDestSurface && aDestSurface->GetType() != gfxASurface::SurfaceTypeImage) {
      MOZ_ASSERT(false, "Destination surface must be ImageSurface type.");
      return;
    }

    nsRefPtr<gfxImageSurface> readSurf;
    nsRefPtr<gfxImageSurface> resultSurf;

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

    gfxIntSize readSize(sharedSurf->Size());
    gfxImageFormat format = (GetContentFlags() & CONTENT_OPAQUE)
                            ? gfxASurface::ImageFormatRGB24
                            : gfxASurface::ImageFormatARGB32;

    if (aDestSurface) {
      resultSurf = static_cast<gfxImageSurface*>(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) {
      SharedSurface_Basic* sharedSurf_Basic = SharedSurface_Basic::Cast(surfGL);
      readSurf = sharedSurf_Basic->GetData();
    } else {
      if (resultSurf->Format() == format &&
          resultSurf->GetSize() == readSize)
      {
        readSurf = resultSurf;
      } else {
        readSurf = GetTempSurface(readSize, format);
      }

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

    bool needsPremult = surfGL->HasAlpha() && !mIsGLAlphaPremult;
    if (needsPremult) {
      gfxImageSurface* sizedReadSurf = nullptr;
      if (readSurf->Format()  == resultSurf->Format() &&
          readSurf->GetSize() == resultSurf->GetSize())
      {
        sizedReadSurf = readSurf;
      } else {
        readSurf->Flush();
        nsRefPtr<gfxContext> ctx = new gfxContext(resultSurf);
        ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
        ctx->SetSource(readSurf);
        ctx->Paint();

        sizedReadSurf = resultSurf;
      }
      MOZ_ASSERT(sizedReadSurf);

      readSurf->Flush();
      resultSurf->Flush();
      gfxUtils::PremultiplyImageSurface(readSurf, resultSurf);
      resultSurf->MarkDirty();
    } else if (resultSurf != readSurf) {
      // Didn't need premult, but we do need to blit to resultSurf
      readSurf->Flush();
      nsRefPtr<gfxContext> ctx = new gfxContext(resultSurf);
      ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
      ctx->SetSource(readSurf);
      ctx->Paint();
    }

    // stick our surface into mSurface, so that the Paint() path is the same
    if (!aDestSurface) {
      mSurface = resultSurf;
    }
  }
}
示例#6
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);
    }

  }
}
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) {
    // WebGL reads entire surface.
    LockTextureRectD3D9 textureLock(mTexture);
    if (!textureLock.HasLock()) {
      NS_WARNING("Failed to lock CanvasLayer texture.");
      return;
    }

    D3DLOCKED_RECT r = textureLock.GetLockRect();

    const bool stridesMatch = r.Pitch == mBounds.width * 4;

    uint8_t *destination;
    if (!stridesMatch) {
      destination = GetTempBlob(mBounds.width * mBounds.height * 4);
    } else {
      DiscardTempBlob();
      destination = (uint8_t*)r.pBits;
    }

    mGLContext->MakeCurrent();

    nsRefPtr<gfxImageSurface> tmpSurface =
      new gfxImageSurface(destination,
                          gfxIntSize(mBounds.width, mBounds.height),
                          mBounds.width * 4,
                          gfxASurface::ImageFormatARGB32);
    mGLContext->ReadScreenIntoImageSurface(tmpSurface);
    tmpSurface = nullptr;

    if (!stridesMatch) {
      for (int y = 0; y < mBounds.height; y++) {
        memcpy((uint8_t*)r.pBits + r.Pitch * y,
               destination + mBounds.width * 4 * y,
               mBounds.width * 4);
      }
    }
  } 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() == gfxASurface::SurfaceTypeWin32) {
      sourceSurface = mSurface->GetAsImageSurface();
    } else if (mSurface->GetType() == gfxASurface::SurfaceTypeImage) {
      sourceSurface = static_cast<gfxImageSurface*>(mSurface.get());
      if (sourceSurface->Format() != gfxASurface::ImageFormatARGB32 &&
          sourceSurface->Format() != gfxASurface::ImageFormatRGB24)
      {
        return;
      }
    } else {
      sourceSurface = new gfxImageSurface(gfxIntSize(mBounds.width, mBounds.height),
                                          gfxASurface::ImageFormatARGB32);
      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() != gfxASurface::ImageFormatARGB32) {
      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);
    }

  }
}
void
CanvasLayerD3D10::UpdateSurface()
{
  if (!IsDirty())
    return;
  Painted();

  if (mDrawTarget) {
    mDrawTarget->Flush();
  } else if (mIsD2DTexture) {
    mSurface->Flush();
    return;
  } else if (mUsingSharedTexture) {
    // need to sync on the d3d9 device
    if (mGLContext) {
      mGLContext->MakeCurrent();
      mGLContext->GuaranteeResolve();
    }
    return;
  }
  if (mGLContext) {
    // WebGL reads entire surface.
    D3D10_MAPPED_TEXTURE2D map;
    
    HRESULT hr = mTexture->Map(0, D3D10_MAP_WRITE_DISCARD, 0, &map);

    if (FAILED(hr)) {
      NS_WARNING("Failed to map CanvasLayer texture.");
      return;
    }

    const bool stridesMatch = map.RowPitch == mBounds.width * 4;

    uint8_t *destination;
    if (!stridesMatch) {
      destination = GetTempBlob(mBounds.width * mBounds.height * 4);
    } else {
      DiscardTempBlob();
      destination = (uint8_t*)map.pData;
    }

    mGLContext->MakeCurrent();

    nsRefPtr<gfxImageSurface> tmpSurface =
      new gfxImageSurface(destination,
                          gfxIntSize(mBounds.width, mBounds.height),
                          mBounds.width * 4,
                          gfxASurface::ImageFormatARGB32);
    mGLContext->ReadScreenIntoImageSurface(tmpSurface);
    tmpSurface = nullptr;

    if (!stridesMatch) {
      for (int y = 0; y < mBounds.height; y++) {
        memcpy((uint8_t*)map.pData + map.RowPitch * y,
               destination + mBounds.width * 4 * y,
               mBounds.width * 4);
      }
    }
    mTexture->Unmap(0);
  } else if (mSurface) {
    RECT r;
    r.left = 0;
    r.top = 0;
    r.right = mBounds.width;
    r.bottom = mBounds.height;

    D3D10_MAPPED_TEXTURE2D map;
    HRESULT hr = mTexture->Map(0, D3D10_MAP_WRITE_DISCARD, 0, &map);

    if (FAILED(hr)) {
      NS_WARNING("Failed to lock CanvasLayer texture.");
      return;
    }

    nsRefPtr<gfxImageSurface> dstSurface;

    dstSurface = new gfxImageSurface((unsigned char*)map.pData,
                                     gfxIntSize(mBounds.width, mBounds.height),
                                     map.RowPitch,
                                     gfxASurface::ImageFormatARGB32);
    nsRefPtr<gfxContext> ctx = new gfxContext(dstSurface);
    ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
    ctx->SetSource(mSurface);
    ctx->Paint();
    
    mTexture->Unmap(0);
  }
}
示例#9
0
void
CopyableCanvasLayer::UpdateSurface(gfxASurface* aDestSurface, Layer* aMaskLayer)
{
  if (!IsDirty())
    return;
  Painted();

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

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

  if (mGLContext) {
    if (aDestSurface && aDestSurface->GetType() != gfxASurface::SurfaceTypeImage) {
      MOZ_ASSERT(false, "Destination surface must be ImageSurface type.");
      return;
    }

    nsRefPtr<gfxImageSurface> readSurf;
    nsRefPtr<gfxImageSurface> resultSurf;

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

    gfxIntSize readSize(sharedSurf->Size());
    gfxImageFormat format = (GetContentFlags() & CONTENT_OPAQUE)
                            ? gfxASurface::ImageFormatRGB24
                            : gfxASurface::ImageFormatARGB32;

    if (aDestSurface) {
      resultSurf = static_cast<gfxImageSurface*>(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) {
      SharedSurface_Basic* sharedSurf_Basic = SharedSurface_Basic::Cast(surfGL);
      readSurf = sharedSurf_Basic->GetData();
    } else {
      if (resultSurf->Format() == format &&
          resultSurf->GetSize() == readSize)
      {
        readSurf = resultSurf;
      } else {
        readSurf = GetTempSurface(readSize, format);
      }

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

    bool needsPremult = surfGL->HasAlpha() && !mIsGLAlphaPremult;
    if (needsPremult) {
      gfxImageSurface* sizedReadSurf = nullptr;
      if (readSurf->Format()  == resultSurf->Format() &&
          readSurf->GetSize() == resultSurf->GetSize())
      {
        sizedReadSurf = readSurf;
      } else {
        readSurf->Flush();
        nsRefPtr<gfxContext> ctx = new gfxContext(resultSurf);
        ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
        ctx->SetSource(readSurf);
        ctx->Paint();

        sizedReadSurf = resultSurf;
      }
      MOZ_ASSERT(sizedReadSurf);

      readSurf->Flush();
      resultSurf->Flush();
      gfxUtils::PremultiplyImageSurface(readSurf, resultSurf);
      resultSurf->MarkDirty();
    } else if (resultSurf != readSurf) {
      // Didn't need premult, but we do need to blit to resultSurf
      readSurf->Flush();
      nsRefPtr<gfxContext> ctx = new gfxContext(resultSurf);
      ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
      ctx->SetSource(readSurf);
      ctx->Paint();
    }

    // stick our surface into mSurface, so that the Paint() path is the same
    if (!aDestSurface) {
      mSurface = resultSurf;
    }
  }
}
示例#10
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;
    nsRefPtr<gfxASurface> resultSurf;

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

    IntSize readSize(ToIntSize(sharedSurf->Size()));
    gfxImageFormat format = (GetContentFlags() & CONTENT_OPAQUE)
                            ? gfxImageFormatRGB24
                            : gfxImageFormatARGB32;

    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) {
      SharedSurface_Basic* sharedSurf_Basic = SharedSurface_Basic::Cast(surfGL);
      readSurf = sharedSurf_Basic->GetData();
    } 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;
    }
  }
}
示例#11
0
void
BasicShadowableCanvasLayer::Paint(gfxContext* aContext, Layer* aMaskLayer)
{
  if (!HasShadow()) {
    BasicCanvasLayer::Paint(aContext, aMaskLayer);
    return;
  }

  if (!IsDirty())
    return;

  if (mGLContext &&
      !mForceReadback &&
      BasicManager()->GetParentBackendType() == mozilla::layers::LAYERS_OPENGL) {
    TextureImage::TextureShareType flags;
    // if process type is default, then it is single-process (non-e10s)
    if (XRE_GetProcessType() == GeckoProcessType_Default)
      flags = TextureImage::ThreadShared;
    else
      flags = TextureImage::ProcessShared;

    SharedTextureHandle handle = GetSharedBackBufferHandle();
    if (!handle) {
      handle = mGLContext->CreateSharedHandle(flags);
      if (handle) {
        mBackBuffer = SharedTextureDescriptor(flags, handle, mBounds.Size(), false);
      }
    }
    if (handle) {
      mGLContext->MakeCurrent();
      mGLContext->UpdateSharedHandle(flags, handle);
      // call Painted() to reset our dirty 'bit'
      Painted();
      FireDidTransactionCallback();
      BasicManager()->PaintedCanvas(BasicManager()->Hold(this),
                                    mNeedsYFlip,
                                    mBackBuffer);
      // Move SharedTextureHandle ownership to ShadowLayer
      mBackBuffer = SurfaceDescriptor();
      return;
    }
  }

  bool isOpaque = (GetContentFlags() & CONTENT_OPAQUE);
  if (!IsSurfaceDescriptorValid(mBackBuffer) ||
      isOpaque != mBufferIsOpaque) {
    DestroyBackBuffer();
    mBufferIsOpaque = isOpaque;

    gfxIntSize size(mBounds.width, mBounds.height);
    gfxASurface::gfxContentType type = isOpaque ?
        gfxASurface::CONTENT_COLOR : gfxASurface::CONTENT_COLOR_ALPHA;

    if (!BasicManager()->AllocBuffer(size, type, &mBackBuffer)) {
      NS_RUNTIMEABORT("creating CanvasLayer back buffer failed!");
    }
  }

  AutoOpenSurface autoBackSurface(OPEN_READ_WRITE, mBackBuffer);

  if (aMaskLayer) {
    static_cast<BasicImplData*>(aMaskLayer->ImplData())
      ->Paint(aContext, nullptr);
  }
  UpdateSurface(autoBackSurface.Get(), nullptr);
  FireDidTransactionCallback();

  BasicManager()->PaintedCanvas(BasicManager()->Hold(this),
                                mNeedsYFlip, mBackBuffer);
}
示例#12
0
void
BasicCanvasLayer::UpdateSurface(gfxASurface* aDestSurface, Layer* aMaskLayer)
{
  if (!IsDirty())
    return;
  Painted();

  if (mDrawTarget) {
    mDrawTarget->Flush();
    // TODO Fix me before turning accelerated quartz canvas by default
    //mSurface = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mDrawTarget);
  }

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

  if (mGLContext) {
    if (aDestSurface && aDestSurface->GetType() != gfxASurface::SurfaceTypeImage) {
      NS_ASSERTION(aDestSurface->GetType() == gfxASurface::SurfaceTypeImage,
                   "Destination surface must be ImageSurface type");
      return;
    }

    // We need to read from the GLContext
    mGLContext->MakeCurrent();

#if defined (MOZ_X11) && defined (MOZ_EGL_XRENDER_COMPOSITE)
    if (!mForceReadback) {
      mGLContext->GuaranteeResolve();
      gfxASurface* offscreenSurface = mGLContext->GetOffscreenPixmapSurface();

      // XRender can only blend premuliplied alpha, so only allow xrender
      // path if we have premultiplied alpha or opaque content.
      if (offscreenSurface && (mGLBufferIsPremultiplied || (GetContentFlags() & CONTENT_OPAQUE))) {  
        mSurface = offscreenSurface;
        mNeedsYFlip = false;
        return;
      }
    }
#endif

    gfxIntSize readSize(mBounds.width, mBounds.height);
    gfxImageFormat format = (GetContentFlags() & CONTENT_OPAQUE)
                              ? gfxASurface::ImageFormatRGB24
                              : gfxASurface::ImageFormatARGB32;

    nsRefPtr<gfxImageSurface> readSurf;
    nsRefPtr<gfxImageSurface> resultSurf;

    bool usingTempSurface = false;

    if (aDestSurface) {
      resultSurf = static_cast<gfxImageSurface*>(aDestSurface);

      if (resultSurf->GetSize() != readSize ||
          resultSurf->Stride() != resultSurf->Width() * 4)
      {
        readSurf = GetTempSurface(readSize, format);
        usingTempSurface = true;
      }
    } else {
      resultSurf = GetTempSurface(readSize, format);
      usingTempSurface = true;
    }

    if (!usingTempSurface)
      DiscardTempSurface();

    if (!readSurf)
      readSurf = resultSurf;

    if (!resultSurf || resultSurf->CairoStatus() != 0)
      return;

    MOZ_ASSERT(readSurf);
    MOZ_ASSERT(readSurf->Stride() == mBounds.width * 4, "gfxImageSurface stride isn't what we expect!");

    // We need to Flush() the surface before modifying it outside of cairo.
    readSurf->Flush();
    mGLContext->ReadScreenIntoImageSurface(readSurf);
    readSurf->MarkDirty();

    // If the underlying GLContext doesn't have a framebuffer into which
    // premultiplied values were written, we have to do this ourselves here.
    // Note that this is a WebGL attribute; GL itself has no knowledge of
    // premultiplied or unpremultiplied alpha.
    if (!mGLBufferIsPremultiplied)
      gfxUtils::PremultiplyImageSurface(readSurf);

    if (readSurf != resultSurf) {
      MOZ_ASSERT(resultSurf->Width() >= readSurf->Width());
      MOZ_ASSERT(resultSurf->Height() >= readSurf->Height());

      resultSurf->Flush();
      resultSurf->CopyFrom(readSurf);
      resultSurf->MarkDirty();
    }

    // stick our surface into mSurface, so that the Paint() path is the same
    if (!aDestSurface) {
      mSurface = resultSurf;
    }
  }
}
示例#13
0
void
CanvasLayerD3D10::UpdateSurface()
{
  if (!IsDirty())
    return;
  Painted();
  if (mDrawTarget) {
    mDrawTarget->Flush();
  } else if (mIsD2DTexture) {
    return;
  }
  if (!mTexture) {
    return;
  }

  if (mGLContext) {
    SharedSurface_GL* surf = mGLContext->RequestFrame();
    if (!surf) {
      return;
    }
    switch (surf->Type()) {
      case SharedSurfaceType::EGLSurfaceANGLE: {
        SharedSurface_ANGLEShareHandle* shareSurf = SharedSurface_ANGLEShareHandle::Cast(surf);
        mSRView = shareSurf->GetSRV();
        return;
      }
      case SharedSurfaceType::Basic: {
        SharedSurface_Basic* shareSurf = SharedSurface_Basic::Cast(surf);
        // WebGL reads entire surface.
        D3D10_MAPPED_TEXTURE2D map;

        HRESULT hr = mTexture->Map(0, D3D10_MAP_WRITE_DISCARD, 0, &map);

        if (FAILED(hr)) {
          NS_WARNING("Failed to map CanvasLayer texture.");
          return;
        }

        DataSourceSurface* frameData = shareSurf->GetData();
        // Scope for DrawTarget, so it's destroyed before Unmap.
        {
          IntSize boundsSize(mBounds.width, mBounds.height);
          RefPtr<DrawTarget> mapDt = Factory::CreateDrawTargetForData(BackendType::CAIRO,
                                                                      (uint8_t*)map.pData,
                                                                      boundsSize,
                                                                      map.RowPitch,
                                                                      SurfaceFormat::B8G8R8A8);

          Rect drawRect(0, 0, frameData->GetSize().width, frameData->GetSize().height);
          mapDt->DrawSurface(frameData, drawRect, drawRect,
                             DrawSurfaceOptions(),  DrawOptions(1.0F, CompositionOp::OP_SOURCE));
          mapDt->Flush();
        }

        mTexture->Unmap(0);
        mSRView = mUploadSRView;
        break;
      }

      default:
        MOZ_CRASH("Unhandled SharedSurfaceType.");
    }
  } else if (mSurface) {
    D3D10_MAPPED_TEXTURE2D map;
    HRESULT hr = mTexture->Map(0, D3D10_MAP_WRITE_DISCARD, 0, &map);

    if (FAILED(hr)) {
      NS_WARNING("Failed to lock CanvasLayer texture.");
      return;
    }

    RefPtr<DrawTarget> destTarget =
      Factory::CreateDrawTargetForD3D10Texture(mTexture,
                                               SurfaceFormat::R8G8B8A8);
    Rect r(Point(0, 0), ToRect(mBounds).Size());
    destTarget->DrawSurface(mSurface, r, r, DrawSurfaceOptions(),
                            DrawOptions(1.0F, CompositionOp::OP_SOURCE));

    mTexture->Unmap(0);
    mSRView = mUploadSRView;
  }
}
void
CanvasLayerD3D10::UpdateSurface()
{
  if (!IsDirty())
    return;
  Painted();

  if (mDrawTarget) {
    mDrawTarget->Flush();
  } else if (mIsD2DTexture) {
    mSurface->Flush();
    return;
  }

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

    switch (surf->Type()) {
      case SharedSurfaceType::EGLSurfaceANGLE: {
        SharedSurface_ANGLEShareHandle* shareSurf = SharedSurface_ANGLEShareHandle::Cast(surf);

        mSRView = shareSurf->GetSRV();
        return;
      }
      case SharedSurfaceType::Basic: {
        SharedSurface_Basic* shareSurf = SharedSurface_Basic::Cast(surf);
        // WebGL reads entire surface.
        D3D10_MAPPED_TEXTURE2D map;

        HRESULT hr = mTexture->Map(0, D3D10_MAP_WRITE_DISCARD, 0, &map);

        if (FAILED(hr)) {
          NS_WARNING("Failed to map CanvasLayer texture.");
          return;
        }

        gfxImageSurface* frameData = shareSurf->GetData();
        // Scope for gfxContext, so it's destroyed before Unmap.
        {
          nsRefPtr<gfxImageSurface> mapSurf = 
              new gfxImageSurface((uint8_t*)map.pData,
                                  shareSurf->Size(),
                                  map.RowPitch,
                                  gfxASurface::ImageFormatARGB32);

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

          mapSurf->Flush();
        }

        mTexture->Unmap(0);
        mSRView = mUploadSRView;
        break;
      }

      default:
        MOZ_CRASH("Unhandled SharedSurfaceType.");
    }
  } else if (mSurface) {
    RECT r;
    r.left = 0;
    r.top = 0;
    r.right = mBounds.width;
    r.bottom = mBounds.height;

    D3D10_MAPPED_TEXTURE2D map;
    HRESULT hr = mTexture->Map(0, D3D10_MAP_WRITE_DISCARD, 0, &map);

    if (FAILED(hr)) {
      NS_WARNING("Failed to lock CanvasLayer texture.");
      return;
    }

    nsRefPtr<gfxImageSurface> dstSurface;

    dstSurface = new gfxImageSurface((unsigned char*)map.pData,
                                     gfxIntSize(mBounds.width, mBounds.height),
                                     map.RowPitch,
                                     gfxASurface::ImageFormatARGB32);
    nsRefPtr<gfxContext> ctx = new gfxContext(dstSurface);
    ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
    ctx->SetSource(mSurface);
    ctx->Paint();
    
    mTexture->Unmap(0);
    mSRView = mUploadSRView;
  }
}
void
CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget)
{
  if (!IsDirty())
    return;
  Painted();

  if (mDrawTarget) {
    mDrawTarget->Flush();
    mSurface = mDrawTarget->Snapshot();
  }

  if (!mGLContext && aDestTarget) {
    NS_ASSERTION(mSurface, "Must have surface to draw!");
    if (mSurface) {
      aDestTarget->CopySurface(mSurface,
                               IntRect(0, 0, mBounds.width, mBounds.height),
                               IntPoint(0, 0));
      mSurface = nullptr;
    }
    return;
  }

  if (mGLContext) {
    SharedSurface_GL* sharedSurf = nullptr;
    if (mStream) {
      sharedSurf = SharedSurface_GL::Cast(mStream->SwapConsumer());
    } else {
      sharedSurf = mGLContext->RequestFrame();
    }

    if (!sharedSurf) {
      NS_WARNING("Null frame received.");
      return;
    }

    IntSize readSize(sharedSurf->Size());
    SurfaceFormat format = (GetContentFlags() & CONTENT_OPAQUE)
                            ? SurfaceFormat::B8G8R8X8
                            : SurfaceFormat::B8G8R8A8;
    bool needsPremult = sharedSurf->HasAlpha() && !mIsGLAlphaPremult;

    // Try to read back directly into aDestTarget's output buffer
    if (aDestTarget) {
      uint8_t* destData;
      IntSize destSize;
      int32_t destStride;
      SurfaceFormat destFormat;
      if (aDestTarget->LockBits(&destData, &destSize, &destStride, &destFormat)) {
        if (destSize == readSize && destFormat == format) {
          RefPtr<DataSourceSurface> data =
            Factory::CreateWrappingDataSourceSurface(destData, destStride, destSize, destFormat);
          mGLContext->Screen()->Readback(sharedSurf, data);
          if (needsPremult) {
            PremultiplySurface(data);
          }
          aDestTarget->ReleaseBits(destData);
          return;
        }
        aDestTarget->ReleaseBits(destData);
      }
    }

    RefPtr<SourceSurface> resultSurf;
    if (sharedSurf->Type() == SharedSurfaceType::Basic && !needsPremult) {
      SharedSurface_Basic* sharedSurf_Basic = SharedSurface_Basic::Cast(sharedSurf);
      resultSurf = sharedSurf_Basic->GetData();
    } else {
      RefPtr<DataSourceSurface> data = GetTempSurface(readSize, format);
      // Readback handles Flush/MarkDirty.
      mGLContext->Screen()->Readback(sharedSurf, data);
      if (needsPremult) {
        PremultiplySurface(data);
      }
      resultSurf = data;
    }
    MOZ_ASSERT(resultSurf);

    if (aDestTarget) {
      aDestTarget->CopySurface(resultSurf,
                               IntRect(0, 0, readSize.width, readSize.height),
                               IntPoint(0, 0));
    } else {
      // If !aDestSurface then we will end up painting using mSurface, so
      // stick our surface into mSurface, so that the Paint() path is the same.
      mSurface = resultSurf;
    }
  }
}
void
CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget)
{
  if (!IsDirty())
    return;
  Painted();

  if (mDrawTarget) {
    mDrawTarget->Flush();
    mSurface = mDrawTarget->Snapshot();
  }

  if (!mGLContext && aDestTarget) {
    NS_ASSERTION(mSurface, "Must have surface to draw!");
    if (mSurface) {
      aDestTarget->CopySurface(mSurface,
                               IntRect(0, 0, mBounds.width, mBounds.height),
                               IntPoint(0, 0));
    }
    return;
  }

  if (mGLContext) {
    RefPtr<DataSourceSurface> readSurf;
    RefPtr<SourceSurface> resultSurf;

    SharedSurface_GL* sharedSurf = nullptr;
    if (mStream) {
      sharedSurf = SharedSurface_GL::Cast(mStream->SwapConsumer());
    } else {
      sharedSurf = mGLContext->RequestFrame();
    }

    if (!sharedSurf) {
      NS_WARNING("Null frame received.");
      return;
    }

    IntSize readSize(sharedSurf->Size());
    SurfaceFormat format = (GetContentFlags() & CONTENT_OPAQUE)
                            ? SurfaceFormat::B8G8R8X8
                            : SurfaceFormat::B8G8R8A8;

    if (aDestTarget) {
      resultSurf = aDestTarget->Snapshot();
      if (!resultSurf) {
        resultSurf = GetTempSurface(readSize, format);
      }
    } else {
      resultSurf = GetTempSurface(readSize, format);
    }
    MOZ_ASSERT(resultSurf);
    MOZ_ASSERT(sharedSurf->APIType() == APITypeT::OpenGL);
    SharedSurface_GL* surfGL = SharedSurface_GL::Cast(sharedSurf);

    if (surfGL->Type() == SharedSurfaceType::Basic) {
      // sharedSurf_Basic->mData must outlive readSurf. Alas, readSurf may not
      // leave the scope it was declared in.
      SharedSurface_Basic* sharedSurf_Basic = SharedSurface_Basic::Cast(surfGL);
      readSurf = sharedSurf_Basic->GetData();
    } else {
      if (resultSurf->GetSize() != readSize ||
          !(readSurf = resultSurf->GetDataSurface()) ||
          readSurf->GetFormat() != format)
      {
        readSurf = GetTempSurface(readSize, format);
      }

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

    bool needsPremult = surfGL->HasAlpha() && !mIsGLAlphaPremult;
    if (needsPremult) {
      PremultiplySurface(readSurf);
    }

    if (readSurf != resultSurf) {
      RefPtr<DataSourceSurface> resultDataSurface =
        resultSurf->GetDataSurface();
      RefPtr<DrawTarget> dt =
        Factory::CreateDrawTargetForData(BackendType::CAIRO,
                                         resultDataSurface->GetData(),
                                         resultDataSurface->GetSize(),
                                         resultDataSurface->Stride(),
                                         resultDataSurface->GetFormat());
      IntSize readSize = readSurf->GetSize();
      dt->CopySurface(readSurf,
                      IntRect(0, 0, readSize.width, readSize.height),
                      IntPoint(0, 0));
    }

    // 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 (!aDestTarget) {
      mSurface = resultSurf;
    }
  }
}