bool BufferTextureData::UpdateFromSurface(gfx::SourceSurface* aSurface) { if (mDescriptor.type() != BufferDescriptor::TRGBDescriptor) { return false; } const RGBDescriptor& rgb = mDescriptor.get_RGBDescriptor(); uint32_t stride = ImageDataSerializer::GetRGBStride(rgb); RefPtr<gfx::DataSourceSurface> surface = gfx::Factory::CreateWrappingDataSourceSurface(GetBuffer(), stride, rgb.size(), rgb.format()); if (!surface) { gfxCriticalError() << "Failed to get serializer as surface!"; return false; } RefPtr<gfx::DataSourceSurface> srcSurf = aSurface->GetDataSurface(); if (!srcSurf) { gfxCriticalError() << "Failed to GetDataSurface in UpdateFromSurface (BT)."; return false; } if (surface->GetSize() != srcSurf->GetSize() || surface->GetFormat() != srcSurf->GetFormat()) { gfxCriticalError() << "Attempt to update texture client from a surface with a different size or format (BT)! This: " << surface->GetSize() << " " << surface->GetFormat() << " Other: " << aSurface->GetSize() << " " << aSurface->GetFormat(); return false; } gfx::DataSourceSurface::MappedSurface sourceMap; gfx::DataSourceSurface::MappedSurface destMap; if (!srcSurf->Map(gfx::DataSourceSurface::READ, &sourceMap)) { gfxCriticalError() << "Failed to map source surface for UpdateFromSurface (BT)."; return false; } if (!surface->Map(gfx::DataSourceSurface::WRITE, &destMap)) { srcSurf->Unmap(); gfxCriticalError() << "Failed to map destination surface for UpdateFromSurface."; return false; } for (int y = 0; y < srcSurf->GetSize().height; y++) { memcpy(destMap.mData + destMap.mStride * y, sourceMap.mData + sourceMap.mStride * y, srcSurf->GetSize().width * BytesPerPixel(srcSurf->GetFormat())); } srcSurf->Unmap(); surface->Unmap(); return true; }
static already_AddRefed<layers::Image> CreateImageFromRawData(const gfx::IntSize& aSize, uint32_t aStride, gfx::SurfaceFormat aFormat, uint8_t* aBuffer, uint32_t aBufferLength, const Maybe<IntRect>& aCropRect) { MOZ_ASSERT(NS_IsMainThread()); // Copy and crop the source buffer into a SourceSurface. RefPtr<SourceSurface> rgbaSurface = CreateSurfaceFromRawData(aSize, aStride, aFormat, aBuffer, aBufferLength, aCropRect); if (NS_WARN_IF(!rgbaSurface)) { return nullptr; } // Convert RGBA to BGRA RefPtr<DataSourceSurface> rgbaDataSurface = rgbaSurface->GetDataSurface(); RefPtr<DataSourceSurface> bgraDataSurface = Factory::CreateDataSourceSurfaceWithStride(rgbaDataSurface->GetSize(), SurfaceFormat::B8G8R8A8, rgbaDataSurface->Stride()); DataSourceSurface::MappedSurface rgbaMap; DataSourceSurface::MappedSurface bgraMap; if (NS_WARN_IF(!rgbaDataSurface->Map(DataSourceSurface::MapType::READ, &rgbaMap)) || NS_WARN_IF(!bgraDataSurface->Map(DataSourceSurface::MapType::WRITE, &bgraMap))) { return nullptr; } libyuv::ABGRToARGB(rgbaMap.mData, rgbaMap.mStride, bgraMap.mData, bgraMap.mStride, bgraDataSurface->GetSize().width, bgraDataSurface->GetSize().height); rgbaDataSurface->Unmap(); bgraDataSurface->Unmap(); // Create an Image from the BGRA SourceSurface. RefPtr<layers::Image> image = CreateImageFromSurface(bgraDataSurface); if (NS_WARN_IF(!image)) { return nullptr; } return image.forget(); }
static already_AddRefed<SharedMemory> ReadSegment(const IPC::Message& aDescriptor, Shmem::id_t* aId, size_t* aNBytes, size_t aExtraSize) { if (SHMEM_CREATED_MESSAGE_TYPE != aDescriptor.type()) { NS_ERROR("expected 'shmem created' message"); return nullptr; } SharedMemory::SharedMemoryType type; PickleIterator iter(aDescriptor); if (!ShmemCreated::ReadInfo(&aDescriptor, &iter, aId, aNBytes, &type)) { return nullptr; } RefPtr<SharedMemory> segment = NewSegment(type); if (!segment) { return nullptr; } if (!segment->ReadHandle(&aDescriptor, &iter)) { NS_ERROR("trying to open invalid handle"); return nullptr; } aDescriptor.EndRead(iter); size_t size = SharedMemory::PageAlignedSize(*aNBytes + aExtraSize); if (!segment->Map(size)) { return nullptr; } // close the handle to the segment after it is mapped segment->CloseHandle(); return segment.forget(); }
bool MemoryDIBTextureData::UpdateFromSurface(gfx::SourceSurface* aSurface) { RefPtr<gfxImageSurface> imgSurf = mSurface->GetAsImageSurface(); RefPtr<DataSourceSurface> srcSurf = aSurface->GetDataSurface(); if (!srcSurf) { gfxCriticalError() << "Failed to GetDataSurface in UpdateFromSurface (DIB)."; return false; } DataSourceSurface::MappedSurface sourceMap; if (!srcSurf->Map(gfx::DataSourceSurface::READ, &sourceMap)) { gfxCriticalError() << "Failed to map source surface for UpdateFromSurface."; return false; } for (int y = 0; y < srcSurf->GetSize().height; y++) { memcpy(imgSurf->Data() + imgSurf->Stride() * y, sourceMap.mData + sourceMap.mStride * y, srcSurf->GetSize().width * BytesPerPixel(srcSurf->GetFormat())); } srcSurf->Unmap(); return true; }
TemporaryRef<gfx::SourceSurface> MacIOSurfaceImage::GetAsSourceSurface() { mSurface->Lock(); size_t bytesPerRow = mSurface->GetBytesPerRow(); size_t ioWidth = mSurface->GetDevicePixelWidth(); size_t ioHeight = mSurface->GetDevicePixelHeight(); unsigned char* ioData = (unsigned char*)mSurface->GetBaseAddress(); RefPtr<gfx::DataSourceSurface> dataSurface = gfx::Factory::CreateDataSourceSurface(gfx::IntSize(ioWidth, ioHeight), gfx::SurfaceFormat::B8G8R8A8); if (NS_WARN_IF(!dataSurface)) { return nullptr; } gfx::DataSourceSurface::MappedSurface mappedSurface; if (!dataSurface->Map(gfx::DataSourceSurface::WRITE, &mappedSurface)) return nullptr; for (size_t i = 0; i < ioHeight; ++i) { memcpy(mappedSurface.mData + i * mappedSurface.mStride, ioData + i * bytesPerRow, ioWidth * 4); } dataSurface->Unmap(); mSurface->Unlock(); return dataSurface; }
TemporaryRef<SourceSurface> DrawTargetSkia::OptimizeSourceSurface(SourceSurface *aSurface) const { if (aSurface->GetType() == SurfaceType::SKIA) { return aSurface; } if (!UsingSkiaGPU()) { // If we're not using skia-gl then drawing doesn't require any // uploading, so any data surface is fine. Call GetDataSurface // to trigger any required readback so that it only happens // once. return aSurface->GetDataSurface(); } // If we are using skia-gl then we want to copy into a surface that // will cache the uploaded gl texture. RefPtr<DataSourceSurface> dataSurf = aSurface->GetDataSurface(); DataSourceSurface::MappedSurface map; if (!dataSurf->Map(DataSourceSurface::READ, &map)) { return nullptr; } RefPtr<SourceSurface> result = CreateSourceSurfaceFromData(map.mData, dataSurf->GetSize(), map.mStride, dataSurf->GetFormat()); dataSurf->Unmap(); return result.forget(); }
TemporaryRef<SourceSurface> DrawTargetD2D1::OptimizeSourceSurface(SourceSurface* aSurface) const { if (aSurface->GetType() == SurfaceType::D2D1_1_IMAGE) { return aSurface; } RefPtr<DataSourceSurface> data = aSurface->GetDataSurface(); DataSourceSurface::MappedSurface map; if (!data->Map(DataSourceSurface::MapType::READ, &map)) { return nullptr; } RefPtr<ID2D1Bitmap1> bitmap; HRESULT hr = mDC->CreateBitmap(D2DIntSize(data->GetSize()), map.mData, map.mStride, D2D1::BitmapProperties1(D2D1_BITMAP_OPTIONS_NONE, D2DPixelFormat(data->GetFormat())), byRef(bitmap)); data->Unmap(); if (!bitmap) { return data; } return new SourceSurfaceD2D1(bitmap.get(), mDC, data->GetFormat(), data->GetSize()); }
NS_IMETHODIMP imgTools::EncodeScaledImage(imgIContainer *aContainer, const nsACString& aMimeType, int32_t aScaledWidth, int32_t aScaledHeight, const nsAString& aOutputOptions, nsIInputStream **aStream) { NS_ENSURE_ARG(aScaledWidth >= 0 && aScaledHeight >= 0); // If no scaled size is specified, we'll just encode the image at its // original size (no scaling). if (aScaledWidth == 0 && aScaledHeight == 0) { return EncodeImage(aContainer, aMimeType, aOutputOptions, aStream); } // Use frame 0 from the image container. RefPtr<SourceSurface> frame = aContainer->GetFrame(imgIContainer::FRAME_FIRST, imgIContainer::FLAG_SYNC_DECODE); NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE); int32_t frameWidth = frame->GetSize().width; int32_t frameHeight = frame->GetSize().height; // If the given width or height is zero we'll replace it with the image's // original dimensions. if (aScaledWidth == 0) { aScaledWidth = frameWidth; } else if (aScaledHeight == 0) { aScaledHeight = frameHeight; } RefPtr<DataSourceSurface> dataSurface = Factory::CreateDataSourceSurface(IntSize(aScaledWidth, aScaledHeight), SurfaceFormat::B8G8R8A8); if (NS_WARN_IF(!dataSurface)) { return NS_ERROR_FAILURE; } DataSourceSurface::MappedSurface map; if (!dataSurface->Map(DataSourceSurface::MapType::WRITE, &map)) { return NS_ERROR_FAILURE; } RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(BackendType::CAIRO, map.mData, dataSurface->GetSize(), map.mStride, SurfaceFormat::B8G8R8A8); dt->DrawSurface(frame, Rect(0, 0, aScaledWidth, aScaledHeight), Rect(0, 0, frameWidth, frameHeight), DrawSurfaceOptions(), DrawOptions(1.0f, CompositionOp::OP_SOURCE)); dataSurface->Unmap(); return EncodeImageData(dataSurface, aMimeType, aOutputOptions, aStream); }
TemporaryRef<DataSourceSurface> gfxUtils::UnpremultiplyDataSurface(DataSourceSurface* aSurface) { // Only premultiply ARGB32 if (aSurface->GetFormat() != SurfaceFormat::B8G8R8A8) { return aSurface; } DataSourceSurface::MappedSurface map; if (!aSurface->Map(DataSourceSurface::MapType::READ, &map)) { return nullptr; } RefPtr<DataSourceSurface> dest = Factory::CreateDataSourceSurfaceWithStride(aSurface->GetSize(), aSurface->GetFormat(), map.mStride); DataSourceSurface::MappedSurface destMap; if (!dest->Map(DataSourceSurface::MapType::WRITE, &destMap)) { aSurface->Unmap(); return nullptr; } uint8_t *src = map.mData; uint8_t *dst = destMap.mData; for (int32_t i = 0; i < aSurface->GetSize().height; ++i) { uint8_t *srcRow = src + (i * map.mStride); uint8_t *dstRow = dst + (i * destMap.mStride); for (int32_t j = 0; j < aSurface->GetSize().width; ++j) { #ifdef IS_LITTLE_ENDIAN uint8_t b = *srcRow++; uint8_t g = *srcRow++; uint8_t r = *srcRow++; uint8_t a = *srcRow++; *dstRow++ = UnpremultiplyValue(a, b); *dstRow++ = UnpremultiplyValue(a, g); *dstRow++ = UnpremultiplyValue(a, r); *dstRow++ = a; #else uint8_t a = *srcRow++; uint8_t r = *srcRow++; uint8_t g = *srcRow++; uint8_t b = *srcRow++; *dstRow++ = a; *dstRow++ = UnpremultiplyValue(a, r); *dstRow++ = UnpremultiplyValue(a, g); *dstRow++ = UnpremultiplyValue(a, b); #endif } } aSurface->Unmap(); dest->Unmap(); return dest; }
GdkPixbuf* nsImageToPixbuf::SourceSurfaceToPixbuf(SourceSurface* aSurface, int32_t aWidth, int32_t aHeight) { MOZ_ASSERT(aWidth <= aSurface->GetSize().width && aHeight <= aSurface->GetSize().height, "Requested rect is bigger than the supplied surface"); GdkPixbuf* pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, aWidth, aHeight); if (!pixbuf) return nullptr; uint32_t destStride = gdk_pixbuf_get_rowstride (pixbuf); guchar* destPixels = gdk_pixbuf_get_pixels (pixbuf); RefPtr<DataSourceSurface> dataSurface = aSurface->GetDataSurface(); DataSourceSurface::MappedSurface map; if (!dataSurface->Map(DataSourceSurface::MapType::READ, &map)) return nullptr; uint8_t* srcData = map.mData; int32_t srcStride = map.mStride; SurfaceFormat format = dataSurface->GetFormat(); for (int32_t row = 0; row < aHeight; ++row) { for (int32_t col = 0; col < aWidth; ++col) { guchar* destPixel = destPixels + row * destStride + 4 * col; uint32_t* srcPixel = reinterpret_cast<uint32_t*>((srcData + row * srcStride + 4 * col)); if (format == SurfaceFormat::B8G8R8A8) { const uint8_t a = (*srcPixel >> 24) & 0xFF; const uint8_t r = unpremultiply((*srcPixel >> 16) & 0xFF, a); const uint8_t g = unpremultiply((*srcPixel >> 8) & 0xFF, a); const uint8_t b = unpremultiply((*srcPixel >> 0) & 0xFF, a); *destPixel++ = r; *destPixel++ = g; *destPixel++ = b; *destPixel++ = a; } else { MOZ_ASSERT(format == SurfaceFormat::B8G8R8X8); const uint8_t r = (*srcPixel >> 16) & 0xFF; const uint8_t g = (*srcPixel >> 8) & 0xFF; const uint8_t b = (*srcPixel >> 0) & 0xFF; *destPixel++ = r; *destPixel++ = g; *destPixel++ = b; *destPixel++ = 0xFF; // A } } }
void TextureClientD3D11::UpdateFromSurface(gfx::SourceSurface* aSurface) { RefPtr<DataSourceSurface> srcSurf = aSurface->GetDataSurface(); if (!srcSurf) { gfxCriticalError() << "Failed to GetDataSurface in UpdateFromSurface."; return; } if (mDrawTarget) { // Ensure unflushed work from our outstanding drawtarget won't override this // update later. mDrawTarget->Flush(); } if (mSize != srcSurf->GetSize() || mFormat != srcSurf->GetFormat()) { gfxCriticalError() << "Attempt to update texture client from a surface with a different size or format!"; return; } DataSourceSurface::MappedSurface sourceMap; if (!srcSurf->Map(DataSourceSurface::READ, &sourceMap)) { gfxCriticalError() << "Failed to map source surface for UpdateFromSurface."; return; } if (mTexture) { RefPtr<ID3D11Device> device; mTexture->GetDevice(getter_AddRefs(device)); RefPtr<ID3D11DeviceContext> ctx; device->GetImmediateContext(getter_AddRefs(ctx)); D3D11_BOX box; box.front = 0; box.back = 1; box.top = box.left = 0; box.right = aSurface->GetSize().width; box.bottom = aSurface->GetSize().height; ctx->UpdateSubresource(mTexture, 0, &box, sourceMap.mData, sourceMap.mStride, 0); } else { RefPtr<ID3D10Device> device; mTexture10->GetDevice(getter_AddRefs(device)); D3D10_BOX box; box.front = 0; box.back = 1; box.top = box.left = 0; box.right = aSurface->GetSize().width; box.bottom = aSurface->GetSize().height; device->UpdateSubresource(mTexture10, 0, &box, sourceMap.mData, sourceMap.mStride, 0); } srcSurf->Unmap(); }
static already_AddRefed<SharedMemory> CreateSegment(SharedMemory::SharedMemoryType aType, size_t aNBytes, size_t aExtraSize) { RefPtr<SharedMemory> segment = NewSegment(aType); if (!segment) { return nullptr; } size_t size = SharedMemory::PageAlignedSize(aNBytes + aExtraSize); if (!segment->Create(size) || !segment->Map(size)) { return nullptr; } return segment.forget(); }
already_AddRefed<DataSourceSurface> DataSourceSurfaceFromYCbCrDescriptor(uint8_t* aBuffer, const YCbCrDescriptor& aDescriptor, gfx::DataSourceSurface* aSurface) { gfx::IntSize ySize = aDescriptor.ySize(); gfx::IntSize cbCrSize = aDescriptor.cbCrSize(); int32_t yStride = ySize.width; int32_t cbCrStride = cbCrSize.width; RefPtr<DataSourceSurface> result; if (aSurface) { MOZ_ASSERT(aSurface->GetSize() == ySize); MOZ_ASSERT(aSurface->GetFormat() == gfx::SurfaceFormat::B8G8R8X8); if (aSurface->GetSize() == ySize && aSurface->GetFormat() == gfx::SurfaceFormat::B8G8R8X8) { result = aSurface; } } if (!result) { result = Factory::CreateDataSourceSurface(ySize, gfx::SurfaceFormat::B8G8R8X8); } if (NS_WARN_IF(!result)) { return nullptr; } DataSourceSurface::MappedSurface map; if (NS_WARN_IF(!result->Map(DataSourceSurface::MapType::WRITE, &map))) { return nullptr; } layers::PlanarYCbCrData ycbcrData; ycbcrData.mYChannel = GetYChannel(aBuffer, aDescriptor); ycbcrData.mYStride = yStride; ycbcrData.mYSize = ySize; ycbcrData.mCbChannel = GetCbChannel(aBuffer, aDescriptor); ycbcrData.mCrChannel = GetCrChannel(aBuffer, aDescriptor); ycbcrData.mCbCrStride = cbCrStride; ycbcrData.mCbCrSize = cbCrSize; ycbcrData.mPicSize = ySize; ycbcrData.mYUVColorSpace = aDescriptor.yUVColorSpace(); gfx::ConvertYCbCrToRGB(ycbcrData, gfx::SurfaceFormat::B8G8R8X8, ySize, map.mData, map.mStride); result->Unmap(); return result.forget(); }
HRESULT D3D11DXVA2Manager::CopyToImage(IMFSample* aVideoSample, const nsIntRect& aRegion, ImageContainer* aContainer, Image** aOutImage) { NS_ENSURE_TRUE(aVideoSample, E_POINTER); NS_ENSURE_TRUE(aContainer, E_POINTER); NS_ENSURE_TRUE(aOutImage, E_POINTER); // Our video frame is stored in a non-sharable ID3D11Texture2D. We need // to create a copy of that frame as a sharable resource, save its share // handle, and put that handle into the rendering pipeline. RefPtr<D3D11ShareHandleImage> image = new D3D11ShareHandleImage(gfx::IntSize(mWidth, mHeight), aRegion); bool ok = image->AllocateTexture(mTextureClientAllocator); NS_ENSURE_TRUE(ok, E_FAIL); HRESULT hr = mTransform->Input(aVideoSample); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); RefPtr<IMFSample> sample; RefPtr<ID3D11Texture2D> texture = image->GetTexture(); hr = CreateOutputSample(sample, texture); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); hr = mTransform->Output(&sample); RefPtr<ID3D11DeviceContext> ctx; mDevice->GetImmediateContext(getter_AddRefs(ctx)); // Copy a small rect into our sync surface, and then map it // to block until decoding/color conversion completes. D3D11_BOX rect = { 0, 0, 0, kSyncSurfaceSize, kSyncSurfaceSize, 1 }; ctx->CopySubresourceRegion(mSyncSurface, 0, 0, 0, 0, texture, 0, &rect); D3D11_MAPPED_SUBRESOURCE mapped; hr = ctx->Map(mSyncSurface, 0, D3D11_MAP_READ, 0, &mapped); NS_ENSURE_TRUE(SUCCEEDED(hr), hr); ctx->Unmap(mSyncSurface, 0); image.forget(aOutImage); return S_OK; }
TemporaryRef<gfx::SourceSurface> GrallocImage::GetAsSourceSurface() { if (!mTextureClient) { return nullptr; } android::sp<GraphicBuffer> graphicBuffer = mTextureClient->GetGraphicBuffer(); RefPtr<gfx::DataSourceSurface> surface = gfx::Factory::CreateDataSourceSurface(GetSize(), gfx::SurfaceFormat::R5G6B5); if (NS_WARN_IF(!surface)) { return nullptr; } gfx::DataSourceSurface::MappedSurface mappedSurface; if (!surface->Map(gfx::DataSourceSurface::WRITE, &mappedSurface)) { NS_WARNING("Could not map DataSourceSurface"); return nullptr; } int32_t rv; uint32_t omxFormat = 0; omxFormat = GrallocImage::GetOmxFormat(graphicBuffer->getPixelFormat()); if (!omxFormat) { rv = ConvertVendorYUVFormatToRGB565(graphicBuffer, surface, &mappedSurface); surface->Unmap(); if (rv != OK) { NS_WARNING("Unknown color format"); return nullptr; } return surface; } rv = ConvertOmxYUVFormatToRGB565(graphicBuffer, surface, &mappedSurface, mData, omxFormat); surface->Unmap(); if (rv != OK) { return nullptr; } return surface; }
void WebGLContext::GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat) { *aImageBuffer = nullptr; *aFormat = 0; // Use GetSurfaceSnapshot() to make sure that appropriate y-flip gets applied bool premult; RefPtr<SourceSurface> snapshot = GetSurfaceSnapshot(mOptions.premultipliedAlpha ? nullptr : &premult); if (!snapshot) { return; } MOZ_ASSERT(mOptions.premultipliedAlpha || !premult, "We must get unpremult when we ask for it!"); RefPtr<DataSourceSurface> dataSurface = snapshot->GetDataSurface(); DataSourceSurface::MappedSurface map; if (!dataSurface->Map(DataSourceSurface::MapType::READ, &map)) { return; } static const fallible_t fallible = fallible_t(); uint8_t* imageBuffer = new (fallible) uint8_t[mWidth * mHeight * 4]; if (!imageBuffer) { dataSurface->Unmap(); return; } memcpy(imageBuffer, map.mData, mWidth * mHeight * 4); dataSurface->Unmap(); int32_t format = imgIEncoder::INPUT_FORMAT_HOSTARGB; if (!mOptions.premultipliedAlpha) { // We need to convert to INPUT_FORMAT_RGBA, otherwise // we are automatically considered premult, and unpremult'd. // Yes, it is THAT silly. // Except for different lossy conversions by color, // we could probably just change the label, and not change the data. gfxUtils::ConvertBGRAtoRGBA(imageBuffer, mWidth * mHeight * 4); format = imgIEncoder::INPUT_FORMAT_RGBA; } *aImageBuffer = imageBuffer; *aFormat = format; }
TemporaryRef<DataSourceSurface> YCbCrImageDataDeserializer::ToDataSourceSurface() { RefPtr<DataSourceSurface> result = Factory::CreateDataSourceSurface(GetYSize(), gfx::SurfaceFormat::B8G8R8X8); DataSourceSurface::MappedSurface map; result->Map(DataSourceSurface::MapType::WRITE, &map); gfx::ConvertYCbCrToRGB32(GetYData(), GetCbData(), GetCrData(), map.mData, 0, 0, //pic x and y GetYSize().width, GetYSize().height, GetYStride(), GetCbCrStride(), map.mStride, gfx::YV12); result->Unmap(); return result.forget(); }
static already_AddRefed<IDirect3DTexture9> SurfaceToTexture(IDirect3DDevice9 *aDevice, SourceSurface *aSurface, const IntSize &aSize) { RefPtr<DataSourceSurface> dataSurface = aSurface->GetDataSurface(); if (!dataSurface) { return nullptr; } DataSourceSurface::MappedSurface map; if (!dataSurface->Map(DataSourceSurface::MapType::READ, &map)) { return nullptr; } nsRefPtr<IDirect3DTexture9> texture = DataToTexture(aDevice, map.mData, map.mStride, aSize, D3dFormatForSurfaceFormat(dataSurface->GetFormat())); dataSurface->Unmap(); return texture.forget(); }
bool GrallocTextureData::UpdateFromSurface(gfx::SourceSurface* aSurface) { MOZ_ASSERT(mMappedBuffer, "Calling TextureClient::BorrowDrawTarget without locking :("); if (!mMappedBuffer) { return false; } RefPtr<DataSourceSurface> srcSurf = aSurface->GetDataSurface(); if (!srcSurf) { gfxCriticalError() << "Failed to GetDataSurface in UpdateFromSurface (GTC)."; return false; } gfx::SurfaceFormat format = SurfaceFormatForPixelFormat(mGraphicBuffer->getPixelFormat()); if (mSize != srcSurf->GetSize() || mFormat != srcSurf->GetFormat()) { gfxCriticalError() << "Attempt to update texture client from a surface with a different size or format! This: " << mSize << " " << format << " Other: " << srcSurf->GetSize() << " " << srcSurf->GetFormat(); return false; } long pixelStride = mGraphicBuffer->getStride(); long byteStride = pixelStride * BytesPerPixel(format); DataSourceSurface::MappedSurface sourceMap; if (!srcSurf->Map(DataSourceSurface::READ, &sourceMap)) { gfxCriticalError() << "Failed to map source surface for UpdateFromSurface (GTC)."; return false; } for (int y = 0; y < srcSurf->GetSize().height; y++) { memcpy(mMappedBuffer + byteStride * y, sourceMap.mData + sourceMap.mStride * y, srcSurf->GetSize().width * BytesPerPixel(srcSurf->GetFormat())); } srcSurf->Unmap(); return true; }
static bool MapSrcAndCreateMappedDest(DataSourceSurface* srcSurf, RefPtr<DataSourceSurface>* out_destSurf, DataSourceSurface::MappedSurface* out_srcMap, DataSourceSurface::MappedSurface* out_destMap) { MOZ_ASSERT(srcSurf); MOZ_ASSERT(out_destSurf && out_srcMap && out_destMap); if (srcSurf->GetFormat() != SurfaceFormat::B8G8R8A8) { MOZ_ASSERT(false, "Only operate on BGRA8."); return false; } // Ok, map source for reading. DataSourceSurface::MappedSurface srcMap; if (!srcSurf->Map(DataSourceSurface::MapType::READ, &srcMap)) { MOZ_ASSERT(false, "Couldn't Map srcSurf."); return false; } // Make our dest surface based on the src. RefPtr<DataSourceSurface> destSurf = Factory::CreateDataSourceSurfaceWithStride(srcSurf->GetSize(), srcSurf->GetFormat(), srcMap.mStride); if (NS_WARN_IF(!destSurf)) { return false; } DataSourceSurface::MappedSurface destMap; if (!destSurf->Map(DataSourceSurface::MapType::WRITE, &destMap)) { MOZ_ASSERT(false, "Couldn't Map destSurf."); srcSurf->Unmap(); return false; } *out_destSurf = destSurf; *out_srcMap = srcMap; *out_destMap = destMap; return true; }
bool ShmemDIBTextureData::UpdateFromSurface(gfx::SourceSurface* aSurface) { RefPtr<DataSourceSurface> srcSurf = aSurface->GetDataSurface(); if (!srcSurf) { gfxCriticalError() << "Failed to GetDataSurface in UpdateFromSurface (DTD)."; return false; } DataSourceSurface::MappedSurface sourceMap; if (!srcSurf->Map(gfx::DataSourceSurface::READ, &sourceMap)) { gfxCriticalError() << "Failed to map source surface for UpdateFromSurface."; return false; } GdiFlush(); uint32_t stride = mSize.width * BytesPerPixel(mFormat); uint8_t* data = (uint8_t*)::MapViewOfFile(mFileMapping, FILE_MAP_WRITE, 0, 0, stride * mSize.height); if (!data) { gfxCriticalError() << "Failed to map view of file for UpdateFromSurface."; srcSurf->Unmap(); return false; } for (int y = 0; y < srcSurf->GetSize().height; y++) { memcpy(data + stride * y, sourceMap.mData + sourceMap.mStride * y, srcSurf->GetSize().width * BytesPerPixel(srcSurf->GetFormat())); } ::UnmapViewOfFile(data); srcSurf->Unmap(); return true; }
already_AddRefed<DataSourceSurface> YCbCrImageDataDeserializer::ToDataSourceSurface() { RefPtr<DataSourceSurface> result = Factory::CreateDataSourceSurface(GetYSize(), gfx::SurfaceFormat::B8G8R8X8); if (NS_WARN_IF(!result)) { return nullptr; } DataSourceSurface::MappedSurface map; if (NS_WARN_IF(!result->Map(DataSourceSurface::MapType::WRITE, &map))) { return nullptr; } gfx::ConvertYCbCrToRGB32(GetYData(), GetCbData(), GetCrData(), map.mData, 0, 0, //pic x and y GetYSize().width, GetYSize().height, GetYStride(), GetCbCrStride(), map.mStride, gfx::YV12); result->Unmap(); return result.forget(); }
/* static */ nsresult ImageEncoder::ExtractDataInternal(const nsAString& aType, const nsAString& aOptions, uint8_t* aImageBuffer, int32_t aFormat, const nsIntSize aSize, layers::Image* aImage, nsICanvasRenderingContextInternal* aContext, nsIInputStream** aStream, imgIEncoder* aEncoder) { if (aSize.IsEmpty()) { return NS_ERROR_INVALID_ARG; } nsCOMPtr<nsIInputStream> imgStream; // get image bytes nsresult rv; if (aImageBuffer) { rv = ImageEncoder::GetInputStream( aSize.width, aSize.height, aImageBuffer, aFormat, aEncoder, nsPromiseFlatString(aOptions).get(), getter_AddRefs(imgStream)); } else if (aContext) { NS_ConvertUTF16toUTF8 encoderType(aType); rv = aContext->GetInputStream(encoderType.get(), nsPromiseFlatString(aOptions).get(), getter_AddRefs(imgStream)); } else if (aImage) { // It is safe to convert PlanarYCbCr format from YUV to RGB off-main-thread. // Other image formats could have problem to convert format off-main-thread. // So here it uses a help function GetBRGADataSourceSurfaceSync() to convert // format on main thread. if (aImage->GetFormat() == ImageFormat::PLANAR_YCBCR) { nsTArray<uint8_t> data; layers::PlanarYCbCrImage* ycbcrImage = static_cast<layers::PlanarYCbCrImage*> (aImage); gfxImageFormat format = gfxImageFormat::ARGB32; uint32_t stride = GetAlignedStride<16>(aSize.width * 4); size_t length = BufferSizeFromStrideAndHeight(stride, aSize.height); data.SetCapacity(length); gfxUtils::ConvertYCbCrToRGB(*ycbcrImage->GetData(), format, aSize, data.Elements(), stride); rv = aEncoder->InitFromData(data.Elements(), aSize.width * aSize.height * 4, aSize.width, aSize.height, aSize.width * 4, imgIEncoder::INPUT_FORMAT_HOSTARGB, aOptions); } else { RefPtr<gfx::DataSourceSurface> dataSurface; dataSurface = GetBRGADataSourceSurfaceSync(aImage); DataSourceSurface::MappedSurface map; if (!dataSurface->Map(gfx::DataSourceSurface::MapType::READ, &map)) { return NS_ERROR_INVALID_ARG; } rv = aEncoder->InitFromData(map.mData, aSize.width * aSize.height * 4, aSize.width, aSize.height, aSize.width * 4, imgIEncoder::INPUT_FORMAT_HOSTARGB, aOptions); dataSurface->Unmap(); } if (NS_SUCCEEDED(rv)) { imgStream = do_QueryInterface(aEncoder); } } else { // no context, so we have to encode an empty image // note that if we didn't have a current context, the spec says we're // supposed to just return transparent black pixels of the canvas // dimensions. RefPtr<DataSourceSurface> emptyCanvas = Factory::CreateDataSourceSurfaceWithStride(IntSize(aSize.width, aSize.height), SurfaceFormat::B8G8R8A8, 4 * aSize.width, true); if (NS_WARN_IF(!emptyCanvas)) { return NS_ERROR_INVALID_ARG; } DataSourceSurface::MappedSurface map; if (!emptyCanvas->Map(DataSourceSurface::MapType::WRITE, &map)) { return NS_ERROR_INVALID_ARG; } rv = aEncoder->InitFromData(map.mData, aSize.width * aSize.height * 4, aSize.width, aSize.height, aSize.width * 4, imgIEncoder::INPUT_FORMAT_HOSTARGB, aOptions); emptyCanvas->Unmap(); if (NS_SUCCEEDED(rv)) { imgStream = do_QueryInterface(aEncoder); } } NS_ENSURE_SUCCESS(rv, rv); imgStream.forget(aStream); return rv; }
TemporaryRef<gfx::SourceSurface> GrallocImage::GetAsSourceSurface() { if (!mTextureClient) { return nullptr; } android::sp<GraphicBuffer> graphicBuffer = mTextureClient->GetGraphicBuffer(); void *buffer; int32_t rv = graphicBuffer->lock(android::GraphicBuffer::USAGE_SW_READ_OFTEN, &buffer); if (rv) { NS_WARNING("Couldn't lock graphic buffer"); return nullptr; } GraphicBufferAutoUnlock unlock(graphicBuffer); uint32_t format = graphicBuffer->getPixelFormat(); uint32_t omxFormat = 0; for (int i = 0; sColorIdMap[i]; i += 2) { if (sColorIdMap[i] == format) { omxFormat = sColorIdMap[i + 1]; break; } } if (!omxFormat) { NS_WARNING("Unknown color format"); return nullptr; } RefPtr<gfx::DataSourceSurface> surface = gfx::Factory::CreateDataSourceSurface(GetSize(), gfx::SurfaceFormat::R5G6B5); if (!surface) { NS_WARNING("Failed to create SourceSurface."); return nullptr; } uint32_t width = GetSize().width; uint32_t height = GetSize().height; gfx::DataSourceSurface::MappedSurface mappedSurface; if (!surface->Map(gfx::DataSourceSurface::WRITE, &mappedSurface)) { NS_WARNING("Could not map DataSourceSurface"); return nullptr; } if (format == HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO) { // The Adreno hardware decoder aligns image dimensions to a multiple of 32, // so we have to account for that here uint32_t alignedWidth = ALIGN(width, 32); uint32_t alignedHeight = ALIGN(height, 32); uint32_t uvOffset = ALIGN(alignedHeight * alignedWidth, 4096); uint32_t uvStride = 2 * ALIGN(width / 2, 32); uint8_t* buffer_as_bytes = static_cast<uint8_t*>(buffer); ConvertYVU420SPToRGB565(buffer, alignedWidth, buffer_as_bytes + uvOffset, uvStride, mappedSurface.mData, width, height); surface->Unmap(); return surface; } if (format == HAL_PIXEL_FORMAT_YCrCb_420_SP) { uint32_t uvOffset = height * width; ConvertYVU420SPToRGB565(buffer, width, buffer + uvOffset, width, mappedSurface.mData, width, height); surface->Unmap(); return surface; } if (format == HAL_PIXEL_FORMAT_YV12) { gfx::ConvertYCbCrToRGB(mData, surface->GetFormat(), mSize, surface->GetData(), surface->Stride()); surface->Unmap(); return surface; } android::ColorConverter colorConverter((OMX_COLOR_FORMATTYPE)omxFormat, OMX_COLOR_Format16bitRGB565); if (!colorConverter.isValid()) { NS_WARNING("Invalid color conversion"); surface->Unmap(); return nullptr; } rv = colorConverter.convert(buffer, width, height, 0, 0, width - 1, height - 1 /* source crop */, mappedSurface.mData, width, height, 0, 0, width - 1, height - 1 /* dest crop */); surface->Unmap(); if (rv) { NS_WARNING("OMX color conversion failed"); return nullptr; } return surface; }
NS_IMETHODIMP imgTools::EncodeCroppedImage(imgIContainer* aContainer, const nsACString& aMimeType, int32_t aOffsetX, int32_t aOffsetY, int32_t aWidth, int32_t aHeight, const nsAString& aOutputOptions, nsIInputStream** aStream) { NS_ENSURE_ARG(aOffsetX >= 0 && aOffsetY >= 0 && aWidth >= 0 && aHeight >= 0); // Offsets must be zero when no width and height are given or else we're out // of bounds. NS_ENSURE_ARG(aWidth + aHeight > 0 || aOffsetX + aOffsetY == 0); // If no size is specified then we'll preserve the image's original dimensions // and don't need to crop. if (aWidth == 0 && aHeight == 0) { return EncodeImage(aContainer, aMimeType, aOutputOptions, aStream); } // Use frame 0 from the image container. RefPtr<SourceSurface> frame = aContainer->GetFrame(imgIContainer::FRAME_FIRST, imgIContainer::FLAG_SYNC_DECODE); NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE); int32_t frameWidth = frame->GetSize().width; int32_t frameHeight = frame->GetSize().height; // If the given width or height is zero we'll replace it with the image's // original dimensions. if (aWidth == 0) { aWidth = frameWidth; } else if (aHeight == 0) { aHeight = frameHeight; } // Check that the given crop rectangle is within image bounds. NS_ENSURE_ARG(frameWidth >= aOffsetX + aWidth && frameHeight >= aOffsetY + aHeight); RefPtr<DataSourceSurface> dataSurface = Factory::CreateDataSourceSurface(IntSize(aWidth, aHeight), SurfaceFormat::B8G8R8A8, /* aZero = */ true); if (NS_WARN_IF(!dataSurface)) { return NS_ERROR_FAILURE; } DataSourceSurface::MappedSurface map; if (!dataSurface->Map(DataSourceSurface::MapType::WRITE, &map)) { return NS_ERROR_FAILURE; } RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(BackendType::CAIRO, map.mData, dataSurface->GetSize(), map.mStride, SurfaceFormat::B8G8R8A8); if (!dt) { gfxWarning() << "imgTools::EncodeCroppedImage failed in CreateDrawTargetForData"; return NS_ERROR_OUT_OF_MEMORY; } dt->CopySurface(frame, IntRect(aOffsetX, aOffsetY, aWidth, aHeight), IntPoint(0, 0)); dataSurface->Unmap(); return EncodeImageData(dataSurface, aMimeType, aOutputOptions, aStream); }
bool nsDragService::CreateDragImage(nsIDOMNode *aDOMNode, nsIScriptableRegion *aRegion, SHDRAGIMAGE *psdi) { if (!psdi) return false; memset(psdi, 0, sizeof(SHDRAGIMAGE)); if (!aDOMNode) return false; // Prepare the drag image nsIntRect dragRect; RefPtr<SourceSurface> surface; nsPresContext* pc; DrawDrag(aDOMNode, aRegion, mScreenX, mScreenY, &dragRect, &surface, &pc); if (!surface) return false; uint32_t bmWidth = dragRect.width, bmHeight = dragRect.height; if (bmWidth == 0 || bmHeight == 0) return false; psdi->crColorKey = CLR_NONE; RefPtr<DataSourceSurface> dataSurface = Factory::CreateDataSourceSurface(IntSize(bmWidth, bmHeight), SurfaceFormat::B8G8R8A8); NS_ENSURE_TRUE(dataSurface, false); DataSourceSurface::MappedSurface map; if (!dataSurface->Map(DataSourceSurface::MapType::READ_WRITE, &map)) { return false; } RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(BackendType::CAIRO, map.mData, dataSurface->GetSize(), map.mStride, dataSurface->GetFormat()); if (!dt) { dataSurface->Unmap(); return false; } dt->DrawSurface(surface, Rect(0, 0, dataSurface->GetSize().width, dataSurface->GetSize().height), Rect(0, 0, surface->GetSize().width, surface->GetSize().height), DrawSurfaceOptions(), DrawOptions(1.0f, CompositionOp::OP_SOURCE)); dt->Flush(); BITMAPV5HEADER bmih; memset((void*)&bmih, 0, sizeof(BITMAPV5HEADER)); bmih.bV5Size = sizeof(BITMAPV5HEADER); bmih.bV5Width = bmWidth; bmih.bV5Height = -(int32_t)bmHeight; // flip vertical bmih.bV5Planes = 1; bmih.bV5BitCount = 32; bmih.bV5Compression = BI_BITFIELDS; bmih.bV5RedMask = 0x00FF0000; bmih.bV5GreenMask = 0x0000FF00; bmih.bV5BlueMask = 0x000000FF; bmih.bV5AlphaMask = 0xFF000000; HDC hdcSrc = CreateCompatibleDC(nullptr); void *lpBits = nullptr; if (hdcSrc) { psdi->hbmpDragImage = ::CreateDIBSection(hdcSrc, (BITMAPINFO*)&bmih, DIB_RGB_COLORS, (void**)&lpBits, nullptr, 0); if (psdi->hbmpDragImage && lpBits) { CopySurfaceDataToPackedArray(map.mData, static_cast<uint8_t*>(lpBits), dataSurface->GetSize(), map.mStride, BytesPerPixel(dataSurface->GetFormat())); } psdi->sizeDragImage.cx = bmWidth; psdi->sizeDragImage.cy = bmHeight; // Mouse position in center if (mScreenX == -1 || mScreenY == -1) { psdi->ptOffset.x = (uint32_t)((float)bmWidth/2.0f); psdi->ptOffset.y = (uint32_t)((float)bmHeight/2.0f); } else { int32_t sx = mScreenX, sy = mScreenY; ConvertToUnscaledDevPixels(pc, &sx, &sy); psdi->ptOffset.x = sx - dragRect.x; psdi->ptOffset.y = sy - dragRect.y; } DeleteDC(hdcSrc); } dataSurface->Unmap(); return psdi->hbmpDragImage != nullptr; }
already_AddRefed<gfx::SourceSurface> D3D11ShareHandleImage::GetAsSourceSurface() { RefPtr<ID3D11Texture2D> texture = GetTexture(); if (!texture) { gfxWarning() << "Cannot readback from shared texture because no texture is available."; return nullptr; } RefPtr<ID3D11Device> device; texture->GetDevice(getter_AddRefs(device)); D3D11_TEXTURE2D_DESC desc; texture->GetDesc(&desc); HRESULT hr; if (desc.Format == DXGI_FORMAT_NV12) { nsAutoCString error; std::unique_ptr<DXVA2Manager> manager(DXVA2Manager::CreateD3D11DXVA(nullptr, error, device)); if (!manager) { gfxWarning() << "Failed to create DXVA2 manager!"; return nullptr; } RefPtr<ID3D11Texture2D> outTexture; hr = manager->CopyToBGRATexture(texture, getter_AddRefs(outTexture)); if (FAILED(hr)) { gfxWarning() << "Failed to copy NV12 to BGRA texture."; return nullptr; } texture = outTexture; texture->GetDesc(&desc); } CD3D11_TEXTURE2D_DESC softDesc(desc.Format, desc.Width, desc.Height); softDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; softDesc.BindFlags = 0; softDesc.MiscFlags = 0; softDesc.MipLevels = 1; softDesc.Usage = D3D11_USAGE_STAGING; RefPtr<ID3D11Texture2D> softTexture; hr = device->CreateTexture2D(&softDesc, NULL, static_cast<ID3D11Texture2D**>(getter_AddRefs(softTexture))); if (FAILED(hr)) { NS_WARNING("Failed to create 2D staging texture."); return nullptr; } RefPtr<ID3D11DeviceContext> context; device->GetImmediateContext(getter_AddRefs(context)); if (!context) { return nullptr; } RefPtr<IDXGIKeyedMutex> mutex; hr = texture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mutex)); if (SUCCEEDED(hr) && mutex) { hr = mutex->AcquireSync(0, 2000); if (hr != S_OK) { NS_WARNING("Acquire sync didn't manage to return within 2 seconds."); } } context->CopyResource(softTexture, texture); if (SUCCEEDED(hr) && mutex) { mutex->ReleaseSync(0); } RefPtr<gfx::DataSourceSurface> surface = gfx::Factory::CreateDataSourceSurface(mSize, gfx::SurfaceFormat::B8G8R8A8); if (NS_WARN_IF(!surface)) { return nullptr; } gfx::DataSourceSurface::MappedSurface mappedSurface; if (!surface->Map(gfx::DataSourceSurface::WRITE, &mappedSurface)) { return nullptr; } D3D11_MAPPED_SUBRESOURCE map; hr = context->Map(softTexture, 0, D3D11_MAP_READ, 0, &map); if (!SUCCEEDED(hr)) { surface->Unmap(); return nullptr; } for (int y = 0; y < mSize.height; y++) { memcpy(mappedSurface.mData + mappedSurface.mStride * y, (unsigned char*)(map.pData) + map.RowPitch * y, mSize.width * 4); } context->Unmap(softTexture, 0); surface->Unmap(); return surface.forget(); }
void TextRenderer::RenderText(const string& aText, const IntPoint& aOrigin, const Matrix4x4& aTransform, uint32_t aTextSize, uint32_t aTargetPixelWidth) { EnsureInitialized(); // For now we only have a bitmap font with a 16px cell size, so we just // scale it up if the user wants larger text. Float scaleFactor = Float(aTextSize) / Float(sCellHeight); aTargetPixelWidth /= scaleFactor; uint32_t numLines = 1; uint32_t maxWidth = 0; uint32_t lineWidth = 0; // Calculate the size of the surface needed to draw all the glyphs. for (uint32_t i = 0; i < aText.length(); i++) { // Insert a line break if we go past the TargetPixelWidth. // XXX - this has the downside of overrunning the intended width, causing // things at the edge of a window to be cut off. if (aText[i] == '\n' || (aText[i] == ' ' && lineWidth > aTargetPixelWidth)) { numLines++; lineWidth = 0; continue; } lineWidth += sGlyphWidths[uint32_t(aText[i])]; maxWidth = std::max(lineWidth, maxWidth); } // Create a surface to draw our glyphs to. RefPtr<DataSourceSurface> textSurf = Factory::CreateDataSourceSurface(IntSize(maxWidth, numLines * sCellHeight), sTextureFormat); if (NS_WARN_IF(!textSurf)) { return; } DataSourceSurface::MappedSurface map; if (NS_WARN_IF(!textSurf->Map(DataSourceSurface::MapType::READ_WRITE, &map))) { return; } // Initialize the surface to transparent white. memset(map.mData, uint8_t(sBackgroundOpacity * 255.0f), numLines * sCellHeight * map.mStride); uint32_t currentXPos = 0; uint32_t currentYPos = 0; // Copy our glyphs onto the surface. for (uint32_t i = 0; i < aText.length(); i++) { if (aText[i] == '\n' || (aText[i] == ' ' && currentXPos > aTargetPixelWidth)) { currentYPos += sCellHeight; currentXPos = 0; continue; } uint32_t glyphXOffset = aText[i] % (sTextureWidth / sCellWidth) * sCellWidth * BytesPerPixel(sTextureFormat); uint32_t truncatedLine = aText[i] / (sTextureWidth / sCellWidth); uint32_t glyphYOffset = truncatedLine * sCellHeight * mMap.mStride; for (int y = 0; y < 16; y++) { memcpy(map.mData + (y + currentYPos) * map.mStride + currentXPos * BytesPerPixel(sTextureFormat), mMap.mData + glyphYOffset + y * mMap.mStride + glyphXOffset, sGlyphWidths[uint32_t(aText[i])] * BytesPerPixel(sTextureFormat)); } currentXPos += sGlyphWidths[uint32_t(aText[i])]; } textSurf->Unmap(); RefPtr<DataTextureSource> src = mCompositor->CreateDataTextureSource(); if (!src->Update(textSurf)) { // Upload failed. return; } RefPtr<EffectRGB> effect = new EffectRGB(src, true, SamplingFilter::LINEAR); EffectChain chain; chain.mPrimaryEffect = effect; Matrix4x4 transform = aTransform; transform.PreScale(scaleFactor, scaleFactor, 1.0f); mCompositor->DrawQuad(Rect(aOrigin.x, aOrigin.y, maxWidth, numLines * 16), IntRect(-10000, -10000, 20000, 20000), chain, 1.0f, transform); }
NS_IMETHODIMP nsClipboard::SetNativeClipboardData( nsITransferable *aTransferable, QClipboard::Mode clipboardMode ) { if (nullptr == aTransferable) { NS_WARNING("nsClipboard::SetNativeClipboardData(): no transferable!"); return NS_ERROR_FAILURE; } // get flavor list that includes all flavors that can be written (including // ones obtained through conversion) nsCOMPtr<nsISupportsArray> flavorList; nsresult rv = aTransferable->FlavorsTransferableCanExport( getter_AddRefs(flavorList) ); if (NS_FAILED(rv)) { NS_WARNING("nsClipboard::SetNativeClipboardData(): no FlavorsTransferable !"); return NS_ERROR_FAILURE; } QClipboard *cb = QGuiApplication::clipboard(); QMimeData *mimeData = new QMimeData; uint32_t flavorCount = 0; flavorList->Count(&flavorCount); bool imageAdded = false; for (uint32_t i = 0; i < flavorCount; ++i) { nsCOMPtr<nsISupports> genericFlavor; flavorList->GetElementAt(i,getter_AddRefs(genericFlavor)); nsCOMPtr<nsISupportsCString> currentFlavor(do_QueryInterface(genericFlavor)); if (currentFlavor) { // flavorStr is the mime type nsXPIDLCString flavorStr; currentFlavor->ToString(getter_Copies(flavorStr)); // Clip is the data which will be sent to the clipboard nsCOMPtr<nsISupports> clip; // len is the length of the data uint32_t len; // Unicode text? if (!strcmp(flavorStr.get(), kUnicodeMime)) { rv = aTransferable->GetTransferData(flavorStr,getter_AddRefs(clip),&len); nsCOMPtr<nsISupportsString> wideString; wideString = do_QueryInterface(clip); if (!wideString || NS_FAILED(rv)) continue; nsAutoString utf16string; wideString->GetData(utf16string); QString str = QString::fromUtf16((const ushort*)utf16string.get()); // Add text to the mimeData mimeData->setText(str); } // html? else if (!strcmp(flavorStr.get(), kHTMLMime)) { rv = aTransferable->GetTransferData(flavorStr,getter_AddRefs(clip),&len); nsCOMPtr<nsISupportsString> wideString; wideString = do_QueryInterface(clip); if (!wideString || NS_FAILED(rv)) continue; nsAutoString utf16string; wideString->GetData(utf16string); QString str = QString::fromUtf16((const ushort*)utf16string.get()); // Add html to the mimeData mimeData->setHtml(str); } // image? else if (!imageAdded // image is added only once to the clipboard && (!strcmp(flavorStr.get(), kNativeImageMime) || !strcmp(flavorStr.get(), kPNGImageMime) || !strcmp(flavorStr.get(), kJPEGImageMime) || !strcmp(flavorStr.get(), kJPGImageMime) || !strcmp(flavorStr.get(), kGIFImageMime)) ) { // Look through our transfer data for the image static const char* const imageMimeTypes[] = { kNativeImageMime, kPNGImageMime, kJPEGImageMime, kJPGImageMime, kGIFImageMime }; nsCOMPtr<nsISupportsInterfacePointer> ptrPrimitive; for (uint32_t i = 0; !ptrPrimitive && i < ArrayLength(imageMimeTypes); i++) { aTransferable->GetTransferData(imageMimeTypes[i], getter_AddRefs(clip), &len); ptrPrimitive = do_QueryInterface(clip); } if (!ptrPrimitive) continue; nsCOMPtr<nsISupports> primitiveData; ptrPrimitive->GetData(getter_AddRefs(primitiveData)); nsCOMPtr<imgIContainer> image(do_QueryInterface(primitiveData)); if (!image) // Not getting an image for an image mime type!? continue; RefPtr<SourceSurface> surface = image->GetFrame(imgIContainer::FRAME_CURRENT, imgIContainer::FLAG_SYNC_DECODE); if (!surface) continue; RefPtr<DataSourceSurface> dataSurface = surface->GetDataSurface(); if (!dataSurface) continue; DataSourceSurface::MappedSurface map; if (!dataSurface->Map(DataSourceSurface::MapType::READ, &map)) continue; QImage qImage(map.mData, dataSurface->GetSize().width, dataSurface->GetSize().height, map.mStride, _moz2dformat_to_qformat(dataSurface->GetFormat())); dataSurface->Unmap(); // Add image to the mimeData mimeData->setImageData(qImage); imageAdded = true; } // Other flavors, adding data to clipboard "as is" else { rv = aTransferable->GetTransferData(flavorStr.get(), getter_AddRefs(clip), &len); // nothing found? if (!clip || NS_FAILED(rv)) continue; void *primitive_data = nullptr; nsPrimitiveHelpers::CreateDataFromPrimitive(flavorStr.get(), clip, &primitive_data, len); if (primitive_data) { QByteArray data ((const char *)primitive_data, len); // Add data to the mimeData mimeData->setData(flavorStr.get(), data); nsMemory::Free(primitive_data); } } } } // If we have some mime data, add it to the clipboard if(!mimeData->formats().isEmpty()) cb->setMimeData(mimeData, clipboardMode); else delete mimeData; return NS_OK; }
// See bug 1083071. On some drivers, Direct3D 11 CreateShaderResourceView fails // with E_OUTOFMEMORY. static bool DoesTextureSharingWorkInternal(ID3D11Device *device, DXGI_FORMAT format, UINT bindflags) { // CreateTexture2D is known to crash on lower feature levels, see bugs // 1170211 and 1089413. if (device->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0) { return false; } if (gfxPrefs::Direct2DForceEnabled() || gfxConfig::IsForcedOnByUser(Feature::HW_COMPOSITING)) { return true; } if (GetModuleHandleW(L"atidxx32.dll")) { nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo(); if (gfxInfo) { nsString vendorID, vendorID2; gfxInfo->GetAdapterVendorID(vendorID); gfxInfo->GetAdapterVendorID2(vendorID2); if (vendorID.EqualsLiteral("0x8086") && vendorID2.IsEmpty()) { if (!gfxPrefs::LayersAMDSwitchableGfxEnabled()) { return false; } gfxCriticalError(CriticalLog::DefaultOptions(false)) << "PossiblyBrokenSurfaceSharing_UnexpectedAMDGPU"; } } } RefPtr<ID3D11Texture2D> texture; D3D11_TEXTURE2D_DESC desc; const int texture_size = 32; desc.Width = texture_size; desc.Height = texture_size; desc.MipLevels = 1; desc.ArraySize = 1; desc.Format = format; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.Usage = D3D11_USAGE_DEFAULT; desc.CPUAccessFlags = 0; desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX; desc.BindFlags = bindflags; uint32_t color[texture_size * texture_size]; for (size_t i = 0; i < sizeof(color)/sizeof(color[0]); i++) { color[i] = 0xff00ffff; } // XXX If we pass the data directly at texture creation time we // get a crash on Intel 8.5.10.[18xx-1994] drivers. // We can work around this issue by doing UpdateSubresource. if (!TryCreateTexture2D(device, &desc, nullptr, texture)) { gfxCriticalNote << "DoesD3D11TextureSharingWork_TryCreateTextureFailure"; return false; } RefPtr<IDXGIKeyedMutex> sourceSharedMutex; texture->QueryInterface(__uuidof(IDXGIKeyedMutex), (void**)getter_AddRefs(sourceSharedMutex)); if (FAILED(sourceSharedMutex->AcquireSync(0, 30*1000))) { gfxCriticalError() << "DoesD3D11TextureSharingWork_SourceMutexTimeout"; // only wait for 30 seconds return false; } RefPtr<ID3D11DeviceContext> deviceContext; device->GetImmediateContext(getter_AddRefs(deviceContext)); int stride = texture_size * 4; deviceContext->UpdateSubresource(texture, 0, nullptr, color, stride, stride * texture_size); if (FAILED(sourceSharedMutex->ReleaseSync(0))) { gfxCriticalError() << "DoesD3D11TextureSharingWork_SourceReleaseSyncTimeout"; return false; } HANDLE shareHandle; RefPtr<IDXGIResource> otherResource; if (FAILED(texture->QueryInterface(__uuidof(IDXGIResource), getter_AddRefs(otherResource)))) { gfxCriticalError() << "DoesD3D11TextureSharingWork_GetResourceFailure"; return false; } if (FAILED(otherResource->GetSharedHandle(&shareHandle))) { gfxCriticalError() << "DoesD3D11TextureSharingWork_GetSharedTextureFailure"; return false; } RefPtr<ID3D11Resource> sharedResource; RefPtr<ID3D11Texture2D> sharedTexture; if (FAILED(device->OpenSharedResource(shareHandle, __uuidof(ID3D11Resource), getter_AddRefs(sharedResource)))) { gfxCriticalError(CriticalLog::DefaultOptions(false)) << "OpenSharedResource failed for format " << format; return false; } if (FAILED(sharedResource->QueryInterface(__uuidof(ID3D11Texture2D), getter_AddRefs(sharedTexture)))) { gfxCriticalError() << "DoesD3D11TextureSharingWork_GetSharedTextureFailure"; return false; } // create a staging texture for readback RefPtr<ID3D11Texture2D> cpuTexture; desc.Usage = D3D11_USAGE_STAGING; desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; desc.MiscFlags = 0; desc.BindFlags = 0; if (FAILED(device->CreateTexture2D(&desc, nullptr, getter_AddRefs(cpuTexture)))) { gfxCriticalError() << "DoesD3D11TextureSharingWork_CreateTextureFailure"; return false; } RefPtr<IDXGIKeyedMutex> sharedMutex; sharedResource->QueryInterface(__uuidof(IDXGIKeyedMutex), (void**)getter_AddRefs(sharedMutex)); { HRESULT hr; AutoTextureLock lock(sharedMutex, hr, 30*1000); if (FAILED(hr)) { gfxCriticalError() << "DoesD3D11TextureSharingWork_AcquireSyncTimeout"; // only wait for 30 seconds return false; } // Copy to the cpu texture so that we can readback deviceContext->CopyResource(cpuTexture, sharedTexture); // We only need to hold on to the mutex during the copy. sharedMutex->ReleaseSync(0); } D3D11_MAPPED_SUBRESOURCE mapped; uint32_t resultColor = 0; if (SUCCEEDED(deviceContext->Map(cpuTexture, 0, D3D11_MAP_READ, 0, &mapped))) { // read the texture resultColor = *(uint32_t*)mapped.pData; deviceContext->Unmap(cpuTexture, 0); } else { gfxCriticalError() << "DoesD3D11TextureSharingWork_MapFailed"; return false; } // check that the color we put in is the color we get out if (resultColor != color[0]) { // Shared surfaces seem to be broken on dual AMD & Intel HW when using the // AMD GPU gfxCriticalNote << "DoesD3D11TextureSharingWork_ColorMismatch"; return false; } RefPtr<ID3D11ShaderResourceView> sharedView; // This if(FAILED()) is the one that actually fails on systems affected by bug 1083071. if (FAILED(device->CreateShaderResourceView(sharedTexture, NULL, getter_AddRefs(sharedView)))) { gfxCriticalNote << "CreateShaderResourceView failed for format" << format; return false; } return true; }