bool CompositableHost::AddMaskEffect(EffectChain& aEffects, const gfx::Matrix4x4& aTransform, bool aIs3D) { RefPtr<TextureSource> source; RefPtr<DeprecatedTextureHost> oldHost = GetDeprecatedTextureHost(); if (oldHost) { oldHost->Lock(); source = oldHost; } else { RefPtr<TextureHost> host = GetTextureHost(); if (host) { host->Lock(); source = host->GetTextureSources(); } } if (!source) { NS_WARNING("Using compositable with no texture host as mask layer"); return false; } RefPtr<EffectMask> effect = new EffectMask(source, source->GetSize(), aTransform); effect->mIs3D = aIs3D; aEffects.mSecondaryEffects[EFFECT_MASK] = effect; return true; }
bool CompositableHost::AddMaskEffect(EffectChain& aEffects, const gfx::Matrix4x4& aTransform, bool aIs3D) { CompositableTextureSourceRef source; RefPtr<TextureHost> host = GetAsTextureHost(); if (!host) { NS_WARNING("Using compositable with no valid TextureHost as mask"); return false; } if (!host->Lock()) { NS_WARNING("Failed to lock the mask texture"); return false; } if (!host->BindTextureSource(source)) { NS_WARNING("The TextureHost was successfully locked but can't provide a TextureSource"); host->Unlock(); return false; } MOZ_ASSERT(source); RefPtr<EffectMask> effect = new EffectMask(source, source->GetSize(), aTransform); effect->mIs3D = aIs3D; aEffects.mSecondaryEffects[EffectTypes::MASK] = effect; return true; }
// Same as above, for YCbCr surfaces void TestTextureClientYCbCr(TextureClient* client, PlanarYCbCrData& ycbcrData) { client->Lock(OpenMode::OPEN_READ_WRITE); UpdateYCbCrTextureClient(client, ycbcrData); client->Unlock(); // client serialization SurfaceDescriptor descriptor; ASSERT_TRUE(client->ToSurfaceDescriptor(descriptor)); ASSERT_EQ(descriptor.type(), SurfaceDescriptor::TSurfaceDescriptorBuffer); auto bufferDesc = descriptor.get_SurfaceDescriptorBuffer(); ASSERT_EQ(bufferDesc.desc().type(), BufferDescriptor::TYCbCrDescriptor); auto ycbcrDesc = bufferDesc.desc().get_YCbCrDescriptor(); ASSERT_EQ(ycbcrDesc.ySize(), ycbcrData.mYSize); ASSERT_EQ(ycbcrDesc.cbCrSize(), ycbcrData.mCbCrSize); ASSERT_EQ(ycbcrDesc.stereoMode(), ycbcrData.mStereoMode); // host deserialization RefPtr<TextureHost> textureHost = CreateBackendIndependentTextureHost(descriptor, nullptr, client->GetFlags()); RefPtr<BufferTextureHost> host = static_cast<BufferTextureHost*>(textureHost.get()); ASSERT_TRUE(host.get() != nullptr); ASSERT_EQ(host->GetFlags(), client->GetFlags()); // host read if (host->Lock()) { // This will work iff the compositor is not BasicCompositor ASSERT_EQ(host->GetFormat(), mozilla::gfx::SurfaceFormat::YUV); host->Unlock(); } }
SourceSurfaceCGIOSurfaceContext::SourceSurfaceCGIOSurfaceContext(DrawTargetCG *aDrawTarget) { #if(1) fprintf(stderr, "SourceSurfaceCGIOSurfaceContext not supported on 10.4\n"); #else CGContextRef cg = (CGContextRef)aDrawTarget->GetNativeSurface(NativeSurfaceType::CGCONTEXT_ACCELERATED); RefPtr<MacIOSurface> surf = MacIOSurface::IOSurfaceContextGetSurface(cg); mFormat = aDrawTarget->GetFormat(); mSize.width = surf->GetWidth(); mSize.height = surf->GetHeight(); // TODO use CreateImageFromIOSurfaceContext instead of reading back the surface //mImage = MacIOSurface::CreateImageFromIOSurfaceContext(cg); mImage = nullptr; aDrawTarget->Flush(); surf->Lock(); size_t bytesPerRow = surf->GetBytesPerRow(); size_t ioHeight = surf->GetHeight(); void* ioData = surf->GetBaseAddress(); // XXX If the width is much less then the stride maybe // we should repack the image? mData = malloc(ioHeight*bytesPerRow); memcpy(mData, ioData, ioHeight*(bytesPerRow)); mStride = bytesPerRow; surf->Unlock(); #endif }
// Same as above, for YCbCr surfaces void TestTextureClientYCbCr(TextureClient* client, PlanarYCbCrData& ycbcrData) { // client allocation ASSERT_TRUE(client->AsTextureClientYCbCr() != nullptr); TextureClientYCbCr* texture = client->AsTextureClientYCbCr(); texture->AllocateForYCbCr(ToIntSize(ycbcrData.mYSize), ToIntSize(ycbcrData.mCbCrSize), ycbcrData.mStereoMode); ASSERT_TRUE(client->IsAllocated()); // client painting texture->UpdateYCbCr(ycbcrData); ASSERT_TRUE(client->Lock(OPEN_READ_ONLY)); client->Unlock(); // client serialization SurfaceDescriptor descriptor; ASSERT_TRUE(client->ToSurfaceDescriptor(descriptor)); ASSERT_NE(descriptor.type(), SurfaceDescriptor::Tnull_t); // host deserialization RefPtr<TextureHost> textureHost = CreateBackendIndependentTextureHost(descriptor, nullptr, client->GetFlags()); RefPtr<BufferTextureHost> host = static_cast<BufferTextureHost*>(textureHost.get()); ASSERT_TRUE(host.get() != nullptr); ASSERT_EQ(host->GetFlags(), client->GetFlags()); // This will work iff the compositor is not BasicCompositor ASSERT_EQ(host->GetFormat(), mozilla::gfx::FORMAT_YUV); // host read ASSERT_TRUE(host->Lock()); ASSERT_TRUE(host->GetFormat() == mozilla::gfx::FORMAT_YUV); YCbCrImageDataDeserializer yuvDeserializer(host->GetBuffer()); ASSERT_TRUE(yuvDeserializer.IsValid()); PlanarYCbCrData data; data.mYChannel = yuvDeserializer.GetYData(); data.mCbChannel = yuvDeserializer.GetCbData(); data.mCrChannel = yuvDeserializer.GetCrData(); data.mYStride = yuvDeserializer.GetYStride(); data.mCbCrStride = yuvDeserializer.GetCbCrStride(); data.mStereoMode = yuvDeserializer.GetStereoMode(); data.mYSize = yuvDeserializer.GetYSize(); data.mCbCrSize = yuvDeserializer.GetCbCrSize(); data.mYSkip = 0; data.mCbSkip = 0; data.mCrSkip = 0; data.mPicSize = data.mYSize; data.mPicX = 0; data.mPicY = 0; AssertYCbCrSurfacesEqual(&ycbcrData, &data); host->Unlock(); }
// 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(); } }
// 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()); }
TextureClient* CairoImage::GetTextureClient(CompositableClient *aClient) { if (!aClient) { return nullptr; } CompositableForwarder* forwarder = aClient->GetForwarder(); RefPtr<TextureClient> textureClient = mTextureClients.Get(forwarder->GetSerial()); if (textureClient) { return textureClient; } RefPtr<SourceSurface> surface = GetAsSourceSurface(); MOZ_ASSERT(surface); if (!surface) { return nullptr; } // gfx::BackendType::NONE means default to content backend textureClient = aClient->CreateTextureClientForDrawing(surface->GetFormat(), surface->GetSize(), gfx::BackendType::NONE, TextureFlags::DEFAULT); if (!textureClient) { return nullptr; } MOZ_ASSERT(textureClient->CanExposeDrawTarget()); if (!textureClient->Lock(OpenMode::OPEN_WRITE_ONLY)) { return nullptr; } TextureClientAutoUnlock autoUnolck(textureClient); { // We must not keep a reference to the DrawTarget after it has been unlocked. DrawTarget* dt = textureClient->BorrowDrawTarget(); if (!dt) { return nullptr; } dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint()); } mTextureClients.Put(forwarder->GetSerial(), textureClient); return textureClient; }
HRESULT MFTDecoder::CreateInputSample(const uint8_t* aData, uint32_t aDataSize, int64_t aTimestamp, RefPtr<IMFSample>* aOutSample) { NS_ENSURE_TRUE(mDecoder != nullptr, E_POINTER); HRESULT hr; RefPtr<IMFSample> sample; hr = wmf::MFCreateSample(byRef(sample)); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); RefPtr<IMFMediaBuffer> buffer; int32_t bufferSize = std::max<uint32_t>(uint32_t(mInputStreamInfo.cbSize), aDataSize); UINT32 alignment = (mInputStreamInfo.cbAlignment > 1) ? mInputStreamInfo.cbAlignment - 1 : 0; hr = wmf::MFCreateAlignedMemoryBuffer(bufferSize, alignment, byRef(buffer)); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); DWORD maxLength = 0; DWORD currentLength = 0; BYTE* dst = nullptr; hr = buffer->Lock(&dst, &maxLength, ¤tLength); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); // Copy data into sample's buffer. memcpy(dst, aData, aDataSize); hr = buffer->Unlock(); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); hr = buffer->SetCurrentLength(aDataSize); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); hr = sample->AddBuffer(buffer); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); hr = sample->SetSampleTime(UsecsToHNs(aTimestamp)); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); *aOutSample = sample.forget(); return S_OK; }
// Run the test for a texture client and a surface void TestTextureClientSurface(TextureClient* texture, gfxImageSurface* surface) { // client allocation ASSERT_TRUE(texture->AsTextureClientSurface() != nullptr); TextureClientSurface* client = texture->AsTextureClientSurface(); client->AllocateForSurface(ToIntSize(surface->GetSize())); ASSERT_TRUE(texture->IsAllocated()); // client painting client->UpdateSurface(surface); nsRefPtr<gfxASurface> aSurface = client->GetAsSurface(); nsRefPtr<gfxImageSurface> clientSurface = aSurface->GetAsImageSurface(); ASSERT_TRUE(texture->Lock(OPEN_READ_ONLY)); AssertSurfacesEqual(surface, clientSurface); texture->Unlock(); // client serialization texture->SetID(1); SurfaceDescriptor descriptor; ASSERT_TRUE(texture->ToSurfaceDescriptor(descriptor)); ASSERT_NE(descriptor.type(), SurfaceDescriptor::Tnull_t); // host deserialization RefPtr<TextureHost> host = CreateBackendIndependentTextureHost(texture->GetID(), descriptor, nullptr, texture->GetFlags()); ASSERT_TRUE(host.get() != nullptr); ASSERT_EQ(host->GetFlags(), texture->GetFlags()); ASSERT_EQ(host->GetID(), texture->GetID()); // host read ASSERT_TRUE(host->Lock()); nsRefPtr<gfxImageSurface> hostSurface = host->GetAsSurface(); host->Unlock(); AssertSurfacesEqual(surface, hostSurface.get()); // host deallocation host->DeallocateSharedData(); }
// Run the test for a texture client and a surface void TestTextureClientSurface(TextureClient* texture, gfxImageSurface* surface) { // client allocation ASSERT_TRUE(texture->AsTextureClientSurface() != nullptr); TextureClientSurface* client = texture->AsTextureClientSurface(); client->AllocateForSurface(ToIntSize(surface->GetSize())); ASSERT_TRUE(texture->IsAllocated()); ASSERT_TRUE(texture->Lock(OPEN_READ_WRITE)); // client painting client->UpdateSurface(surface); nsRefPtr<gfxASurface> aSurface = client->GetAsSurface(); nsRefPtr<gfxImageSurface> clientSurface = aSurface->GetAsImageSurface(); AssertSurfacesEqual(surface, clientSurface); 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()); }
/* static */ already_AddRefed<TextureClient> ImageClient::CreateTextureClientForImage(Image* aImage, KnowsCompositor* aForwarder) { RefPtr<TextureClient> texture; if (aImage->GetFormat() == ImageFormat::PLANAR_YCBCR) { PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(aImage); const PlanarYCbCrData* data = ycbcr->GetData(); if (!data) { return nullptr; } texture = TextureClient::CreateForYCbCr(aForwarder, data->mYSize, data->mYStride, data->mCbCrSize, data->mCbCrStride, data->mStereoMode, data->mColorDepth, data->mYUVColorSpace, TextureFlags::DEFAULT); if (!texture) { return nullptr; } TextureClientAutoLock autoLock(texture, OpenMode::OPEN_WRITE_ONLY); if (!autoLock.Succeeded()) { return nullptr; } bool status = UpdateYCbCrTextureClient(texture, *data); MOZ_ASSERT(status); if (!status) { return nullptr; } #ifdef MOZ_WIDGET_ANDROID } else if (aImage->GetFormat() == ImageFormat::SURFACE_TEXTURE) { gfx::IntSize size = aImage->GetSize(); SurfaceTextureImage* typedImage = aImage->AsSurfaceTextureImage(); texture = AndroidSurfaceTextureData::CreateTextureClient( typedImage->GetHandle(), size, typedImage->GetContinuous(), typedImage->GetOriginPos(), aForwarder->GetTextureForwarder(), TextureFlags::DEFAULT); #endif } else { RefPtr<gfx::SourceSurface> surface = aImage->GetAsSourceSurface(); MOZ_ASSERT(surface); texture = TextureClient::CreateForDrawing(aForwarder, surface->GetFormat(), aImage->GetSize(), BackendSelector::Content, TextureFlags::DEFAULT); if (!texture) { return nullptr; } MOZ_ASSERT(texture->CanExposeDrawTarget()); if (!texture->Lock(OpenMode::OPEN_WRITE_ONLY)) { return nullptr; } { // We must not keep a reference to the DrawTarget after it has been unlocked. DrawTarget* dt = texture->BorrowDrawTarget(); if (!dt) { gfxWarning() << "ImageClientSingle::UpdateImage failed in BorrowDrawTarget"; return nullptr; } MOZ_ASSERT(surface.get()); dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint()); } texture->Unlock(); } return texture.forget(); }
bool WMFReader::DecodeAudioData() { NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); HRESULT hr; hr = mSourceReader->ReadSample(MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, // control flags 0, // read stream index nullptr, nullptr, nullptr); if (FAILED(hr)) { LOG("WMFReader::DecodeAudioData() ReadSample failed with hr=0x%x", hr); // End the stream. mAudioQueue.Finish(); return false; } DWORD flags = 0; LONGLONG timestampHns = 0; RefPtr<IMFSample> sample; hr = mSourceReaderCallback->Wait(&flags, ×tampHns, byRef(sample)); if (FAILED(hr) || (flags & MF_SOURCE_READERF_ERROR) || (flags & MF_SOURCE_READERF_ENDOFSTREAM) || (flags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED)) { LOG("WMFReader::DecodeAudioData() ReadSample failed with hr=0x%x flags=0x%x", hr, flags); // End the stream. mAudioQueue.Finish(); return false; } if (!sample) { // Not enough data? Try again... return true; } RefPtr<IMFMediaBuffer> buffer; hr = sample->ConvertToContiguousBuffer(byRef(buffer)); NS_ENSURE_TRUE(SUCCEEDED(hr), false); BYTE* data = nullptr; // Note: *data will be owned by the IMFMediaBuffer, we don't need to free it. DWORD maxLength = 0, currentLength = 0; hr = buffer->Lock(&data, &maxLength, ¤tLength); NS_ENSURE_TRUE(SUCCEEDED(hr), false); uint32_t numFrames = currentLength / mAudioBytesPerSample / mAudioChannels; NS_ASSERTION(sizeof(AudioDataValue) == mAudioBytesPerSample, "Size calculation is wrong"); nsAutoArrayPtr<AudioDataValue> pcmSamples(new AudioDataValue[numFrames * mAudioChannels]); memcpy(pcmSamples.get(), data, currentLength); buffer->Unlock(); int64_t offset = mDecoder->GetResource()->Tell(); int64_t timestamp = HNsToUsecs(timestampHns); int64_t duration = GetSampleDuration(sample); mAudioQueue.Push(new AudioData(offset, timestamp, duration, numFrames, pcmSamples.forget(), mAudioChannels)); #ifdef LOG_SAMPLE_DECODE LOG("Decoded audio sample! timestamp=%lld duration=%lld currentLength=%u", timestamp, duration, currentLength); #endif return true; }
bool ImageClientSingle::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags) { AutoLockImage autoLock(aContainer); Image *image = autoLock.GetImage(); if (!image) { return false; } // Don't try to update to an invalid image. We return true because the caller // would attempt to recreate the ImageClient otherwise, and that isn't going // to help. if (!image->IsValid()) { return true; } if (mLastPaintedImageSerial == image->GetSerial()) { return true; } RefPtr<TextureClient> texture = image->GetTextureClient(this); AutoRemoveTexture autoRemoveTexture(this); if (texture != mFrontBuffer) { autoRemoveTexture.mTexture = mFrontBuffer; mFrontBuffer = nullptr; } if (!texture) { // Slow path, we should not be hitting it very often and if we do it means // we are using an Image class that is not backed by textureClient and we // should fix it. if (image->GetFormat() == ImageFormat::PLANAR_YCBCR) { PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(image); const PlanarYCbCrData* data = ycbcr->GetData(); if (!data) { return false; } texture = TextureClient::CreateForYCbCr(GetForwarder(), data->mYSize, data->mCbCrSize, data->mStereoMode, TextureFlags::DEFAULT | mTextureFlags ); if (!texture || !texture->Lock(OpenMode::OPEN_WRITE_ONLY)) { return false; } bool status = texture->AsTextureClientYCbCr()->UpdateYCbCr(*data); MOZ_ASSERT(status); texture->Unlock(); if (!status) { return false; } } else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE || image->GetFormat() == ImageFormat::EGLIMAGE) { gfx::IntSize size = image->GetSize(); if (image->GetFormat() == ImageFormat::EGLIMAGE) { EGLImageImage* typedImage = static_cast<EGLImageImage*>(image); texture = new EGLImageTextureClient(GetForwarder(), mTextureFlags, typedImage, size); #ifdef MOZ_WIDGET_ANDROID } else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE) { SurfaceTextureImage* typedImage = static_cast<SurfaceTextureImage*>(image); const SurfaceTextureImage::Data* data = typedImage->GetData(); texture = new SurfaceTextureClient(GetForwarder(), mTextureFlags, data->mSurfTex, size, data->mOriginPos); #endif } else { MOZ_ASSERT(false, "Bad ImageFormat."); } } else { RefPtr<gfx::SourceSurface> surface = image->GetAsSourceSurface(); MOZ_ASSERT(surface); texture = CreateTextureClientForDrawing(surface->GetFormat(), image->GetSize(), gfx::BackendType::NONE, mTextureFlags); if (!texture) { return false; } MOZ_ASSERT(texture->CanExposeDrawTarget()); if (!texture->Lock(OpenMode::OPEN_WRITE_ONLY)) { return false; } { // We must not keep a reference to the DrawTarget after it has been unlocked. DrawTarget* dt = texture->BorrowDrawTarget(); if (!dt) { gfxWarning() << "ImageClientSingle::UpdateImage failed in BorrowDrawTarget"; return false; } MOZ_ASSERT(surface.get()); dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint()); } texture->Unlock(); } } if (!texture || !AddTextureClient(texture)) { return false; } mFrontBuffer = texture; GetForwarder()->UseTexture(this, texture); UpdatePictureRect(image->GetPictureRect()); mLastPaintedImageSerial = image->GetSerial(); aContainer->NotifyPaintedImage(image); texture->SyncWithObject(GetForwarder()->GetSyncObject()); return true; }
SimpleTiledLayerTile SimpleTiledLayerBuffer::ValidateTile(SimpleTiledLayerTile aTile, const nsIntPoint& aTileOrigin, const nsIntRegion& aDirtyRegion) { PROFILER_LABEL("SimpleTiledLayerBuffer", "ValidateTile"); static gfx::IntSize kTileSize(TILEDLAYERBUFFER_TILE_SIZE, TILEDLAYERBUFFER_TILE_SIZE); gfx::SurfaceFormat tileFormat = gfxPlatform::GetPlatform()->Optimal2DFormatForContent(GetContentType()); // if this is true, we're using a separate buffer to do our drawing first bool doBufferedDrawing = true; bool fullPaint = false; RefPtr<TextureClient> textureClient = mManager->GetSimpleTileTexturePool(tileFormat)->GetTextureClientWithAutoRecycle(); if (!textureClient) { NS_WARNING("TextureClient allocation failed"); return SimpleTiledLayerTile(); } if (!textureClient->Lock(OPEN_WRITE)) { NS_WARNING("TextureClient lock failed"); return SimpleTiledLayerTile(); } TextureClientSurface *textureClientSurf = textureClient->AsTextureClientSurface(); if (!textureClientSurf) { doBufferedDrawing = false; } RefPtr<DrawTarget> drawTarget; nsRefPtr<gfxImageSurface> clientAsImageSurface; unsigned char *bufferData = nullptr; // these are set/updated differently based on doBufferedDrawing nsIntRect drawBounds; nsIntRegion drawRegion; nsIntRegion invalidateRegion; if (doBufferedDrawing) { // try to obtain the TextureClient as an ImageSurface, so that we can // access the pixels directly nsRefPtr<gfxASurface> asurf = textureClientSurf->GetAsSurface(); clientAsImageSurface = asurf ? asurf->GetAsImageSurface() : nullptr; if (clientAsImageSurface) { int32_t bufferStride = clientAsImageSurface->Stride(); if (!aTile.mCachedBuffer) { aTile.mCachedBuffer = SharedBuffer::Create(clientAsImageSurface->GetDataSize()); fullPaint = true; } bufferData = (unsigned char*) aTile.mCachedBuffer->Data(); drawTarget = gfxPlatform::GetPlatform()->CreateDrawTargetForData(bufferData, kTileSize, bufferStride, tileFormat); if (fullPaint) { drawBounds = nsIntRect(aTileOrigin.x, aTileOrigin.y, GetScaledTileLength(), GetScaledTileLength()); drawRegion = nsIntRegion(drawBounds); } else { drawBounds = aDirtyRegion.GetBounds(); drawRegion = nsIntRegion(drawBounds); if (GetContentType() == gfxContentType::COLOR_ALPHA) drawTarget->ClearRect(Rect(drawBounds.x - aTileOrigin.x, drawBounds.y - aTileOrigin.y, drawBounds.width, drawBounds.height)); } } else { // failed to obtain the client as an ImageSurface doBufferedDrawing = false; } } // this might get set above if we couldn't extract out a buffer if (!doBufferedDrawing) { drawTarget = textureClient->AsTextureClientDrawTarget()->GetAsDrawTarget(); fullPaint = true; drawBounds = nsIntRect(aTileOrigin.x, aTileOrigin.y, GetScaledTileLength(), GetScaledTileLength()); drawRegion = nsIntRegion(drawBounds); if (GetContentType() == gfxContentType::COLOR_ALPHA) drawTarget->ClearRect(Rect(0, 0, drawBounds.width, drawBounds.height)); } // do the drawing RefPtr<gfxContext> ctxt = new gfxContext(drawTarget); ctxt->Scale(mResolution, mResolution); ctxt->Translate(gfxPoint(-aTileOrigin.x, -aTileOrigin.y)); mCallback(mThebesLayer, ctxt, drawRegion, fullPaint ? DrawRegionClip::CLIP_NONE : DrawRegionClip::DRAW_SNAPPED, // XXX DRAW or DRAW_SNAPPED? invalidateRegion, mCallbackData); ctxt = nullptr; drawTarget = nullptr; if (doBufferedDrawing) { memcpy(clientAsImageSurface->Data(), bufferData, clientAsImageSurface->GetDataSize()); clientAsImageSurface = nullptr; bufferData = nullptr; } textureClient->Unlock(); if (!mCompositableClient->AddTextureClient(textureClient)) { NS_WARNING("Failed to add tile TextureClient [simple]"); return SimpleTiledLayerTile(); } // aTile.mCachedBuffer was set earlier aTile.mTileBuffer = textureClient; aTile.mManager = mManager; aTile.mLastUpdate = TimeStamp::Now(); return aTile; }
bool PersistentBufferProviderShared::SetForwarder(KnowsCompositor* aFwd) { MOZ_ASSERT(aFwd); if (!aFwd) { return false; } if (mFwd == aFwd) { // The forwarder should not change most of the time. return true; } if (IsActivityTracked()) { mFwd->GetActiveResourceTracker().RemoveObject(this); } if (mFwd->GetTextureForwarder() != aFwd->GetTextureForwarder() || mFwd->GetCompositorBackendType() != aFwd->GetCompositorBackendType()) { // We are going to be used with an different and/or incompatible forwarder. // This should be extremely rare. We have to copy the front buffer into a // texture that is compatible with the new forwarder. // Grab the current front buffer. RefPtr<TextureClient> prevTexture = GetTexture(mFront); // Get rid of everything else Destroy(); if (prevTexture) { RefPtr<TextureClient> newTexture = TextureClient::CreateForDrawing( aFwd, mFormat, mSize, BackendSelector::Canvas, TextureFlags::DEFAULT, TextureAllocationFlags::ALLOC_DEFAULT ); MOZ_ASSERT(newTexture); if (!newTexture) { return false; } // If we early-return in one of the following branches, we will // leave the buffer provider in an empty state, since we called // Destroy. Not ideal but at least we won't try to use it with a // an incompatible ipc channel. if (!newTexture->Lock(OpenMode::OPEN_WRITE)) { return false; } if (!prevTexture->Lock(OpenMode::OPEN_READ)) { newTexture->Unlock(); return false; } bool success = prevTexture->CopyToTextureClient(newTexture, nullptr, nullptr); prevTexture->Unlock(); newTexture->Unlock(); if (!success) { return false; } if (!mTextures.append(newTexture)) { return false; } mFront = Some<uint32_t>(mTextures.length() - 1); mBack = mFront; } } mFwd = aFwd; return true; }
TileClient ClientTiledLayerBuffer::ValidateTile(TileClient aTile, const nsIntPoint& aTileOrigin, const nsIntRegion& aDirtyRegion) { PROFILER_LABEL("ClientTiledLayerBuffer", "ValidateTile"); #ifdef GFX_TILEDLAYER_PREF_WARNINGS if (aDirtyRegion.IsComplex()) { printf_stderr("Complex region\n"); } #endif if (aTile.IsPlaceholderTile()) { aTile.SetLayerManager(mManager); } // Discard our front and backbuffers if our contents changed. In this case // the calling code will already have taken care of invalidating the entire // layer. if (HasFormatChanged()) { aTile.DiscardBackBuffer(); aTile.DiscardFrontBuffer(); } bool createdTextureClient = false; nsIntRegion offsetDirtyRegion = aDirtyRegion.MovedBy(-aTileOrigin); bool usingSinglePaintBuffer = !!mSinglePaintDrawTarget; RefPtr<TextureClient> backBuffer = aTile.GetBackBuffer(offsetDirtyRegion, mManager->GetTexturePool(gfxPlatform::GetPlatform()->Optimal2DFormatForContent(GetContentType())), &createdTextureClient, !usingSinglePaintBuffer); if (!backBuffer->Lock(OPEN_READ_WRITE)) { NS_WARNING("Failed to lock tile TextureClient for updating."); aTile.DiscardFrontBuffer(); return aTile; } // We must not keep a reference to the DrawTarget after it has been unlocked, // make sure these are null'd before unlocking as destruction of the context // may cause the target to be flushed. RefPtr<DrawTarget> drawTarget = backBuffer->AsTextureClientDrawTarget()->GetAsDrawTarget(); drawTarget->SetTransform(Matrix()); RefPtr<gfxContext> ctxt = new gfxContext(drawTarget); if (usingSinglePaintBuffer) { // XXX Perhaps we should just copy the bounding rectangle here? RefPtr<gfx::SourceSurface> source = mSinglePaintDrawTarget->Snapshot(); nsIntRegionRectIterator it(aDirtyRegion); for (const nsIntRect* dirtyRect = it.Next(); dirtyRect != nullptr; dirtyRect = it.Next()) { #ifdef GFX_TILEDLAYER_PREF_WARNINGS printf_stderr(" break into subdirtyRect %i, %i, %i, %i\n", dirtyRect->x, dirtyRect->y, dirtyRect->width, dirtyRect->height); #endif gfx::Rect drawRect(dirtyRect->x - aTileOrigin.x, dirtyRect->y - aTileOrigin.y, dirtyRect->width, dirtyRect->height); drawRect.Scale(mResolution); gfx::IntRect copyRect(NS_roundf((dirtyRect->x - mSinglePaintBufferOffset.x) * mResolution), NS_roundf((dirtyRect->y - mSinglePaintBufferOffset.y) * mResolution), drawRect.width, drawRect.height); gfx::IntPoint copyTarget(NS_roundf(drawRect.x), NS_roundf(drawRect.y)); drawTarget->CopySurface(source, copyRect, copyTarget); // Mark the newly updated area as invalid in the front buffer aTile.mInvalidFront.Or(aTile.mInvalidFront, nsIntRect(copyTarget.x, copyTarget.y, copyRect.width, copyRect.height)); } // The new buffer is now validated, remove the dirty region from it. aTile.mInvalidBack.Sub(nsIntRect(0, 0, TILEDLAYERBUFFER_TILE_SIZE, TILEDLAYERBUFFER_TILE_SIZE), offsetDirtyRegion); } else { // Area of the full tile... nsIntRegion tileRegion = nsIntRect(aTileOrigin.x, aTileOrigin.y, TILEDLAYERBUFFER_TILE_SIZE, TILEDLAYERBUFFER_TILE_SIZE); // Intersect this area with the portion that's dirty. tileRegion = tileRegion.Intersect(aDirtyRegion); // Move invalid areas into layer space. aTile.mInvalidFront.MoveBy(aTileOrigin); aTile.mInvalidBack.MoveBy(aTileOrigin); // Add the area that's going to be redrawn to the invalid area of the // front region. aTile.mInvalidFront.Or(aTile.mInvalidFront, tileRegion); // Add invalid areas of the backbuffer to the area to redraw. tileRegion.Or(tileRegion, aTile.mInvalidBack); // Move invalid areas back into tile space. aTile.mInvalidFront.MoveBy(-aTileOrigin); // This will be validated now. aTile.mInvalidBack.SetEmpty(); nsIntRect bounds = tileRegion.GetBounds(); bounds.ScaleRoundOut(mResolution, mResolution); bounds.MoveBy(-aTileOrigin); if (GetContentType() != gfxContentType::COLOR) { drawTarget->ClearRect(Rect(bounds.x, bounds.y, bounds.width, bounds.height)); } ctxt->NewPath(); ctxt->Clip(gfxRect(bounds.x, bounds.y, bounds.width, bounds.height)); ctxt->Scale(mResolution, mResolution); ctxt->Translate(gfxPoint(-aTileOrigin.x, -aTileOrigin.y)); mCallback(mThebesLayer, ctxt, tileRegion.GetBounds(), DrawRegionClip::CLIP_NONE, nsIntRegion(), mCallbackData); } #ifdef GFX_TILEDLAYER_DEBUG_OVERLAY DrawDebugOverlay(drawTarget, aTileOrigin.x * mResolution, aTileOrigin.y * mResolution, GetTileLength(), GetTileLength()); #endif ctxt = nullptr; drawTarget = nullptr; backBuffer->Unlock(); aTile.Flip(); if (createdTextureClient) { if (!mCompositableClient->AddTextureClient(backBuffer)) { NS_WARNING("Failed to add tile TextureClient."); aTile.DiscardFrontBuffer(); aTile.DiscardBackBuffer(); return aTile; } } // Note, we don't call UpdatedTexture. The Updated function is called manually // by the TiledContentHost before composition. if (backBuffer->HasInternalBuffer()) { // If our new buffer has an internal buffer, we don't want to keep another // TextureClient around unnecessarily, so discard the back-buffer. aTile.DiscardBackBuffer(); } return aTile; }
HRESULT WMFVideoMFTManager::CreateBasicVideoFrame(IMFSample* aSample, int64_t aStreamOffset, VideoData** aOutVideoData) { NS_ENSURE_TRUE(aSample, E_POINTER); NS_ENSURE_TRUE(aOutVideoData, E_POINTER); *aOutVideoData = nullptr; HRESULT hr; RefPtr<IMFMediaBuffer> buffer; // Must convert to contiguous buffer to use IMD2DBuffer interface. hr = aSample->ConvertToContiguousBuffer(byRef(buffer)); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); // Try and use the IMF2DBuffer interface if available, otherwise fallback // to the IMFMediaBuffer interface. Apparently IMF2DBuffer is more efficient, // but only some systems (Windows 8?) support it. BYTE* data = nullptr; LONG stride = 0; RefPtr<IMF2DBuffer> twoDBuffer; hr = buffer->QueryInterface(static_cast<IMF2DBuffer**>(byRef(twoDBuffer))); if (SUCCEEDED(hr)) { hr = twoDBuffer->Lock2D(&data, &stride); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); } else { hr = buffer->Lock(&data, nullptr, nullptr); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); stride = mVideoStride; } // YV12, planar format: [YYYY....][VVVV....][UUUU....] // i.e., Y, then V, then U. VideoData::YCbCrBuffer b; // Y (Y') plane b.mPlanes[0].mData = data; b.mPlanes[0].mStride = stride; b.mPlanes[0].mHeight = mVideoHeight; b.mPlanes[0].mWidth = mVideoWidth; b.mPlanes[0].mOffset = 0; b.mPlanes[0].mSkip = 0; // The V and U planes are stored 16-row-aligned, so we need to add padding // to the row heights to ensure the Y'CbCr planes are referenced properly. uint32_t padding = 0; if (mVideoHeight % 16 != 0) { padding = 16 - (mVideoHeight % 16); } uint32_t y_size = stride * (mVideoHeight + padding); uint32_t v_size = stride * (mVideoHeight + padding) / 4; uint32_t halfStride = (stride + 1) / 2; uint32_t halfHeight = (mVideoHeight + 1) / 2; uint32_t halfWidth = (mVideoWidth + 1) / 2; // U plane (Cb) b.mPlanes[1].mData = data + y_size + v_size; b.mPlanes[1].mStride = halfStride; b.mPlanes[1].mHeight = halfHeight; b.mPlanes[1].mWidth = halfWidth; b.mPlanes[1].mOffset = 0; b.mPlanes[1].mSkip = 0; // V plane (Cr) b.mPlanes[2].mData = data + y_size; b.mPlanes[2].mStride = halfStride; b.mPlanes[2].mHeight = halfHeight; b.mPlanes[2].mWidth = halfWidth; b.mPlanes[2].mOffset = 0; b.mPlanes[2].mSkip = 0; Microseconds pts = GetSampleTime(aSample); Microseconds duration = GetSampleDuration(aSample); nsRefPtr<VideoData> v = VideoData::Create(mVideoInfo, mImageContainer, aStreamOffset, std::max(0LL, pts), duration, b, false, -1, ToIntRect(mPictureRegion)); if (twoDBuffer) { twoDBuffer->Unlock2D(); } else { buffer->Unlock(); } v.forget(aOutVideoData); return S_OK; }
HRESULT WMFVideoMFTManager::CreateBasicVideoFrame(IMFSample* aSample, int64_t aStreamOffset, VideoData** aOutVideoData) { NS_ENSURE_TRUE(aSample, E_POINTER); NS_ENSURE_TRUE(aOutVideoData, E_POINTER); *aOutVideoData = nullptr; HRESULT hr; RefPtr<IMFMediaBuffer> buffer; // Must convert to contiguous buffer to use IMD2DBuffer interface. hr = aSample->ConvertToContiguousBuffer(getter_AddRefs(buffer)); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); // Try and use the IMF2DBuffer interface if available, otherwise fallback // to the IMFMediaBuffer interface. Apparently IMF2DBuffer is more efficient, // but only some systems (Windows 8?) support it. BYTE* data = nullptr; LONG stride = 0; RefPtr<IMF2DBuffer> twoDBuffer; hr = buffer->QueryInterface(static_cast<IMF2DBuffer**>(getter_AddRefs(twoDBuffer))); if (SUCCEEDED(hr)) { hr = twoDBuffer->Lock2D(&data, &stride); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); } else { hr = buffer->Lock(&data, nullptr, nullptr); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); stride = mVideoStride; } // YV12, planar format: [YYYY....][VVVV....][UUUU....] // i.e., Y, then V, then U. VideoData::YCbCrBuffer b; uint32_t videoWidth = mImageSize.width; uint32_t videoHeight = mImageSize.height; // Y (Y') plane b.mPlanes[0].mData = data; b.mPlanes[0].mStride = stride; b.mPlanes[0].mHeight = videoHeight; b.mPlanes[0].mWidth = videoWidth; b.mPlanes[0].mOffset = 0; b.mPlanes[0].mSkip = 0; // The V and U planes are stored 16-row-aligned, so we need to add padding // to the row heights to ensure the Y'CbCr planes are referenced properly. uint32_t padding = 0; if (videoHeight % 16 != 0) { padding = 16 - (videoHeight % 16); } uint32_t y_size = stride * (videoHeight + padding); uint32_t v_size = stride * (videoHeight + padding) / 4; uint32_t halfStride = (stride + 1) / 2; uint32_t halfHeight = (videoHeight + 1) / 2; uint32_t halfWidth = (videoWidth + 1) / 2; // U plane (Cb) b.mPlanes[1].mData = data + y_size + v_size; b.mPlanes[1].mStride = halfStride; b.mPlanes[1].mHeight = halfHeight; b.mPlanes[1].mWidth = halfWidth; b.mPlanes[1].mOffset = 0; b.mPlanes[1].mSkip = 0; // V plane (Cr) b.mPlanes[2].mData = data + y_size; b.mPlanes[2].mStride = halfStride; b.mPlanes[2].mHeight = halfHeight; b.mPlanes[2].mWidth = halfWidth; b.mPlanes[2].mOffset = 0; b.mPlanes[2].mSkip = 0; media::TimeUnit pts = GetSampleTime(aSample); NS_ENSURE_TRUE(pts.IsValid(), E_FAIL); media::TimeUnit duration = GetSampleDuration(aSample); NS_ENSURE_TRUE(duration.IsValid(), E_FAIL); RefPtr<layers::PlanarYCbCrImage> image = new IMFYCbCrImage(buffer, twoDBuffer); nsIntRect pictureRegion = mVideoInfo.ScaledImageRect(videoWidth, videoHeight); VideoData::SetVideoDataToImage(image, mVideoInfo, b, pictureRegion, false); RefPtr<VideoData> v = VideoData::CreateFromImage(mVideoInfo, mImageContainer, aStreamOffset, pts.ToMicroseconds(), duration.ToMicroseconds(), image.forget(), false, -1, pictureRegion); v.forget(aOutVideoData); return S_OK; }
HRESULT WMFAudioMFTManager::Output(int64_t aStreamOffset, nsRefPtr<MediaData>& aOutData) { aOutData = nullptr; RefPtr<IMFSample> sample; HRESULT hr; int typeChangeCount = 0; while (true) { hr = mDecoder->Output(&sample); if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { return hr; } if (hr == MF_E_TRANSFORM_STREAM_CHANGE) { hr = UpdateOutputType(); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); // Catch infinite loops, but some decoders perform at least 2 stream // changes on consecutive calls, so be permissive. // 100 is arbitrarily > 2. NS_ENSURE_TRUE(typeChangeCount < 100, MF_E_TRANSFORM_STREAM_CHANGE); ++typeChangeCount; continue; } break; } NS_ENSURE_TRUE(SUCCEEDED(hr), hr); RefPtr<IMFMediaBuffer> buffer; hr = sample->ConvertToContiguousBuffer(byRef(buffer)); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); BYTE* data = nullptr; // Note: *data will be owned by the IMFMediaBuffer, we don't need to free it. DWORD maxLength = 0, currentLength = 0; hr = buffer->Lock(&data, &maxLength, ¤tLength); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); // Sometimes when starting decoding, the AAC decoder gives us samples // with a negative timestamp. AAC does usually have preroll (or encoder // delay) encoded into its bitstream, but the amount encoded to the stream // is variable, and it not signalled in-bitstream. There is sometimes // signalling in the MP4 container what the preroll amount, but it's // inconsistent. It looks like WMF's AAC encoder may take this into // account, so strip off samples with a negative timestamp to get us // to a 0-timestamp start. This seems to maintain A/V sync, so we can run // with this until someone complains... // We calculate the timestamp and the duration based on the number of audio // frames we've already played. We don't trust the timestamp stored on the // IMFSample, as sometimes it's wrong, possibly due to buggy encoders? // If this sample block comes after a discontinuity (i.e. a gap or seek) // reset the frame counters, and capture the timestamp. Future timestamps // will be offset from this block's timestamp. UINT32 discontinuity = false; sample->GetUINT32(MFSampleExtension_Discontinuity, &discontinuity); if (mMustRecaptureAudioPosition || discontinuity) { // Update the output type, in case this segment has a different // rate. This also triggers on the first sample, which can have a // different rate than is advertised in the container, and sometimes we // don't get a MF_E_TRANSFORM_STREAM_CHANGE when the rate changes. hr = UpdateOutputType(); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); mAudioFrameSum = 0; LONGLONG timestampHns = 0; hr = sample->GetSampleTime(×tampHns); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); mAudioTimeOffset = media::TimeUnit::FromMicroseconds(timestampHns / 10); mMustRecaptureAudioPosition = false; } // We can assume PCM 16 output. int32_t numSamples = currentLength / 2; int32_t numFrames = numSamples / mAudioChannels; MOZ_ASSERT(numFrames >= 0); MOZ_ASSERT(numSamples >= 0); if (numFrames == 0) { // All data from this chunk stripped, loop back and try to output the next // frame, if possible. return S_OK; } nsAutoArrayPtr<AudioDataValue> audioData(new AudioDataValue[numSamples]); int16_t* pcm = (int16_t*)data; for (int32_t i = 0; i < numSamples; ++i) { audioData[i] = AudioSampleToFloat(pcm[i]); } buffer->Unlock(); media::TimeUnit timestamp = mAudioTimeOffset + FramesToTimeUnit(mAudioFrameSum, mAudioRate); NS_ENSURE_TRUE(timestamp.IsValid(), E_FAIL); mAudioFrameSum += numFrames; media::TimeUnit duration = FramesToTimeUnit(numFrames, mAudioRate); NS_ENSURE_TRUE(duration.IsValid(), E_FAIL); aOutData = new AudioData(aStreamOffset, timestamp.ToMicroseconds(), duration.ToMicroseconds(), numFrames, audioData.forget(), mAudioChannels, mAudioRate); #ifdef LOG_SAMPLE_DECODE LOG("Decoded audio sample! timestamp=%lld duration=%lld currentLength=%u", timestamp.ToMicroseconds(), duration.ToMicroseconds(), currentLength); #endif return S_OK; }
NS_IMETHOD Run() override { AssertIsOnMainThread(); MutexAutoLock lock(mPromiseProxy->Lock()); if (mPromiseProxy->CleanedUp()) { return NS_OK; } nsCOMPtr<nsPIDOMWindowOuter> window; nsresult rv = OpenWindow(getter_AddRefs(window)); if (NS_SUCCEEDED(rv)) { MOZ_ASSERT(window); WorkerPrivate* workerPrivate = mPromiseProxy->GetWorkerPrivate(); MOZ_ASSERT(workerPrivate); WorkerPrivate::LocationInfo& info = workerPrivate->GetLocationInfo(); nsCOMPtr<nsIURI> baseURI; nsresult rv = NS_NewURI(getter_AddRefs(baseURI), info.mHref); if (NS_WARN_IF(NS_FAILED(rv))) { return NS_ERROR_FAILURE; } nsCOMPtr<nsIDocShell> docShell = window->GetDocShell(); nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell); if (!webProgress) { return NS_ERROR_FAILURE; } RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); MOZ_ASSERT(swm); nsCOMPtr<nsIPrincipal> principal = workerPrivate->GetPrincipal(); MOZ_ASSERT(principal); RefPtr<ServiceWorkerRegistrationInfo> registration = swm->GetRegistration(principal, NS_ConvertUTF16toUTF8(mScope)); if (NS_WARN_IF(!registration)) { return NS_ERROR_FAILURE; } RefPtr<ServiceWorkerInfo> serviceWorkerInfo = registration->GetServiceWorkerInfoById(workerPrivate->ServiceWorkerID()); if (NS_WARN_IF(!serviceWorkerInfo)) { return NS_ERROR_FAILURE; } nsCOMPtr<nsIWebProgressListener> listener = new WebProgressListener(mPromiseProxy, serviceWorkerInfo->WorkerPrivate(), window, baseURI); rv = webProgress->AddProgressListener(listener, nsIWebProgress::NOTIFY_STATE_DOCUMENT); MOZ_ASSERT(NS_SUCCEEDED(rv)); return NS_OK; } RefPtr<ResolveOpenWindowRunnable> resolveRunnable = new ResolveOpenWindowRunnable(mPromiseProxy, nullptr, rv); NS_WARN_IF(!resolveRunnable->Dispatch()); return NS_OK; }
TextureClient* CairoImage::GetTextureClient(CompositableClient *aClient) { if (!aClient) { return nullptr; } CompositableForwarder* forwarder = aClient->GetForwarder(); RefPtr<TextureClient> textureClient = mTextureClients.Get(forwarder->GetSerial()); if (textureClient) { return textureClient; } RefPtr<SourceSurface> surface = GetAsSourceSurface(); MOZ_ASSERT(surface); if (!surface) { return nullptr; } // XXX windows' TextureClients do not hold ISurfaceAllocator, // recycler does not work on windows. #ifndef XP_WIN // XXX only gonk ensure when TextureClient is recycled, // TextureHost is not used by CompositableHost. #ifdef MOZ_WIDGET_GONK RefPtr<TextureClientRecycleAllocator> recycler = aClient->GetTextureClientRecycler(); if (recycler) { textureClient = recycler->CreateOrRecycleForDrawing(surface->GetFormat(), surface->GetSize(), gfx::BackendType::NONE, aClient->GetTextureFlags()); } #endif #endif if (!textureClient) { // gfx::BackendType::NONE means default to content backend textureClient = aClient->CreateTextureClientForDrawing(surface->GetFormat(), surface->GetSize(), gfx::BackendType::NONE, TextureFlags::DEFAULT); } if (!textureClient) { return nullptr; } MOZ_ASSERT(textureClient->CanExposeDrawTarget()); if (!textureClient->Lock(OpenMode::OPEN_WRITE_ONLY)) { return nullptr; } TextureClientAutoUnlock autoUnolck(textureClient); { // We must not keep a reference to the DrawTarget after it has been unlocked. DrawTarget* dt = textureClient->BorrowDrawTarget(); if (!dt) { return nullptr; } dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint()); } mTextureClients.Put(forwarder->GetSerial(), textureClient); return textureClient; }
SimpleTiledLayerTile SimpleTiledLayerBuffer::ValidateTile(SimpleTiledLayerTile aTile, const nsIntPoint& aTileOrigin, const nsIntRegion& aDirtyRegion) { PROFILER_LABEL("SimpleTiledLayerBuffer", "ValidateTile"); static gfx::IntSize kTileSize(gfxPrefs::LayersTileWidth(), gfxPrefs::LayersTileHeight()); gfx::SurfaceFormat tileFormat = gfxPlatform::GetPlatform()->Optimal2DFormatForContent(GetContentType()); // if this is true, we're using a separate buffer to do our drawing first bool doBufferedDrawing = true; bool fullPaint = false; RefPtr<TextureClient> textureClient = mManager->GetSimpleTileTexturePool(tileFormat)->GetTextureClientWithAutoRecycle(); if (!textureClient) { NS_WARNING("TextureClient allocation failed"); return SimpleTiledLayerTile(); } if (!textureClient->Lock(OPEN_READ_WRITE)) { NS_WARNING("TextureClient lock failed"); return SimpleTiledLayerTile(); } if (!textureClient->CanExposeDrawTarget()) { doBufferedDrawing = false; } RefPtr<DrawTarget> drawTarget; unsigned char *bufferData = nullptr; // these are set/updated differently based on doBufferedDrawing nsIntRect drawBounds; nsIntRegion drawRegion; nsIntRegion invalidateRegion; RefPtr<DrawTarget> srcDT; uint8_t* srcData = nullptr; int32_t srcStride = 0; gfx::IntSize srcSize; gfx::SurfaceFormat srcFormat = gfx::SurfaceFormat::UNKNOWN; if (doBufferedDrawing) { // try to directly access the pixels of the TextureClient srcDT = textureClient->GetAsDrawTarget(); if (srcDT->LockBits(&srcData, &srcSize, &srcStride, &srcFormat)) { if (!aTile.mCachedBuffer) { aTile.mCachedBuffer = SharedBuffer::Create(srcStride * srcSize.height); fullPaint = true; } bufferData = (unsigned char*) aTile.mCachedBuffer->Data(); drawTarget = gfxPlatform::GetPlatform()->CreateDrawTargetForData(bufferData, kTileSize, srcStride, tileFormat); if (fullPaint) { drawBounds = nsIntRect(aTileOrigin.x, aTileOrigin.y, GetScaledTileSize().width, GetScaledTileSize().height); drawRegion = nsIntRegion(drawBounds); } else { drawBounds = aDirtyRegion.GetBounds(); drawRegion = nsIntRegion(drawBounds); if (GetContentType() == gfxContentType::COLOR_ALPHA) drawTarget->ClearRect(Rect(drawBounds.x - aTileOrigin.x, drawBounds.y - aTileOrigin.y, drawBounds.width, drawBounds.height)); } } else { // failed to obtain the client as an ImageSurface doBufferedDrawing = false; } } // this might get set above if we couldn't extract out a buffer if (!doBufferedDrawing) { drawTarget = textureClient->GetAsDrawTarget(); fullPaint = true; drawBounds = nsIntRect(aTileOrigin.x, aTileOrigin.y, GetScaledTileSize().width, GetScaledTileSize().height); drawRegion = nsIntRegion(drawBounds); if (GetContentType() == gfxContentType::COLOR_ALPHA) drawTarget->ClearRect(Rect(0, 0, drawBounds.width, drawBounds.height)); } // do the drawing RefPtr<gfxContext> ctxt = new gfxContext(drawTarget); ctxt->Scale(mResolution, mResolution); ctxt->Translate(gfxPoint(-aTileOrigin.x, -aTileOrigin.y)); mCallback(mThebesLayer, ctxt, drawRegion, fullPaint ? DrawRegionClip::CLIP_NONE : DrawRegionClip::DRAW_SNAPPED, // XXX DRAW or DRAW_SNAPPED? invalidateRegion, mCallbackData); ctxt = nullptr; if (doBufferedDrawing) { memcpy(srcData, bufferData, srcSize.height * srcStride); bufferData = nullptr; srcDT->ReleaseBits(srcData); srcDT = nullptr; } drawTarget = nullptr; textureClient->Unlock(); if (!mCompositableClient->AddTextureClient(textureClient)) { NS_WARNING("Failed to add tile TextureClient [simple]"); return SimpleTiledLayerTile(); } // aTile.mCachedBuffer was set earlier aTile.mTileBuffer = textureClient; aTile.mManager = mManager; aTile.mLastUpdate = TimeStamp::Now(); return aTile; }
HRESULT WMFAudioMFTManager::Output(int64_t aStreamOffset, nsAutoPtr<MediaData>& aOutData) { aOutData = nullptr; RefPtr<IMFSample> sample; HRESULT hr; while (true) { hr = mDecoder->Output(&sample); if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT) { return hr; } if (hr == MF_E_TRANSFORM_STREAM_CHANGE) { hr = UpdateOutputType(); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); continue; } break; } NS_ENSURE_TRUE(SUCCEEDED(hr), hr); RefPtr<IMFMediaBuffer> buffer; hr = sample->ConvertToContiguousBuffer(byRef(buffer)); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); BYTE* data = nullptr; // Note: *data will be owned by the IMFMediaBuffer, we don't need to free it. DWORD maxLength = 0, currentLength = 0; hr = buffer->Lock(&data, &maxLength, ¤tLength); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); // Sometimes when starting decoding, the AAC decoder gives us samples // with a negative timestamp. AAC does usually have preroll (or encoder // delay) encoded into its bitstream, but the amount encoded to the stream // is variable, and it not signalled in-bitstream. There is sometimes // signalling in the MP4 container what the preroll amount, but it's // inconsistent. It looks like WMF's AAC encoder may take this into // account, so strip off samples with a negative timestamp to get us // to a 0-timestamp start. This seems to maintain A/V sync, so we can run // with this until someone complains... // We calculate the timestamp and the duration based on the number of audio // frames we've already played. We don't trust the timestamp stored on the // IMFSample, as sometimes it's wrong, possibly due to buggy encoders? // If this sample block comes after a discontinuity (i.e. a gap or seek) // reset the frame counters, and capture the timestamp. Future timestamps // will be offset from this block's timestamp. UINT32 discontinuity = false; int32_t numFramesToStrip = 0; sample->GetUINT32(MFSampleExtension_Discontinuity, &discontinuity); if (mMustRecaptureAudioPosition || discontinuity) { // Update the output type, in case this segment has a different // rate. This also triggers on the first sample, which can have a // different rate than is advertised in the container, and sometimes we // don't get a MF_E_TRANSFORM_STREAM_CHANGE when the rate changes. hr = UpdateOutputType(); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); mAudioFrameSum = 0; LONGLONG timestampHns = 0; hr = sample->GetSampleTime(×tampHns); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); hr = HNsToFrames(timestampHns, mAudioRate, &mAudioFrameOffset); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); if (mAudioFrameOffset < 0) { // First sample has a negative timestamp. Strip off the samples until // we reach positive territory. numFramesToStrip = -mAudioFrameOffset; mAudioFrameOffset = 0; } mMustRecaptureAudioPosition = false; } MOZ_ASSERT(numFramesToStrip >= 0); int32_t numSamples = currentLength / mAudioBytesPerSample; int32_t numFrames = numSamples / mAudioChannels; int32_t offset = std::min<int32_t>(numFramesToStrip, numFrames); numFrames -= offset; numSamples -= offset * mAudioChannels; MOZ_ASSERT(numFrames >= 0); MOZ_ASSERT(numSamples >= 0); if (numFrames == 0) { // All data from this chunk stripped, loop back and try to output the next // frame, if possible. return S_OK; } nsAutoArrayPtr<AudioDataValue> audioData(new AudioDataValue[numSamples]); // Just assume PCM output for now... MOZ_ASSERT(mAudioBytesPerSample == 2); int16_t* pcm = ((int16_t*)data) + (offset * mAudioChannels); MOZ_ASSERT(pcm >= (int16_t*)data); MOZ_ASSERT(pcm <= (int16_t*)(data + currentLength)); MOZ_ASSERT(pcm+numSamples <= (int16_t*)(data + currentLength)); for (int32_t i = 0; i < numSamples; ++i) { audioData[i] = AudioSampleToFloat(pcm[i]); } buffer->Unlock(); int64_t timestamp; hr = FramesToUsecs(mAudioFrameOffset + mAudioFrameSum, mAudioRate, ×tamp); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); mAudioFrameSum += numFrames; int64_t duration; hr = FramesToUsecs(numFrames, mAudioRate, &duration); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); aOutData = new AudioData(aStreamOffset, timestamp, duration, numFrames, audioData.forget(), mAudioChannels, mAudioRate); #ifdef LOG_SAMPLE_DECODE LOG("Decoded audio sample! timestamp=%lld duration=%lld currentLength=%u", timestamp, duration, currentLength); #endif return S_OK; }
bool WMFReader::DecodeAudioData() { MOZ_ASSERT(OnTaskQueue()); HRESULT hr; hr = mSourceReader->ReadSample(MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, // control flags 0, // read stream index nullptr, nullptr, nullptr); if (FAILED(hr)) { DECODER_LOG("WMFReader::DecodeAudioData() ReadSample failed with hr=0x%x", hr); // End the stream. return false; } DWORD flags = 0; LONGLONG timestampHns = 0; RefPtr<IMFSample> sample; hr = mSourceReaderCallback->Wait(&flags, ×tampHns, byRef(sample)); if (FAILED(hr) || (flags & MF_SOURCE_READERF_ERROR) || (flags & MF_SOURCE_READERF_ENDOFSTREAM) || (flags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED)) { DECODER_LOG("WMFReader::DecodeAudioData() ReadSample failed with hr=0x%x flags=0x%x", hr, flags); // End the stream. return false; } if (!sample) { // Not enough data? Try again... return true; } RefPtr<IMFMediaBuffer> buffer; hr = sample->ConvertToContiguousBuffer(byRef(buffer)); NS_ENSURE_TRUE(SUCCEEDED(hr), false); BYTE* data = nullptr; // Note: *data will be owned by the IMFMediaBuffer, we don't need to free it. DWORD maxLength = 0, currentLength = 0; hr = buffer->Lock(&data, &maxLength, ¤tLength); NS_ENSURE_TRUE(SUCCEEDED(hr), false); uint32_t numFrames = currentLength / mAudioBytesPerSample / mAudioChannels; NS_ASSERTION(sizeof(AudioDataValue) == mAudioBytesPerSample, "Size calculation is wrong"); nsAutoArrayPtr<AudioDataValue> pcmSamples(new AudioDataValue[numFrames * mAudioChannels]); memcpy(pcmSamples.get(), data, currentLength); buffer->Unlock(); // We calculate the timestamp and the duration based on the number of audio // frames we've already played. We don't trust the timestamp stored on the // IMFSample, as sometimes it's wrong, possibly due to buggy encoders? // If this sample block comes after a discontinuity (i.e. a gap or seek) // reset the frame counters, and capture the timestamp. Future timestamps // will be offset from this block's timestamp. UINT32 discontinuity = false; sample->GetUINT32(MFSampleExtension_Discontinuity, &discontinuity); if (mMustRecaptureAudioPosition || discontinuity) { mAudioFrameSum = 0; hr = HNsToFrames(timestampHns, mAudioRate, &mAudioFrameOffset); NS_ENSURE_TRUE(SUCCEEDED(hr), false); mMustRecaptureAudioPosition = false; } int64_t timestamp; hr = FramesToUsecs(mAudioFrameOffset + mAudioFrameSum, mAudioRate, ×tamp); NS_ENSURE_TRUE(SUCCEEDED(hr), false); mAudioFrameSum += numFrames; int64_t duration; hr = FramesToUsecs(numFrames, mAudioRate, &duration); NS_ENSURE_TRUE(SUCCEEDED(hr), false); mAudioQueue.Push(new AudioData(mDecoder->GetResource()->Tell(), timestamp, duration, numFrames, pcmSamples.forget(), mAudioChannels, mAudioRate)); #ifdef LOG_SAMPLE_DECODE DECODER_LOG("Decoded audio sample! timestamp=%lld duration=%lld currentLength=%u", timestamp, duration, currentLength); #endif return true; }
static TemporaryRef<TextureClient> TexClientFromReadback(SharedSurface* src, ISurfaceAllocator* allocator, TextureFlags baseFlags, LayersBackend layersBackend) { auto backendType = gfx::BackendType::CAIRO; TexClientFactory factory(allocator, src->mHasAlpha, src->mSize, backendType, baseFlags, layersBackend); RefPtr<BufferTextureClient> texClient; { gl::ScopedReadbackFB autoReadback(src); // We have a source FB, now we need a format. GLenum destFormat = LOCAL_GL_BGRA; GLenum destType = LOCAL_GL_UNSIGNED_BYTE; GLenum readFormat; GLenum readType; // We actually don't care if they match, since we can handle // any read{Format,Type} we get. auto gl = src->mGL; GetActualReadFormats(gl, destFormat, destType, &readFormat, &readType); MOZ_ASSERT(readFormat == LOCAL_GL_RGBA || readFormat == LOCAL_GL_BGRA); MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_BYTE); // With a format and type, we can create texClient. if (readFormat == LOCAL_GL_BGRA && readType == LOCAL_GL_UNSIGNED_BYTE) { // 0xAARRGGBB // In Lendian: [BB, GG, RR, AA] texClient = factory.CreateB8G8R8AX8(); } else if (readFormat == LOCAL_GL_RGBA && readType == LOCAL_GL_UNSIGNED_BYTE) { // [RR, GG, BB, AA] texClient = factory.CreateR8G8B8AX8(); } else { MOZ_CRASH("Bad `read{Format,Type}`."); } MOZ_ASSERT(texClient); if (!texClient) return nullptr; // With a texClient, we can lock for writing. MOZ_ALWAYS_TRUE( texClient->Lock(OpenMode::OPEN_WRITE) ); uint8_t* lockedBytes = texClient->GetLockedData(); // ReadPixels from the current FB into lockedBits. auto width = src->mSize.width; auto height = src->mSize.height; { ScopedPackAlignment autoAlign(gl, 4); gl->raw_fReadPixels(0, 0, width, height, readFormat, readType, lockedBytes); } // RB_SWAPPED doesn't work with D3D11. (bug 1051010) // RB_SWAPPED doesn't work with Basic. (bug ???????) // RB_SWAPPED doesn't work with D3D9. (bug ???????) bool layersNeedsManualSwap = layersBackend == LayersBackend::LAYERS_BASIC || layersBackend == LayersBackend::LAYERS_D3D9 || layersBackend == LayersBackend::LAYERS_D3D11; if (texClient->HasFlags(TextureFlags::RB_SWAPPED) && layersNeedsManualSwap) { size_t pixels = width * height; uint8_t* itr = lockedBytes; for (size_t i = 0; i < pixels; i++) { SwapRB_R8G8B8A8(itr); itr += 4; } texClient->RemoveFlags(TextureFlags::RB_SWAPPED); } texClient->Unlock(); } return texClient.forget(); }
bool ImageClientSingle::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags) { AutoTArray<ImageContainer::OwningImage,4> images; uint32_t generationCounter; aContainer->GetCurrentImages(&images, &generationCounter); if (mLastUpdateGenerationCounter == generationCounter) { return true; } mLastUpdateGenerationCounter = generationCounter; for (int32_t i = images.Length() - 1; i >= 0; --i) { if (!images[i].mImage->IsValid()) { // Don't try to update to an invalid image. images.RemoveElementAt(i); } } if (images.IsEmpty()) { // This can happen if a ClearAllImages raced with SetCurrentImages from // another thread and ClearImagesFromImageBridge ran after the // SetCurrentImages call but before UpdateImageClientNow. // This can also happen if all images in the list are invalid. // We return true because the caller would attempt to recreate the // ImageClient otherwise, and that isn't going to help. return true; } nsTArray<Buffer> newBuffers; AutoTArray<CompositableForwarder::TimedTextureClient,4> textures; for (auto& img : images) { Image* image = img.mImage; #ifdef MOZ_WIDGET_GONK if (image->GetFormat() == ImageFormat::OVERLAY_IMAGE) { OverlayImage* overlayImage = static_cast<OverlayImage*>(image); OverlaySource source; if (overlayImage->GetSidebandStream().IsValid()) { // Duplicate GonkNativeHandle::NhObj for ipc, // since ParamTraits<GonkNativeHandle>::Write() absorbs native_handle_t. RefPtr<GonkNativeHandle::NhObj> nhObj = overlayImage->GetSidebandStream().GetDupNhObj(); GonkNativeHandle handle(nhObj); if (!handle.IsValid()) { gfxWarning() << "ImageClientSingle::UpdateImage failed in GetDupNhObj"; return false; } source.handle() = OverlayHandle(handle); } else { source.handle() = OverlayHandle(overlayImage->GetOverlayId()); } source.size() = overlayImage->GetSize(); GetForwarder()->UseOverlaySource(this, source, image->GetPictureRect()); continue; } #endif RefPtr<TextureClient> texture = image->GetTextureClient(this); const bool hasTextureClient = !!texture; for (int32_t i = mBuffers.Length() - 1; i >= 0; --i) { if (mBuffers[i].mImageSerial == image->GetSerial()) { if (hasTextureClient) { MOZ_ASSERT(image->GetTextureClient(this) == mBuffers[i].mTextureClient); } else { texture = mBuffers[i].mTextureClient; } // Remove this element from mBuffers so mBuffers only contains // images that aren't present in 'images' mBuffers.RemoveElementAt(i); } } if (!texture) { // Slow path, we should not be hitting it very often and if we do it means // we are using an Image class that is not backed by textureClient and we // should fix it. if (image->GetFormat() == ImageFormat::PLANAR_YCBCR) { PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(image); const PlanarYCbCrData* data = ycbcr->GetData(); if (!data) { return false; } texture = TextureClient::CreateForYCbCr(GetForwarder(), data->mYSize, data->mCbCrSize, data->mStereoMode, TextureFlags::DEFAULT | mTextureFlags ); if (!texture) { return false; } TextureClientAutoLock autoLock(texture, OpenMode::OPEN_WRITE_ONLY); if (!autoLock.Succeeded()) { return false; } bool status = UpdateYCbCrTextureClient(texture, *data); MOZ_ASSERT(status); if (!status) { return false; } } else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE || image->GetFormat() == ImageFormat::EGLIMAGE) { gfx::IntSize size = image->GetSize(); if (image->GetFormat() == ImageFormat::EGLIMAGE) { EGLImageImage* typedImage = image->AsEGLImageImage(); texture = EGLImageTextureData::CreateTextureClient( typedImage, size, GetForwarder(), mTextureFlags); #ifdef MOZ_WIDGET_ANDROID } else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE) { SurfaceTextureImage* typedImage = image->AsSurfaceTextureImage(); texture = AndroidSurfaceTextureData::CreateTextureClient( typedImage->GetSurfaceTexture(), size, typedImage->GetOriginPos(), GetForwarder(), mTextureFlags ); #endif } else { MOZ_ASSERT(false, "Bad ImageFormat."); } } else { RefPtr<gfx::SourceSurface> surface = image->GetAsSourceSurface(); MOZ_ASSERT(surface); texture = CreateTextureClientForDrawing(surface->GetFormat(), image->GetSize(), BackendSelector::Content, mTextureFlags); if (!texture) { return false; } MOZ_ASSERT(texture->CanExposeDrawTarget()); if (!texture->Lock(OpenMode::OPEN_WRITE_ONLY)) { return false; } { // We must not keep a reference to the DrawTarget after it has been unlocked. DrawTarget* dt = texture->BorrowDrawTarget(); if (!dt) { gfxWarning() << "ImageClientSingle::UpdateImage failed in BorrowDrawTarget"; return false; } MOZ_ASSERT(surface.get()); dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint()); } texture->Unlock(); } } if (!texture || !AddTextureClient(texture)) { return false; } CompositableForwarder::TimedTextureClient* t = textures.AppendElement(); t->mTextureClient = texture; t->mTimeStamp = img.mTimeStamp; t->mPictureRect = image->GetPictureRect(); t->mFrameID = img.mFrameID; t->mProducerID = img.mProducerID; Buffer* newBuf = newBuffers.AppendElement(); newBuf->mImageSerial = image->GetSerial(); newBuf->mTextureClient = texture; texture->SyncWithObject(GetForwarder()->GetSyncObject()); } GetForwarder()->UseTextures(this, textures); for (auto& b : mBuffers) { RemoveTexture(b.mTextureClient); } mBuffers.SwapElements(newBuffers); return true; }
NS_IMETHOD Run() override { AssertIsOnMainThread(); MutexAutoLock lock(mPromiseProxy->Lock()); if (mPromiseProxy->CleanedUp()) { return NS_OK; } #ifdef MOZ_WIDGET_ANDROID // This fires an intent that will start launching Fennec and foreground it, // if necessary. java::GeckoAppShell::OpenWindowForNotification(); #endif nsCOMPtr<nsPIDOMWindowOuter> window; nsresult rv = OpenWindow(getter_AddRefs(window)); if (NS_SUCCEEDED(rv)) { MOZ_ASSERT(window); rv = nsContentUtils::DispatchFocusChromeEvent(window); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } WorkerPrivate* workerPrivate = mPromiseProxy->GetWorkerPrivate(); MOZ_ASSERT(workerPrivate); WorkerPrivate::LocationInfo& info = workerPrivate->GetLocationInfo(); nsCOMPtr<nsIURI> baseURI; nsresult rv = NS_NewURI(getter_AddRefs(baseURI), info.mHref); if (NS_WARN_IF(NS_FAILED(rv))) { return NS_ERROR_FAILURE; } nsCOMPtr<nsIDocShell> docShell = window->GetDocShell(); nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell); if (!webProgress) { return NS_ERROR_FAILURE; } RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); MOZ_ASSERT(swm); nsCOMPtr<nsIPrincipal> principal = workerPrivate->GetPrincipal(); MOZ_ASSERT(principal); RefPtr<ServiceWorkerRegistrationInfo> registration = swm->GetRegistration(principal, NS_ConvertUTF16toUTF8(mScope)); if (NS_WARN_IF(!registration)) { return NS_ERROR_FAILURE; } RefPtr<ServiceWorkerInfo> serviceWorkerInfo = registration->GetServiceWorkerInfoById(workerPrivate->ServiceWorkerID()); if (NS_WARN_IF(!serviceWorkerInfo)) { return NS_ERROR_FAILURE; } nsCOMPtr<nsIWebProgressListener> listener = new WebProgressListener(mPromiseProxy, serviceWorkerInfo->WorkerPrivate(), window, baseURI); rv = webProgress->AddProgressListener(listener, nsIWebProgress::NOTIFY_STATE_DOCUMENT); MOZ_ASSERT(NS_SUCCEEDED(rv)); return NS_OK; } #ifdef MOZ_WIDGET_ANDROID else if (rv == NS_ERROR_NOT_AVAILABLE) { // We couldn't get a browser window, so Fennec must not be running. // Send an Intent to launch Fennec and wait for "BrowserChrome:Ready" // to try opening a window again. nsCOMPtr<nsIObserverService> os = services::GetObserverService(); NS_ENSURE_STATE(os); WorkerPrivate* workerPrivate = mPromiseProxy->GetWorkerPrivate(); MOZ_ASSERT(workerPrivate); RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance(); MOZ_ASSERT(swm); nsCOMPtr<nsIPrincipal> principal = workerPrivate->GetPrincipal(); MOZ_ASSERT(principal); RefPtr<ServiceWorkerRegistrationInfo> registration = swm->GetRegistration(principal, NS_ConvertUTF16toUTF8(mScope)); if (NS_WARN_IF(!registration)) { return NS_ERROR_FAILURE; } RefPtr<ServiceWorkerInfo> serviceWorkerInfo = registration->GetServiceWorkerInfoById(workerPrivate->ServiceWorkerID()); if (NS_WARN_IF(!serviceWorkerInfo)) { return NS_ERROR_FAILURE; } os->AddObserver(static_cast<nsIObserver*>(serviceWorkerInfo->WorkerPrivate()), "BrowserChrome:Ready", true); serviceWorkerInfo->WorkerPrivate()->AddPendingWindow(this); return NS_OK; } #endif RefPtr<ResolveOpenWindowRunnable> resolveRunnable = new ResolveOpenWindowRunnable(mPromiseProxy, nullptr, rv); Unused << NS_WARN_IF(!resolveRunnable->Dispatch()); return NS_OK; }