already_AddRefed<ID2D1Image> GetImageForSourceSurface(DrawTarget *aDT, SourceSurface *aSurface) { if (aDT->IsTiledDrawTarget() || aDT->IsDualDrawTarget() || aDT->IsCaptureDT()) { gfxDevCrash(LogReason::FilterNodeD2D1Target) << "Incompatible draw target type! " << (int)aDT->IsTiledDrawTarget() << " " << (int)aDT->IsDualDrawTarget(); return nullptr; } switch (aDT->GetBackendType()) { case BackendType::DIRECT2D1_1: return static_cast<DrawTargetD2D1*>(aDT)->GetImageForSurface(aSurface, ExtendMode::CLAMP); default: gfxDevCrash(LogReason::FilterNodeD2D1Backend) << "Unknown draw target type! " << (int)aDT->GetBackendType(); return nullptr; } }
PTextureParent* CrossProcessCompositorBridgeParent::AllocPTextureParent(const SurfaceDescriptor& aSharedData, const LayersBackend& aLayersBackend, const TextureFlags& aFlags, const uint64_t& aId, const uint64_t& aSerial) { CompositorBridgeParent::LayerTreeState* state = nullptr; LayerTreeMap::iterator itr = sIndirectLayerTrees.find(aId); if (sIndirectLayerTrees.end() != itr) { state = &itr->second; } TextureFlags flags = aFlags; if (!state || state->mPendingCompositorUpdates) { // The compositor was recreated, and we're receiving layers updates for a // a layer manager that will soon be discarded or invalidated. We can't // return null because this will mess up deserialization later and we'll // kill the content process. Instead, we signal that the underlying // TextureHost should not attempt to access the compositor. flags |= TextureFlags::INVALID_COMPOSITOR; } else if (state->mLayerManager && state->mLayerManager->GetCompositor() && aLayersBackend != state->mLayerManager->GetCompositor()->GetBackendType()) { gfxDevCrash(gfx::LogReason::PAllocTextureBackendMismatch) << "Texture backend is wrong"; } return TextureHost::CreateIPDLActor(this, aSharedData, aLayersBackend, aFlags, aSerial); }
bool DataSourceSurfaceD2D1::Map(MapType aMapType, MappedSurface *aMappedSurface) { // DataSourceSurfaces used with the new Map API should not be used with GetData!! MOZ_ASSERT(!mMapped); MOZ_ASSERT(!mIsMapped); D2D1_MAP_OPTIONS options; if (aMapType == MapType::READ) { options = D2D1_MAP_OPTIONS_READ; } else { gfxDevCrash(LogReason::D2D1NoWriteMap) << "No support for Write maps on D2D1 DataSourceSurfaces yet!"; return false; } D2D1_MAPPED_RECT map; if (FAILED(mBitmap->Map(D2D1_MAP_OPTIONS_READ, &map))) { gfxCriticalError() << "Failed to map bitmap (M)."; return false; } aMappedSurface->mData = map.bits; aMappedSurface->mStride = map.pitch; mIsMapped = !!aMappedSurface->mData; return mIsMapped; }
void AsyncTransactionWaiter::WaitComplete() { MOZ_ASSERT(!InImageBridgeChildThread()); MonitorAutoLock mon(mCompletedMonitor); int count = 0; const int maxCount = 5; while (mWaitCount > 0 && (count < maxCount)) { if (!NS_SUCCEEDED(mCompletedMonitor.Wait(PR_MillisecondsToInterval(10000)))) { NS_WARNING("Failed to wait Monitor"); return; } if (count > 1) { printf_stderr("Waiting async transaction complete.\n"); } count++; } if (mWaitCount > 0) { printf_stderr("Timeout of waiting transaction complete."); } if (count == maxCount) { gfxDevCrash(gfx::LogReason::AsyncTransactionTimeout) << "Bug 1244883: AsyncTransactionWaiter timed out."; } }
RefPtr<UnscaledFont> GetUnscaledFont(Translator *aTranslator, wr::FontKey key) { StaticMutexAutoLock lock(sFontDataTableLock); auto i = sFontDataTable.find(key); if (i == sFontDataTable.end()) { gfxDevCrash(LogReason::UnscaledFontNotFound) << "Failed to get UnscaledFont entry for FontKey " << key.mHandle << " because " << sFontDeleteLog.Find(key); return nullptr; } FontTemplate &data = i->second; if (data.mUnscaledFont) { return data.mUnscaledFont; } MOZ_ASSERT(data.mData); FontType type = #ifdef XP_MACOSX FontType::MAC; #elif defined(XP_WIN) FontType::DWRITE; #elif defined(ANDROID) FontType::FREETYPE; #else FontType::FONTCONFIG; #endif // makes a copy of the data RefPtr<NativeFontResource> fontResource = Factory::CreateNativeFontResource((uint8_t*)data.mData, data.mSize, aTranslator->GetReferenceDrawTarget()->GetBackendType(), type, aTranslator->GetFontContext()); RefPtr<UnscaledFont> unscaledFont; if (!fontResource) { gfxDevCrash(LogReason::NativeFontResourceNotFound) << "Failed to create NativeFontResource for FontKey " << key.mHandle; } else { // Instance data is only needed for GDI fonts which webrender does not // support. unscaledFont = fontResource->CreateUnscaledFont(data.mIndex, nullptr, 0); if (!unscaledFont) { gfxDevCrash(LogReason::UnscaledFontNotFound) << "Failed to create UnscaledFont for FontKey " << key.mHandle; } } data.mUnscaledFont = unscaledFont; return unscaledFont; }
bool ScaledFontWin::GetFontFileData(FontFileDataOutput aDataCallback, void *aBaton) { AutoDC dc; AutoSelectFont font(dc.GetDC(), &mLogFont); // Check for a font collection first. uint32_t table = 0x66637474; // 'ttcf' uint32_t tableSize = ::GetFontData(dc.GetDC(), table, 0, nullptr, 0); if (tableSize == GDI_ERROR) { // Try as if just a single font. table = 0; tableSize = ::GetFontData(dc.GetDC(), table, 0, nullptr, 0); if (tableSize == GDI_ERROR) { return false; } } UniquePtr<uint8_t[]> fontData(new uint8_t[tableSize]); uint32_t sizeGot = ::GetFontData(dc.GetDC(), table, 0, fontData.get(), tableSize); if (sizeGot != tableSize) { return false; } // If it's a font collection then attempt to get the index. uint32_t index = 0; if (table != 0) { UniquePtr<SFNTData> sfntData = SFNTData::Create(fontData.get(), tableSize); if (!sfntData) { gfxWarning() << "Failed to create SFNTData for GetFontFileData."; return false; } // We cast here because for VS2015 char16_t != wchar_t, even though they are // both 16 bit. if (!sfntData->GetIndexForU16Name( reinterpret_cast<char16_t*>(mLogFont.lfFaceName), &index, LF_FACESIZE - 1)) { gfxWarning() << "Failed to get index for face name."; gfxDevCrash(LogReason::GetFontFileDataFailed) << "Failed to get index for face name |" << NS_ConvertUTF16toUTF8(mLogFont.lfFaceName).get() << "|."; return false; } } aDataCallback(fontData.get(), tableSize, index, mSize, aBaton); return true; }
void ContentClientBasic::CreateBuffer(ContentType aType, const IntRect& aRect, uint32_t aFlags, RefPtr<gfx::DrawTarget>* aBlackDT, RefPtr<gfx::DrawTarget>* aWhiteDT) { MOZ_ASSERT(!(aFlags & BUFFER_COMPONENT_ALPHA)); if (aFlags & BUFFER_COMPONENT_ALPHA) { gfxDevCrash(LogReason::AlphaWithBasicClient) << "Asking basic content client for component alpha"; } *aBlackDT = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget( IntSize(aRect.width, aRect.height), gfxPlatform::GetPlatform()->Optimal2DFormatForContent(aType)); }
static bool LockD3DTexture(T* aTexture) { MOZ_ASSERT(aTexture); RefPtr<IDXGIKeyedMutex> mutex; aTexture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mutex)); // Textures created by the DXVA decoders don't have a mutex for synchronization if (mutex) { HRESULT hr = mutex->AcquireSync(0, 10000); if (hr == WAIT_TIMEOUT) { gfxDevCrash(LogReason::D3DLockTimeout) << "D3D lock mutex timeout"; } if (FAILED(hr)) { NS_WARNING("Failed to lock the texture"); return false; } } return true; }
void ClientSingleTiledLayerBuffer::PaintThebes( const nsIntRegion& aNewValidRegion, const nsIntRegion& aPaintRegion, const nsIntRegion& aDirtyRegion, LayerManager::DrawPaintedLayerCallback aCallback, void* aCallbackData, TilePaintFlags aFlags) { mWasLastPaintProgressive = !!(aFlags & TilePaintFlags::Progressive); bool asyncPaint = !!(aFlags & TilePaintFlags::Async); // Compare layer valid region size to current backbuffer size, discard if not // matching. gfx::IntSize size = aNewValidRegion.GetBounds().Size(); gfx::IntPoint origin = aNewValidRegion.GetBounds().TopLeft(); nsIntRegion paintRegion = aPaintRegion; RefPtr<TextureClient> discardedFrontBuffer = nullptr; RefPtr<TextureClient> discardedFrontBufferOnWhite = nullptr; nsIntRegion discardedValidRegion; if (mSize != size || mTilingOrigin != origin) { discardedFrontBuffer = mTile.mFrontBuffer; discardedFrontBufferOnWhite = mTile.mFrontBufferOnWhite; discardedValidRegion = mValidRegion; TILING_LOG( "TILING %p: Single-tile valid region changed. Discarding buffers.\n", &mPaintedLayer); ResetPaintedAndValidState(); mSize = size; mTilingOrigin = origin; paintRegion = aNewValidRegion; } SurfaceMode mode; gfxContentType content = GetContentType(&mode); mFormat = gfxPlatform::GetPlatform()->OptimalFormatForContent(content); if (mTile.IsPlaceholderTile()) { mTile.SetTextureAllocator(this); } if (mManager->AsShadowForwarder()->SupportsTextureDirectMapping()) { AutoTArray<uint64_t, 2> syncTextureSerials; mTile.GetSyncTextureSerials(mode, syncTextureSerials); if (syncTextureSerials.Length() > 0) { mManager->AsShadowForwarder()->SyncTextures(syncTextureSerials); } } // The dirty region relative to the top-left of the tile. nsIntRegion tileVisibleRegion = aNewValidRegion.MovedBy(-mTilingOrigin); nsIntRegion tileDirtyRegion = paintRegion.MovedBy(-mTilingOrigin); Maybe<AcquiredBackBuffer> backBuffer = mTile.AcquireBackBuffer(mCompositableClient, tileDirtyRegion, tileVisibleRegion, content, mode, aFlags); if (!backBuffer) { return; } // Mark the area we need to paint in the back buffer as invalid in the // front buffer as they will become out of sync. mTile.mInvalidFront.OrWith(tileDirtyRegion); // Add backbuffer's invalid region to the dirty region to be painted. // This will be empty if we were able to copy from the front in to the back. nsIntRegion tileInvalidRegion = mTile.mInvalidBack; tileInvalidRegion.AndWith(tileVisibleRegion); paintRegion.OrWith(tileInvalidRegion.MovedBy(mTilingOrigin)); tileDirtyRegion.OrWith(tileInvalidRegion); // Mark the region we will be painting and the region we copied from the front // buffer as needing to be uploaded to the compositor mTile.mUpdateRect = tileDirtyRegion.GetBounds().Union(backBuffer->mUpdatedRect); // If the old frontbuffer was discarded then attempt to copy what we // can from it to the new backbuffer. if (discardedFrontBuffer) { nsIntRegion copyableRegion; copyableRegion.And(aNewValidRegion, discardedValidRegion); copyableRegion.SubOut(aDirtyRegion); OpenMode readMode = asyncPaint ? OpenMode::OPEN_READ_ASYNC : OpenMode::OPEN_READ; DualTextureClientAutoLock discardedBuffer( discardedFrontBuffer, discardedFrontBufferOnWhite, readMode); if (discardedBuffer.Succeeded()) { RefPtr<gfx::SourceSurface> discardedSurface = discardedBuffer->Snapshot(); for (auto iter = copyableRegion.RectIter(); !iter.Done(); iter.Next()) { const gfx::IntRect src = iter.Get() - discardedValidRegion.GetBounds().TopLeft(); const gfx::IntPoint dest = iter.Get().TopLeft() - mTilingOrigin; backBuffer->mTarget->CopySurface(discardedSurface, src, dest); } TILING_LOG("TILING %p: Region copied from discarded frontbuffer %s\n", &mPaintedLayer, Stringify(copyableRegion).c_str()); // We don't need to repaint valid content that was just copied. paintRegion.SubOut(copyableRegion); copyableRegion.MoveBy(-mTilingOrigin); tileDirtyRegion.SubOut(copyableRegion); } else { gfxWarning() << "[Tiling:Client] Failed to aquire the discarded front " "buffer's draw target"; } } if (mode != SurfaceMode::SURFACE_OPAQUE) { for (auto iter = tileDirtyRegion.RectIter(); !iter.Done(); iter.Next()) { const gfx::Rect drawRect(iter.Get().X(), iter.Get().Y(), iter.Get().Width(), iter.Get().Height()); backBuffer->mTarget->ClearRect(drawRect); } } // Paint into the target { RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(backBuffer->mTarget); if (!ctx) { gfxDevCrash(gfx::LogReason::InvalidContext) << "SingleTiledContextClient context problem " << gfx::hexa(backBuffer->mTarget); return; } ctx->SetMatrix( ctx->CurrentMatrix().PreTranslate(-mTilingOrigin.x, -mTilingOrigin.y)); aCallback(&mPaintedLayer, ctx, paintRegion, paintRegion, DrawRegionClip::DRAW, nsIntRegion(), aCallbackData); } if (asyncPaint) { if (!backBuffer->mCapture->IsEmpty()) { UniquePtr<PaintTask> task(new PaintTask()); task->mCapture = backBuffer->mCapture; task->mTarget = backBuffer->mBackBuffer; task->mClients = std::move(backBuffer->mTextureClients); if (discardedFrontBuffer) { task->mClients.AppendElement(discardedFrontBuffer); } if (discardedFrontBufferOnWhite) { task->mClients.AppendElement(discardedFrontBufferOnWhite); } // The target is an alias for the capture, and the paint thread expects // to be the only one with a reference to the capture backBuffer->mTarget = nullptr; backBuffer->mCapture = nullptr; PaintThread::Get()->QueuePaintTask(std::move(task)); mManager->SetQueuedAsyncPaints(); } } else { MOZ_ASSERT(backBuffer->mTarget == backBuffer->mBackBuffer); MOZ_ASSERT(!backBuffer->mCapture); } // The new buffer is now validated, remove the dirty region from it. mTile.mInvalidBack.SubOut(tileDirtyRegion); backBuffer = Nothing(); mTile.Flip(); UnlockTile(mTile); mValidRegion = aNewValidRegion; mLastPaintSurfaceMode = mode; mLastPaintContentType = content; }
void ClientSingleTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion, const nsIntRegion& aPaintRegion, const nsIntRegion& aDirtyRegion, LayerManager::DrawPaintedLayerCallback aCallback, void* aCallbackData, bool aIsProgressive) { mWasLastPaintProgressive = aIsProgressive; // Compare layer valid region size to current backbuffer size, discard if not matching. gfx::IntSize size = aNewValidRegion.GetBounds().Size(); gfx::IntPoint origin = aNewValidRegion.GetBounds().TopLeft(); nsIntRegion paintRegion = aPaintRegion; RefPtr<TextureClient> discardedFrontBuffer = nullptr; RefPtr<TextureClient> discardedFrontBufferOnWhite = nullptr; nsIntRegion discardedValidRegion; if (mSize != size || mTilingOrigin != origin) { discardedFrontBuffer = mTile.mFrontBuffer; discardedFrontBufferOnWhite = mTile.mFrontBufferOnWhite; discardedValidRegion = mValidRegion; TILING_LOG("TILING %p: Single-tile valid region changed. Discarding buffers.\n", &mPaintedLayer) ; ResetPaintedAndValidState(); mSize = size; mTilingOrigin = origin; paintRegion = aNewValidRegion; } SurfaceMode mode; gfxContentType content = GetContentType(&mode); mFormat = gfxPlatform::GetPlatform()->OptimalFormatForContent(content); if (mTile.IsPlaceholderTile()) { mTile.SetTextureAllocator(this); } // The dirty region relative to the top-left of the tile. nsIntRegion tileDirtyRegion = paintRegion.MovedBy(-mTilingOrigin); nsIntRegion extraPainted; RefPtr<TextureClient> backBufferOnWhite; RefPtr<TextureClient> backBuffer = mTile.GetBackBuffer(mCompositableClient, tileDirtyRegion, content, mode, extraPainted, &backBufferOnWhite); mTile.mUpdateRect = tileDirtyRegion.GetBounds().Union(extraPainted.GetBounds()); extraPainted.MoveBy(mTilingOrigin); extraPainted.And(extraPainted, aNewValidRegion); mPaintedRegion.OrWith(paintRegion); mPaintedRegion.OrWith(extraPainted); if (!backBuffer) { return; } RefPtr<gfx::DrawTarget> dt = backBuffer->BorrowDrawTarget(); RefPtr<gfx::DrawTarget> dtOnWhite; if (backBufferOnWhite) { dtOnWhite = backBufferOnWhite->BorrowDrawTarget(); } if (mode != SurfaceMode::SURFACE_OPAQUE) { for (auto iter = tileDirtyRegion.RectIter(); !iter.Done(); iter.Next()) { const gfx::IntRect& rect = iter.Get(); if (dtOnWhite) { dt->FillRect(gfx::Rect(rect.x, rect.y, rect.width, rect.height), gfx::ColorPattern(gfx::Color(0.0, 0.0, 0.0, 1.0))); dtOnWhite->FillRect(gfx::Rect(rect.x, rect.y, rect.width, rect.height), gfx::ColorPattern(gfx::Color(1.0, 1.0, 1.0, 1.0))); } else { dt->ClearRect(gfx::Rect(rect.x, rect.y, rect.width, rect.height)); } } } // If the old frontbuffer was discarded then attempt to copy what we // can from it to the new backbuffer. if (discardedFrontBuffer) { nsIntRegion copyableRegion; copyableRegion.And(aNewValidRegion, discardedValidRegion); copyableRegion.SubOut(aDirtyRegion); if (!copyableRegion.IsEmpty()) { TextureClientAutoLock frontLock(discardedFrontBuffer, OpenMode::OPEN_READ); if (frontLock.Succeeded()) { for (auto iter = copyableRegion.RectIter(); !iter.Done(); iter.Next()) { const gfx::IntRect rect = iter.Get() - discardedValidRegion.GetBounds().TopLeft(); const gfx::IntPoint dest = iter.Get().TopLeft() - mTilingOrigin; discardedFrontBuffer->CopyToTextureClient(backBuffer, &rect, &dest); } } if (discardedFrontBufferOnWhite && backBufferOnWhite) { TextureClientAutoLock frontOnWhiteLock(discardedFrontBufferOnWhite, OpenMode::OPEN_READ); if (frontOnWhiteLock.Succeeded()) { for (auto iter = copyableRegion.RectIter(); !iter.Done(); iter.Next()) { const gfx::IntRect rect = iter.Get() - discardedValidRegion.GetBounds().TopLeft(); const gfx::IntPoint dest = iter.Get().TopLeft() - mTilingOrigin; discardedFrontBufferOnWhite->CopyToTextureClient(backBufferOnWhite, &rect, &dest); } } } TILING_LOG("TILING %p: Region copied from discarded frontbuffer %s\n", &mPaintedLayer, Stringify(copyableRegion).c_str()); // We don't need to repaint valid content that was just copied. paintRegion.SubOut(copyableRegion); } } if (dtOnWhite) { dt = gfx::Factory::CreateDualDrawTarget(dt, dtOnWhite); dtOnWhite = nullptr; } { RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(dt); if (!ctx) { gfxDevCrash(gfx::LogReason::InvalidContext) << "SingleTiledContextClient context problem " << gfx::hexa(dt); return; } ctx->SetMatrix(ctx->CurrentMatrix().Translate(-mTilingOrigin.x, -mTilingOrigin.y)); aCallback(&mPaintedLayer, ctx, paintRegion, paintRegion, DrawRegionClip::DRAW, nsIntRegion(), aCallbackData); } // Mark the area we just drew into the back buffer as invalid in the front buffer as they're // now out of sync. mTile.mInvalidFront.OrWith(tileDirtyRegion); // The new buffer is now validated, remove the dirty region from it. mTile.mInvalidBack.SubOut(tileDirtyRegion); dt = nullptr; mTile.Flip(); UnlockTile(mTile); if (backBuffer->HasIntermediateBuffer()) { // If our new buffer has an internal buffer, we don't want to keep another // TextureClient around unnecessarily, so discard the back-buffer. mTile.DiscardBackBuffer(); } mValidRegion = aNewValidRegion; mLastPaintSurfaceMode = mode; mLastPaintContentType = content; }
void BasicCompositor::DrawQuad(const gfx::Rect& aRect, const gfx::Rect& aClipRect, const EffectChain &aEffectChain, gfx::Float aOpacity, const gfx::Matrix4x4& aTransform, const gfx::Rect& aVisibleRect) { RefPtr<DrawTarget> buffer = mRenderTarget->mDrawTarget; // For 2D drawing, |dest| and |buffer| are the same surface. For 3D drawing, // |dest| is a temporary surface. RefPtr<DrawTarget> dest = buffer; AutoRestoreTransform autoRestoreTransform(dest); Matrix newTransform; Rect transformBounds; Matrix4x4 new3DTransform; IntPoint offset = mRenderTarget->GetOrigin(); if (aTransform.Is2D()) { newTransform = aTransform.As2D(); } else { // Create a temporary surface for the transform. dest = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(RoundOut(aRect).Size(), SurfaceFormat::B8G8R8A8); if (!dest) { return; } dest->SetTransform(Matrix::Translation(-aRect.x, -aRect.y)); // Get the bounds post-transform. transformBounds = aTransform.TransformAndClipBounds(aRect, Rect(offset.x, offset.y, buffer->GetSize().width, buffer->GetSize().height)); transformBounds.RoundOut(); if (transformBounds.IsEmpty()) { return; } // Propagate the coordinate offset to our 2D draw target. newTransform = Matrix::Translation(transformBounds.x, transformBounds.y); // When we apply the 3D transformation, we do it against a temporary // surface, so undo the coordinate offset. new3DTransform = Matrix4x4::Translation(aRect.x, aRect.y, 0) * aTransform; } buffer->PushClipRect(aClipRect); newTransform.PostTranslate(-offset.x, -offset.y); buffer->SetTransform(newTransform); RefPtr<SourceSurface> sourceMask; Matrix maskTransform; if (aEffectChain.mSecondaryEffects[EffectTypes::MASK]) { EffectMask *effectMask = static_cast<EffectMask*>(aEffectChain.mSecondaryEffects[EffectTypes::MASK].get()); sourceMask = effectMask->mMaskTexture->AsSourceBasic()->GetSurface(dest); if (!sourceMask) { gfxWarning() << "Invalid sourceMask effect"; } MOZ_ASSERT(effectMask->mMaskTransform.Is2D(), "How did we end up with a 3D transform here?!"); MOZ_ASSERT(!effectMask->mIs3D); maskTransform = effectMask->mMaskTransform.As2D(); maskTransform.PreTranslate(-offset.x, -offset.y); } CompositionOp blendMode = CompositionOp::OP_OVER; if (Effect* effect = aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE].get()) { blendMode = static_cast<EffectBlendMode*>(effect)->mBlendMode; } switch (aEffectChain.mPrimaryEffect->mType) { case EffectTypes::SOLID_COLOR: { EffectSolidColor* effectSolidColor = static_cast<EffectSolidColor*>(aEffectChain.mPrimaryEffect.get()); bool unboundedOp = !IsOperatorBoundByMask(blendMode); if (unboundedOp) { dest->PushClipRect(aRect); } FillRectWithMask(dest, aRect, effectSolidColor->mColor, DrawOptions(aOpacity, blendMode), sourceMask, &maskTransform); if (unboundedOp) { dest->PopClip(); } break; } case EffectTypes::RGB: { TexturedEffect* texturedEffect = static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get()); TextureSourceBasic* source = texturedEffect->mTexture->AsSourceBasic(); if (source && texturedEffect->mPremultiplied) { DrawSurfaceWithTextureCoords(dest, aRect, source->GetSurface(dest), texturedEffect->mTextureCoords, texturedEffect->mFilter, DrawOptions(aOpacity, blendMode), sourceMask, &maskTransform); } else if (source) { SourceSurface* srcSurf = source->GetSurface(dest); if (srcSurf) { RefPtr<DataSourceSurface> srcData = srcSurf->GetDataSurface(); // Yes, we re-create the premultiplied data every time. // This might be better with a cache, eventually. RefPtr<DataSourceSurface> premultData = gfxUtils::CreatePremultipliedDataSurface(srcData); DrawSurfaceWithTextureCoords(dest, aRect, premultData, texturedEffect->mTextureCoords, texturedEffect->mFilter, DrawOptions(aOpacity, blendMode), sourceMask, &maskTransform); } } else { gfxDevCrash(LogReason::IncompatibleBasicTexturedEffect) << "Bad for basic with " << texturedEffect->mTexture->Name() << " and " << gfx::hexa(sourceMask); } break; } case EffectTypes::YCBCR: { NS_RUNTIMEABORT("Can't (easily) support component alpha with BasicCompositor!"); break; } case EffectTypes::RENDER_TARGET: { EffectRenderTarget* effectRenderTarget = static_cast<EffectRenderTarget*>(aEffectChain.mPrimaryEffect.get()); RefPtr<BasicCompositingRenderTarget> surface = static_cast<BasicCompositingRenderTarget*>(effectRenderTarget->mRenderTarget.get()); RefPtr<SourceSurface> sourceSurf = surface->mDrawTarget->Snapshot(); DrawSurfaceWithTextureCoords(dest, aRect, sourceSurf, effectRenderTarget->mTextureCoords, effectRenderTarget->mFilter, DrawOptions(aOpacity, blendMode), sourceMask, &maskTransform); break; } case EffectTypes::COMPONENT_ALPHA: { NS_RUNTIMEABORT("Can't (easily) support component alpha with BasicCompositor!"); break; } default: { NS_RUNTIMEABORT("Invalid effect type!"); break; } } if (!aTransform.Is2D()) { dest->Flush(); RefPtr<SourceSurface> snapshot = dest->Snapshot(); RefPtr<DataSourceSurface> source = snapshot->GetDataSurface(); RefPtr<DataSourceSurface> temp = Factory::CreateDataSourceSurface(RoundOut(transformBounds).Size(), SurfaceFormat::B8G8R8A8 #ifdef MOZ_ENABLE_SKIA , true #endif ); if (NS_WARN_IF(!temp)) { buffer->PopClip(); return; } Transform(temp, source, new3DTransform, transformBounds.TopLeft()); transformBounds.MoveTo(0, 0); buffer->DrawSurface(temp, transformBounds, transformBounds); } buffer->PopClip(); }