void ThebesLayerD3D9::DrawRegion(const nsIntRegion &aRegion) { HRESULT hr; nsIntRect visibleRect = mVisibleRegion.GetBounds(); nsRefPtr<gfxContext> context; #ifdef CAIRO_HAS_D2D_SURFACE if (mD2DSurface) { context = new gfxContext(mD2DSurface); nsIntRegionRectIterator iter(aRegion); context->Translate(gfxPoint(-visibleRect.x, -visibleRect.y)); context->NewPath(); const nsIntRect *iterRect; while ((iterRect = iter.Next())) { context->Rectangle(gfxRect(iterRect->x, iterRect->y, iterRect->width, iterRect->height)); } context->Clip(); if (mD2DSurface->GetContentType() != gfxASurface::CONTENT_COLOR) { context->SetOperator(gfxContext::OPERATOR_CLEAR); context->Paint(); context->SetOperator(gfxContext::OPERATOR_OVER); } LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo(); cbInfo.Callback(this, context, aRegion, nsIntRegion(), cbInfo.CallbackData); mD2DSurface->Flush(); // XXX - This call is quite expensive, we may want to consider doing our // drawing in a seperate 'validation' iteration. And then flushing once for // all the D2D surfaces we might have drawn, before doing our D3D9 rendering // loop. cairo_d2d_finish_device(gfxWindowsPlatform::GetPlatform()->GetD2DDevice()); return; } #endif D3DFORMAT fmt = UseOpaqueSurface(this) ? D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8; nsIntRect bounds = aRegion.GetBounds(); gfxASurface::gfxImageFormat imageFormat = gfxASurface::ImageFormatARGB32; nsRefPtr<gfxASurface> destinationSurface; nsRefPtr<IDirect3DTexture9> tmpTexture; device()->CreateTexture(bounds.width, bounds.height, 1, 0, fmt, D3DPOOL_SYSTEMMEM, getter_AddRefs(tmpTexture), NULL); nsRefPtr<IDirect3DSurface9> surf; HDC dc; if (UseOpaqueSurface(this)) { hr = tmpTexture->GetSurfaceLevel(0, getter_AddRefs(surf)); if (FAILED(hr)) { // Uh-oh, bail. NS_WARNING("Failed to get texture surface level."); return; } hr = surf->GetDC(&dc); if (FAILED(hr)) { NS_WARNING("Failed to get device context for texture surface."); return; } destinationSurface = new gfxWindowsSurface(dc); } else { // XXX - We may consider retaining a SYSTEMMEM texture texture the size // of our DEFAULT texture and then use UpdateTexture and add dirty rects // to update in a single call. destinationSurface = gfxPlatform::GetPlatform()-> CreateOffscreenSurface(gfxIntSize(bounds.width, bounds.height), imageFormat); } context = new gfxContext(destinationSurface); context->Translate(gfxPoint(-bounds.x, -bounds.y)); LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo(); cbInfo.Callback(this, context, aRegion, nsIntRegion(), cbInfo.CallbackData); if (UseOpaqueSurface(this)) { surf->ReleaseDC(dc); } else { D3DLOCKED_RECT r; tmpTexture->LockRect(0, &r, NULL, 0); nsRefPtr<gfxImageSurface> imgSurface = new gfxImageSurface((unsigned char *)r.pBits, gfxIntSize(bounds.width, bounds.height), r.Pitch, imageFormat); context = new gfxContext(imgSurface); context->SetSource(destinationSurface); context->SetOperator(gfxContext::OPERATOR_SOURCE); context->Paint(); imgSurface = NULL; tmpTexture->UnlockRect(0); } nsRefPtr<IDirect3DSurface9> srcSurface; nsRefPtr<IDirect3DSurface9> dstSurface; mTexture->GetSurfaceLevel(0, getter_AddRefs(dstSurface)); tmpTexture->GetSurfaceLevel(0, getter_AddRefs(srcSurface)); nsIntRegionRectIterator iter(aRegion); const nsIntRect *iterRect; while ((iterRect = iter.Next())) { RECT rect; rect.left = iterRect->x - bounds.x; rect.top = iterRect->y - bounds.y; rect.right = rect.left + iterRect->width; rect.bottom = rect.top + iterRect->height; POINT point; point.x = iterRect->x - visibleRect.x; point.y = iterRect->y - visibleRect.y; device()->UpdateSurface(srcSurface, &rect, dstSurface, &point); } }
void ThebesLayerD3D9::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode, const nsTArray<ReadbackProcessor::Update>& aReadbackUpdates) { HRESULT hr; nsIntRect visibleRect = mVisibleRegion.GetBounds(); nsRefPtr<gfxASurface> destinationSurface; nsIntRect bounds = aRegion.GetBounds(); nsRefPtr<IDirect3DTexture9> tmpTexture; OpaqueRenderer opaqueRenderer(aRegion); OpaqueRenderer opaqueRendererOnWhite(aRegion); switch (aMode) { case SurfaceMode::SURFACE_OPAQUE: destinationSurface = opaqueRenderer.Begin(this); break; case SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA: { hr = device()->CreateTexture(bounds.width, bounds.height, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, getter_AddRefs(tmpTexture), nullptr); if (FAILED(hr)) { ReportFailure(NS_LITERAL_CSTRING("Failed to create temporary texture in system memory."), hr); return; } // XXX - We may consider retaining a SYSTEMMEM texture texture the size // of our DEFAULT texture and then use UpdateTexture and add dirty rects // to update in a single call. nsRefPtr<gfxWindowsSurface> dest = new gfxWindowsSurface( gfxIntSize(bounds.width, bounds.height), gfxImageFormat::ARGB32); // If the contents of this layer don't require component alpha in the // end of rendering, it's safe to enable Cleartype since all the Cleartype // glyphs must be over (or under) opaque pixels. dest->SetSubpixelAntialiasingEnabled(!(mContentFlags & CONTENT_COMPONENT_ALPHA)); destinationSurface = dest.forget(); break; } case SurfaceMode::SURFACE_COMPONENT_ALPHA: { nsRefPtr<gfxWindowsSurface> onBlack = opaqueRenderer.Begin(this); nsRefPtr<gfxWindowsSurface> onWhite = opaqueRendererOnWhite.Begin(this); if (onBlack && onWhite) { FillSurface(onBlack, aRegion, bounds.TopLeft(), gfxRGBA(0.0, 0.0, 0.0, 1.0)); FillSurface(onWhite, aRegion, bounds.TopLeft(), gfxRGBA(1.0, 1.0, 1.0, 1.0)); gfxASurface* surfaces[2] = { onBlack.get(), onWhite.get() }; destinationSurface = new gfxTeeSurface(surfaces, ArrayLength(surfaces)); // Using this surface as a source will likely go horribly wrong, since // only the onBlack surface will really be used, so alpha information will // be incorrect. destinationSurface->SetAllowUseAsSource(false); } break; } } if (!destinationSurface) return; nsRefPtr<gfxContext> context; if (gfxPlatform::GetPlatform()->SupportsAzureContentForType(BackendType::CAIRO)) { RefPtr<DrawTarget> dt = gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(destinationSurface, IntSize(destinationSurface->GetSize().width, destinationSurface->GetSize().height)); context = new gfxContext(dt); } else { context = new gfxContext(destinationSurface); } context->Translate(gfxPoint(-bounds.x, -bounds.y)); LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo(); cbInfo.Callback(this, context, aRegion, DrawRegionClip::CLIP_NONE, nsIntRegion(), cbInfo.CallbackData); for (uint32_t i = 0; i < aReadbackUpdates.Length(); ++i) { NS_ASSERTION(aMode == SurfaceMode::SURFACE_OPAQUE, "Transparent surfaces should not be used for readback"); const ReadbackProcessor::Update& update = aReadbackUpdates[i]; nsIntPoint offset = update.mLayer->GetBackgroundLayerOffset(); nsRefPtr<gfxContext> ctx = update.mLayer->GetSink()->BeginUpdate(update.mUpdateRect + offset, update.mSequenceCounter); if (ctx) { ctx->Translate(gfxPoint(offset.x, offset.y)); ctx->SetSource(destinationSurface, gfxPoint(bounds.x, bounds.y)); ctx->Paint(); update.mLayer->GetSink()->EndUpdate(ctx, update.mUpdateRect + offset); } } // Release the cairo d3d9 surface before we try to composite it context = nullptr; nsAutoTArray<IDirect3DTexture9*,2> srcTextures; nsAutoTArray<IDirect3DTexture9*,2> destTextures; switch (aMode) { case SurfaceMode::SURFACE_OPAQUE: // Must release reference to dest surface before ending drawing destinationSurface = nullptr; opaqueRenderer.End(); srcTextures.AppendElement(opaqueRenderer.GetTexture()); destTextures.AppendElement(mTexture); break; case SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA: { LockTextureRectD3D9 textureLock(tmpTexture); if (!textureLock.HasLock()) { NS_WARNING("Failed to lock ThebesLayer tmpTexture texture."); return; } D3DLOCKED_RECT r = textureLock.GetLockRect(); nsRefPtr<gfxImageSurface> imgSurface = new gfxImageSurface((unsigned char *)r.pBits, bounds.Size(), r.Pitch, gfxImageFormat::ARGB32); if (destinationSurface) { nsRefPtr<gfxContext> context = new gfxContext(imgSurface); context->SetSource(destinationSurface); context->SetOperator(gfxContext::OPERATOR_SOURCE); context->Paint(); } // Must release reference to dest surface before ending drawing destinationSurface = nullptr; imgSurface = nullptr; srcTextures.AppendElement(tmpTexture); destTextures.AppendElement(mTexture); break; } case SurfaceMode::SURFACE_COMPONENT_ALPHA: { // Must release reference to dest surface before ending drawing destinationSurface = nullptr; opaqueRenderer.End(); opaqueRendererOnWhite.End(); srcTextures.AppendElement(opaqueRenderer.GetTexture()); destTextures.AppendElement(mTexture); srcTextures.AppendElement(opaqueRendererOnWhite.GetTexture()); destTextures.AppendElement(mTextureOnWhite); break; } } NS_ASSERTION(srcTextures.Length() == destTextures.Length(), "Mismatched lengths"); // Copy to the texture. for (uint32_t i = 0; i < srcTextures.Length(); ++i) { nsRefPtr<IDirect3DSurface9> srcSurface; nsRefPtr<IDirect3DSurface9> dstSurface; destTextures[i]->GetSurfaceLevel(0, getter_AddRefs(dstSurface)); srcTextures[i]->GetSurfaceLevel(0, getter_AddRefs(srcSurface)); nsIntRegionRectIterator iter(aRegion); const nsIntRect *iterRect; while ((iterRect = iter.Next())) { RECT rect; rect.left = iterRect->x - bounds.x; rect.top = iterRect->y - bounds.y; rect.right = iterRect->XMost() - bounds.x; rect.bottom = iterRect->YMost() - bounds.y; POINT point; point.x = iterRect->x - visibleRect.x; point.y = iterRect->y - visibleRect.y; device()->UpdateSurface(srcSurface, &rect, dstSurface, &point); } } }
void PaintedLayerD3D9::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode, const nsTArray<ReadbackProcessor::Update>& aReadbackUpdates) { nsIntRect visibleRect = mVisibleRegion.GetBounds(); nsRefPtr<gfxASurface> destinationSurface; nsIntRect bounds = aRegion.GetBounds(); nsRefPtr<IDirect3DTexture9> tmpTexture; OpaqueRenderer opaqueRenderer(aRegion); TransparentRenderer transparentRenderer(aRegion); OpaqueRenderer opaqueRendererOnWhite(aRegion); switch (aMode) { case SurfaceMode::SURFACE_OPAQUE: destinationSurface = opaqueRenderer.Begin(this); break; case SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA: { destinationSurface = transparentRenderer.Begin(this); // If the contents of this layer don't require component alpha in the // end of rendering, it's safe to enable Cleartype since all the Cleartype // glyphs must be over (or under) opaque pixels. destinationSurface->SetSubpixelAntialiasingEnabled(!(mContentFlags & CONTENT_COMPONENT_ALPHA)); break; } case SurfaceMode::SURFACE_COMPONENT_ALPHA: { nsRefPtr<gfxWindowsSurface> onBlack = opaqueRenderer.Begin(this); nsRefPtr<gfxWindowsSurface> onWhite = opaqueRendererOnWhite.Begin(this); if (onBlack && onWhite) { FillSurface(onBlack, aRegion, bounds.TopLeft(), gfxRGBA(0.0, 0.0, 0.0, 1.0)); FillSurface(onWhite, aRegion, bounds.TopLeft(), gfxRGBA(1.0, 1.0, 1.0, 1.0)); gfxASurface* surfaces[2] = { onBlack.get(), onWhite.get() }; destinationSurface = new gfxTeeSurface(surfaces, ArrayLength(surfaces)); // Using this surface as a source will likely go horribly wrong, since // only the onBlack surface will really be used, so alpha information will // be incorrect. destinationSurface->SetAllowUseAsSource(false); } break; } } if (!destinationSurface) return; MOZ_ASSERT(gfxPlatform::GetPlatform()->SupportsAzureContentForType(BackendType::CAIRO)); RefPtr<DrawTarget> dt = gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(destinationSurface, IntSize(destinationSurface->GetSize().width, destinationSurface->GetSize().height)); nsRefPtr<gfxContext> context = new gfxContext(dt); context->SetMatrix(context->CurrentMatrix().Translate(-bounds.x, -bounds.y)); LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo(); cbInfo.Callback(this, context, aRegion, DrawRegionClip::CLIP_NONE, nsIntRegion(), cbInfo.CallbackData); for (uint32_t i = 0; i < aReadbackUpdates.Length(); ++i) { NS_ASSERTION(aMode == SurfaceMode::SURFACE_OPAQUE, "Transparent surfaces should not be used for readback"); const ReadbackProcessor::Update& update = aReadbackUpdates[i]; nsIntPoint offset = update.mLayer->GetBackgroundLayerOffset(); nsRefPtr<gfxContext> ctx = update.mLayer->GetSink()->BeginUpdate(update.mUpdateRect + offset, update.mSequenceCounter); if (ctx) { ctx->SetMatrix(ctx->CurrentMatrix().Translate(offset.x, offset.y)); ctx->SetSource(destinationSurface, gfxPoint(bounds.x, bounds.y)); ctx->Paint(); update.mLayer->GetSink()->EndUpdate(ctx, update.mUpdateRect + offset); } } // Release the cairo d3d9 surface before we try to composite it context = nullptr; nsAutoTArray<IDirect3DTexture9*,2> srcTextures; nsAutoTArray<IDirect3DTexture9*,2> destTextures; switch (aMode) { case SurfaceMode::SURFACE_OPAQUE: // Must release reference to dest surface before ending drawing destinationSurface = nullptr; opaqueRenderer.End(); srcTextures.AppendElement(opaqueRenderer.GetTexture()); destTextures.AppendElement(mTexture); break; case SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA: // Must release reference to dest surface before ending drawing destinationSurface = nullptr; transparentRenderer.End(); srcTextures.AppendElement(transparentRenderer.GetTexture()); destTextures.AppendElement(mTexture); break; case SurfaceMode::SURFACE_COMPONENT_ALPHA: { // Must release reference to dest surface before ending drawing destinationSurface = nullptr; opaqueRenderer.End(); opaqueRendererOnWhite.End(); srcTextures.AppendElement(opaqueRenderer.GetTexture()); destTextures.AppendElement(mTexture); srcTextures.AppendElement(opaqueRendererOnWhite.GetTexture()); destTextures.AppendElement(mTextureOnWhite); break; } } NS_ASSERTION(srcTextures.Length() == destTextures.Length(), "Mismatched lengths"); // Copy to the texture. for (uint32_t i = 0; i < srcTextures.Length(); ++i) { nsRefPtr<IDirect3DSurface9> srcSurface; nsRefPtr<IDirect3DSurface9> dstSurface; destTextures[i]->GetSurfaceLevel(0, getter_AddRefs(dstSurface)); srcTextures[i]->GetSurfaceLevel(0, getter_AddRefs(srcSurface)); nsIntRegionRectIterator iter(aRegion); const nsIntRect *iterRect; while ((iterRect = iter.Next())) { RECT rect; rect.left = iterRect->x - bounds.x; rect.top = iterRect->y - bounds.y; rect.right = iterRect->XMost() - bounds.x; rect.bottom = iterRect->YMost() - bounds.y; POINT point; point.x = iterRect->x - visibleRect.x; point.y = iterRect->y - visibleRect.y; device()->UpdateSurface(srcSurface, &rect, dstSurface, &point); } } }