void WebRenderBridgeParent::ProcessWebRenderParentCommands(InfallibleTArray<WebRenderParentCommand>& aCommands) { for (InfallibleTArray<WebRenderParentCommand>::index_type i = 0; i < aCommands.Length(); ++i) { const WebRenderParentCommand& cmd = aCommands[i]; switch (cmd.type()) { case WebRenderParentCommand::TOpAddExternalImage: { const OpAddExternalImage& op = cmd.get_OpAddExternalImage(); Range<const wr::ImageKey> keys(&op.key(), 1); // Check if key is obsoleted. if (keys[0].mNamespace != mIdNamespace) { break; } MOZ_ASSERT(mExternalImageIds.Get(wr::AsUint64(op.externalImageId())).get()); MOZ_ASSERT(mActiveImageKeys.find(wr::AsUint64(keys[0])) == mActiveImageKeys.end()); mActiveImageKeys.insert(wr::AsUint64(keys[0])); RefPtr<WebRenderImageHost> host = mExternalImageIds.Get(wr::AsUint64(op.externalImageId())); if (!host) { NS_ERROR("CompositableHost does not exist"); break; } if (!gfxEnv::EnableWebRenderRecording()) { TextureHost* texture = host->GetAsTextureHostForComposite(); if (!texture) { NS_ERROR("TextureHost does not exist"); break; } WebRenderTextureHost* wrTexture = texture->AsWebRenderTextureHost(); if (wrTexture) { wrTexture->AddWRImage(mApi, keys, wrTexture->GetExternalImageKey()); break; } } RefPtr<DataSourceSurface> dSurf = host->GetAsSurface(); if (!dSurf) { NS_ERROR("TextureHost does not return DataSourceSurface"); break; } DataSourceSurface::MappedSurface map; if (!dSurf->Map(gfx::DataSourceSurface::MapType::READ, &map)) { NS_ERROR("DataSourceSurface failed to map"); break; } IntSize size = dSurf->GetSize(); wr::ImageDescriptor descriptor(size, map.mStride, dSurf->GetFormat()); auto slice = Range<uint8_t>(map.mData, size.height * map.mStride); mApi->AddImage(keys[0], descriptor, slice); dSurf->Unmap(); break; } case WebRenderParentCommand::TOpUpdateAsyncImagePipeline: { const OpUpdateAsyncImagePipeline& op = cmd.get_OpUpdateAsyncImagePipeline(); mAsyncImageManager->UpdateAsyncImagePipeline(op.pipelineId(), op.scBounds(), op.scTransform(), op.scaleToSize(), op.filter(), op.mixBlendMode()); break; } case WebRenderParentCommand::TCompositableOperation: { if (!ReceiveCompositableUpdate(cmd.get_CompositableOperation())) { NS_ERROR("ReceiveCompositableUpdate failed"); } break; } case WebRenderParentCommand::TOpAddCompositorAnimations: { const OpAddCompositorAnimations& op = cmd.get_OpAddCompositorAnimations(); CompositorAnimations data(Move(op.data())); if (data.animations().Length()) { mAnimStorage->SetAnimations(data.id(), data.animations()); mActiveAnimations.insert(data.id()); // Store the default opacity if (op.opacity().type() == OptionalOpacity::Tfloat) { mAnimStorage->SetAnimatedValue(data.id(), op.opacity().get_float()); } // Store the default transform if (op.transform().type() == OptionalTransform::TMatrix4x4) { Matrix4x4 transform(Move(op.transform().get_Matrix4x4())); mAnimStorage->SetAnimatedValue(data.id(), Move(transform)); } } break; } default: { // other commands are handle on the child break; } } } }
already_AddRefed<gfx::SourceSurface> D3D11ShareHandleImage::GetAsSourceSurface() { if (!mTexture) { NS_WARNING("Cannot readback from shared texture because no texture is available."); return nullptr; } RefPtr<ID3D11Device> device; mTexture->GetDevice(byRef(device)); RefPtr<IDXGIKeyedMutex> keyedMutex; if (FAILED(mTexture->QueryInterface(static_cast<IDXGIKeyedMutex**>(byRef(keyedMutex))))) { NS_WARNING("Failed to QueryInterface for IDXGIKeyedMutex, strange."); return nullptr; } if (FAILED(keyedMutex->AcquireSync(0, 0))) { NS_WARNING("Failed to acquire sync for keyedMutex, plugin failed to release?"); return nullptr; } D3D11_TEXTURE2D_DESC desc; mTexture->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; HRESULT hr = device->CreateTexture2D(&softDesc, NULL, static_cast<ID3D11Texture2D**>(byRef(softTexture))); if (FAILED(hr)) { NS_WARNING("Failed to create 2D staging texture."); keyedMutex->ReleaseSync(0); return nullptr; } RefPtr<ID3D11DeviceContext> context; device->GetImmediateContext(byRef(context)); if (!context) { keyedMutex->ReleaseSync(0); return nullptr; } context->CopyResource(softTexture, mTexture); keyedMutex->ReleaseSync(0); RefPtr<gfx::DataSourceSurface> surface = gfx::Factory::CreateDataSourceSurface(mSize, gfx::SurfaceFormat::B8G8R8X8); 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(); }
NS_IMETHODIMP AsyncFaviconDataReady::OnComplete(nsIURI *aFaviconURI, uint32_t aDataLen, const uint8_t *aData, const nsACString &aMimeType) { if (!aDataLen || !aData) { if (mURLShortcut) { OnFaviconDataNotAvailable(); } return NS_OK; } nsCOMPtr<nsIFile> icoFile; nsresult rv = FaviconHelper::GetOutputIconPath(mNewURI, icoFile, mURLShortcut); NS_ENSURE_SUCCESS(rv, rv); nsAutoString path; rv = icoFile->GetPath(path); NS_ENSURE_SUCCESS(rv, rv); // Convert the obtained favicon data to an input stream nsCOMPtr<nsIInputStream> stream; rv = NS_NewByteInputStream(getter_AddRefs(stream), reinterpret_cast<const char*>(aData), aDataLen, NS_ASSIGNMENT_DEPEND); NS_ENSURE_SUCCESS(rv, rv); // Decode the image from the format it was returned to us in (probably PNG) nsAutoCString mimeTypeOfInputData; mimeTypeOfInputData.AssignLiteral("image/vnd.microsoft.icon"); nsCOMPtr<imgIContainer> container; nsCOMPtr<imgITools> imgtool = do_CreateInstance("@mozilla.org/image/tools;1"); rv = imgtool->DecodeImageData(stream, aMimeType, getter_AddRefs(container)); NS_ENSURE_SUCCESS(rv, rv); nsRefPtr<gfxASurface> imgFrame = container->GetFrame(imgIContainer::FRAME_FIRST, 0); NS_ENSURE_TRUE(imgFrame, NS_ERROR_FAILURE); RefPtr<SourceSurface> surface = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(nullptr, imgFrame); NS_ENSURE_TRUE(surface, NS_ERROR_FAILURE); RefPtr<DataSourceSurface> dataSurface; IntSize size; if (mURLShortcut) { // Create a 48x48 surface and paint the icon into the central 16x16 rect. size.width = 48; size.height = 48; dataSurface = Factory::CreateDataSourceSurface(size, SurfaceFormat::B8G8R8A8); NS_ENSURE_TRUE(dataSurface, 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, dataSurface->GetFormat()); dt->FillRect(Rect(0, 0, size.width, size.height), ColorPattern(Color(1.0f, 1.0f, 1.0f, 1.0f))); dt->DrawSurface(surface, Rect(16, 16, 16, 16), Rect(Point(0, 0), Size(surface->GetSize().width, surface->GetSize().height))); dataSurface->Unmap(); } else { size.width = GetSystemMetrics(SM_CXSMICON); size.height = GetSystemMetrics(SM_CYSMICON); if (!size.width || !size.height) { size.width = 16; size.height = 16; } dataSurface = surface->GetDataSurface(); } // Allocate a new buffer that we own and can use out of line in // another thread. uint8_t *data = SurfaceToPackedBGRA(dataSurface); if (!data) { return NS_ERROR_OUT_OF_MEMORY; } int32_t stride = 4 * size.width; int32_t dataLength = stride * size.height; // AsyncEncodeAndWriteIcon takes ownership of the heap allocated buffer nsCOMPtr<nsIRunnable> event = new AsyncEncodeAndWriteIcon(path, data, dataLength, stride, size.width, size.height, mURLShortcut); mIOThread->Dispatch(event, NS_DISPATCH_NORMAL); return NS_OK; }
/* static */ nsresult ImageEncoder::ExtractDataInternal(const nsAString& aType, const nsAString& aOptions, uint8_t* aImageBuffer, int32_t aFormat, const nsIntSize aSize, 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 { // 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; }
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) { gfxCriticalError() << "Failed to get immediate 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(); }
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); 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->CopySurface(frame, IntRect(aOffsetX, aOffsetY, aWidth, aHeight), IntPoint(0, 0)); dataSurface->Unmap(); return EncodeImageData(dataSurface, aMimeType, aOutputOptions, aStream); }
/* static */ nsresult ImageEncoder::ExtractDataInternal(const nsAString& aType, const nsAString& aOptions, uint8_t* aImageBuffer, int32_t aFormat, const nsIntSize aSize, layers::Image* aImage, nsICanvasRenderingContextInternal* aContext, layers::AsyncCanvasRenderer* aRenderer, 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 (aRenderer) { NS_ConvertUTF16toUTF8 encoderType(aType); rv = aRenderer->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 = SurfaceFormat::A8R8G8B8_UINT32; 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; RefPtr<layers::Image> image(aImage); dataSurface = GetBRGADataSourceSurfaceSync(image.forget()); 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; }
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); } // Retrieve the image's size. int32_t imageWidth = 0; int32_t imageHeight = 0; aContainer->GetWidth(&imageWidth); aContainer->GetHeight(&imageHeight); // If the given width or height is zero we'll replace it with the image's // original dimensions. IntSize scaledSize(aScaledWidth == 0 ? imageWidth : aScaledWidth, aScaledHeight == 0 ? imageHeight : aScaledHeight); // Use frame 0 from the image container. RefPtr<SourceSurface> frame = aContainer->GetFrameAtSize(scaledSize, imgIContainer::FRAME_FIRST, imgIContainer::FLAG_HIGH_QUALITY_SCALING | imgIContainer::FLAG_SYNC_DECODE); NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE); RefPtr<DataSourceSurface> dataSurface = Factory::CreateDataSourceSurface(scaledSize, 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); if (!dt) { gfxWarning() << "imgTools::EncodeImage failed in CreateDrawTargetForData"; return NS_ERROR_OUT_OF_MEMORY; } IntSize frameSize = frame->GetSize(); dt->DrawSurface(frame, Rect(0, 0, scaledSize.width, scaledSize.height), Rect(0, 0, frameSize.width, frameSize.height), DrawSurfaceOptions(), DrawOptions(1.0f, CompositionOp::OP_SOURCE)); dataSurface->Unmap(); return EncodeImageData(dataSurface, aMimeType, aOutputOptions, aStream); }
nsresult nsWindowGfx::CreateIcon(imgIContainer *aContainer, bool aIsCursor, uint32_t aHotspotX, uint32_t aHotspotY, IntSize aScaledSize, HICON *aIcon) { MOZ_ASSERT((aScaledSize.width > 0 && aScaledSize.height > 0) || (aScaledSize.width == 0 && aScaledSize.height == 0)); // Get the image data RefPtr<SourceSurface> surface = aContainer->GetFrame(imgIContainer::FRAME_CURRENT, imgIContainer::FLAG_SYNC_DECODE); NS_ENSURE_TRUE(surface, NS_ERROR_NOT_AVAILABLE); IntSize frameSize = surface->GetSize(); if (frameSize.IsEmpty()) { return NS_ERROR_FAILURE; } IntSize iconSize(aScaledSize.width, aScaledSize.height); if (iconSize == IntSize(0, 0)) { // use frame's intrinsic size iconSize = frameSize; } RefPtr<DataSourceSurface> dataSurface; bool mappedOK; DataSourceSurface::MappedSurface map; if (iconSize != frameSize) { // Scale the surface dataSurface = Factory::CreateDataSourceSurface(iconSize, SurfaceFormat::B8G8R8A8); NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE); mappedOK = dataSurface->Map(DataSourceSurface::MapType::READ_WRITE, &map); NS_ENSURE_TRUE(mappedOK, NS_ERROR_FAILURE); RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(BackendType::CAIRO, map.mData, dataSurface->GetSize(), map.mStride, SurfaceFormat::B8G8R8A8); if (!dt) { gfxWarning() << "nsWindowGfx::CreatesIcon failed in CreateDrawTargetForData"; return NS_ERROR_OUT_OF_MEMORY; } dt->DrawSurface(surface, Rect(0, 0, iconSize.width, iconSize.height), Rect(0, 0, frameSize.width, frameSize.height), DrawSurfaceOptions(), DrawOptions(1.0f, CompositionOp::OP_SOURCE)); } else if (surface->GetFormat() != SurfaceFormat::B8G8R8A8) { // Convert format to SurfaceFormat::B8G8R8A8 dataSurface = gfxUtils:: CopySurfaceToDataSourceSurfaceWithFormat(surface, SurfaceFormat::B8G8R8A8); NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE); mappedOK = dataSurface->Map(DataSourceSurface::MapType::READ, &map); } else { dataSurface = surface->GetDataSurface(); NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE); mappedOK = dataSurface->Map(DataSourceSurface::MapType::READ, &map); } NS_ENSURE_TRUE(dataSurface && mappedOK, NS_ERROR_FAILURE); MOZ_ASSERT(dataSurface->GetFormat() == SurfaceFormat::B8G8R8A8); uint8_t* data = nullptr; UniquePtr<uint8_t[]> autoDeleteArray; if (map.mStride == BytesPerPixel(dataSurface->GetFormat()) * iconSize.width) { // Mapped data is already packed data = map.mData; } else { // We can't use map.mData since the pixels are not packed (as required by // CreateDIBitmap, which is called under the DataToBitmap call below). // // We must unmap before calling SurfaceToPackedBGRA because it needs access // to the pixel data. dataSurface->Unmap(); map.mData = nullptr; autoDeleteArray = SurfaceToPackedBGRA(dataSurface); data = autoDeleteArray.get(); NS_ENSURE_TRUE(data, NS_ERROR_FAILURE); } HBITMAP bmp = DataToBitmap(data, iconSize.width, -iconSize.height, 32); uint8_t* a1data = Data32BitTo1Bit(data, iconSize.width, iconSize.height); if (map.mData) { dataSurface->Unmap(); } if (!a1data) { return NS_ERROR_FAILURE; } HBITMAP mbmp = DataToBitmap(a1data, iconSize.width, -iconSize.height, 1); PR_Free(a1data); ICONINFO info = {0}; info.fIcon = !aIsCursor; info.xHotspot = aHotspotX; info.yHotspot = aHotspotY; info.hbmMask = mbmp; info.hbmColor = bmp; HCURSOR icon = ::CreateIconIndirect(&info); ::DeleteObject(mbmp); ::DeleteObject(bmp); if (!icon) return NS_ERROR_FAILURE; *aIcon = icon; return NS_OK; }
NS_IMETHODIMP AsyncFaviconDataReady::OnComplete(nsIURI *aFaviconURI, uint32_t aDataLen, const uint8_t *aData, const nsACString &aMimeType) { if (!aDataLen || !aData) { if (mURLShortcut) { OnFaviconDataNotAvailable(); } return NS_OK; } nsCOMPtr<nsIFile> icoFile; nsresult rv = FaviconHelper::GetOutputIconPath(mNewURI, icoFile, mURLShortcut); NS_ENSURE_SUCCESS(rv, rv); nsAutoString path; rv = icoFile->GetPath(path); NS_ENSURE_SUCCESS(rv, rv); // Convert the obtained favicon data to an input stream nsCOMPtr<nsIInputStream> stream; rv = NS_NewByteInputStream(getter_AddRefs(stream), reinterpret_cast<const char*>(aData), aDataLen, NS_ASSIGNMENT_DEPEND); NS_ENSURE_SUCCESS(rv, rv); // Decode the image from the format it was returned to us in (probably PNG) nsCOMPtr<imgIContainer> container; nsCOMPtr<imgITools> imgtool = do_CreateInstance("@mozilla.org/image/tools;1"); rv = imgtool->DecodeImageData(stream, aMimeType, getter_AddRefs(container)); NS_ENSURE_SUCCESS(rv, rv); RefPtr<SourceSurface> surface = container->GetFrame(imgIContainer::FRAME_FIRST, imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_ASYNC_NOTIFY); NS_ENSURE_TRUE(surface, NS_ERROR_FAILURE); RefPtr<DataSourceSurface> dataSurface; IntSize size; if (mURLShortcut) { // Create a 48x48 surface and paint the icon into the central 16x16 rect. size.width = 48; size.height = 48; dataSurface = Factory::CreateDataSourceSurface(size, SurfaceFormat::B8G8R8A8); NS_ENSURE_TRUE(dataSurface, 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, dataSurface->GetFormat()); if (!dt) { gfxWarning() << "AsyncFaviconDataReady::OnComplete failed in CreateDrawTargetForData"; return NS_ERROR_OUT_OF_MEMORY; } dt->FillRect(Rect(0, 0, size.width, size.height), ColorPattern(Color(1.0f, 1.0f, 1.0f, 1.0f))); dt->DrawSurface(surface, Rect(16, 16, 16, 16), Rect(Point(0, 0), Size(surface->GetSize().width, surface->GetSize().height))); dataSurface->Unmap(); } else { // By using the input image surface's size, we may end up encoding // to a different size than a 16x16 (or bigger for higher DPI) ICO, but // Windows will resize appropriately for us. If we want to encode ourselves // one day because we like our resizing better, we'd have to manually // resize the image here and use GetSystemMetrics w/ SM_CXSMICON and // SM_CYSMICON. We don't support resizing images asynchronously at the // moment anyway so getting the DPI aware icon size won't help. size.width = surface->GetSize().width; size.height = surface->GetSize().height; dataSurface = surface->GetDataSurface(); NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE); } // Allocate a new buffer that we own and can use out of line in // another thread. UniquePtr<uint8_t[]> data = SurfaceToPackedBGRA(dataSurface); if (!data) { return NS_ERROR_OUT_OF_MEMORY; } int32_t stride = 4 * size.width; int32_t dataLength = stride * size.height; // AsyncEncodeAndWriteIcon takes ownership of the heap allocated buffer nsCOMPtr<nsIRunnable> event = new AsyncEncodeAndWriteIcon(path, Move(data), dataLength, stride, size.width, size.height, mURLShortcut); mIOThread->Dispatch(event, NS_DISPATCH_NORMAL); return NS_OK; }
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); 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; }
already_AddRefed<gfx::SourceSurface> D3D9SurfaceImage::GetAsSourceSurface() { NS_ENSURE_TRUE(mTextureClient, nullptr); HRESULT hr; RefPtr<gfx::DataSourceSurface> surface = gfx::Factory::CreateDataSourceSurface(mSize, gfx::SurfaceFormat::B8G8R8X8); if (NS_WARN_IF(!surface)) { return nullptr; } // Ensure that the texture is ready to be used. EnsureSynchronized(); // Readback the texture from GPU memory into system memory, so that // we can copy it into the Cairo image. This is expensive. RefPtr<IDirect3DSurface9> textureSurface = mTextureClient->GetD3D9Surface(); if (!textureSurface) { return nullptr; } RefPtr<IDirect3DDevice9> device = mTextureClient->GetD3D9Device(); if (!device) { return nullptr; } RefPtr<IDirect3DSurface9> systemMemorySurface; hr = device->CreateOffscreenPlainSurface(mSize.width, mSize.height, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, byRef(systemMemorySurface), 0); NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr); hr = device->GetRenderTargetData(textureSurface, systemMemorySurface); NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr); D3DLOCKED_RECT rect; hr = systemMemorySurface->LockRect(&rect, nullptr, 0); NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr); gfx::DataSourceSurface::MappedSurface mappedSurface; if (!surface->Map(gfx::DataSourceSurface::WRITE, &mappedSurface)) { systemMemorySurface->UnlockRect(); return nullptr; } const unsigned char* src = (const unsigned char*)(rect.pBits); const unsigned srcPitch = rect.Pitch; for (int y = 0; y < mSize.height; y++) { memcpy(mappedSurface.mData + mappedSurface.mStride * y, (unsigned char*)(src) + srcPitch * y, mSize.width * 4); } systemMemorySurface->UnlockRect(); surface->Unmap(); return surface.forget(); }
already_AddRefed<SourceSurface> MacIOSurfaceImage::GetAsSourceSurface() { RefPtr<DataSourceSurface> dataSurface; mSurface->Lock(); size_t bytesPerRow = mSurface->GetBytesPerRow(); size_t ioWidth = mSurface->GetDevicePixelWidth(); size_t ioHeight = mSurface->GetDevicePixelHeight(); SurfaceFormat format = mSurface->GetFormat() == SurfaceFormat::NV12 ? SurfaceFormat::B8G8R8X8 : SurfaceFormat::B8G8R8A8; dataSurface = Factory::CreateDataSourceSurface(IntSize(ioWidth, ioHeight), format); if (NS_WARN_IF(!dataSurface)) { return nullptr; } DataSourceSurface::MappedSurface mappedSurface; if (!dataSurface->Map(DataSourceSurface::WRITE, &mappedSurface)) return nullptr; if (mSurface->GetFormat() == SurfaceFormat::NV12) { if (mSurface->GetDevicePixelWidth() > PlanarYCbCrImage::MAX_DIMENSION || mSurface->GetDevicePixelHeight() > PlanarYCbCrImage::MAX_DIMENSION) { return nullptr; } /* Extract and separate the CbCr planes */ size_t cbCrStride = mSurface->GetBytesPerRow(1); size_t cbCrWidth = mSurface->GetDevicePixelWidth(1); size_t cbCrHeight = mSurface->GetDevicePixelHeight(1); auto cbPlane = MakeUnique<uint8_t[]>(cbCrWidth * cbCrHeight); auto crPlane = MakeUnique<uint8_t[]>(cbCrWidth * cbCrHeight); uint8_t* src = (uint8_t*)mSurface->GetBaseAddressOfPlane(1); uint8_t* cbDest = cbPlane.get(); uint8_t* crDest = crPlane.get(); for (size_t i = 0; i < cbCrHeight; i++) { uint8_t* rowSrc = src + cbCrStride * i; for (size_t j = 0; j < cbCrWidth; j++) { *cbDest = *rowSrc; cbDest++; rowSrc++; *crDest = *rowSrc; crDest++; rowSrc++; } } /* Convert to RGB */ PlanarYCbCrData data; data.mYChannel = (uint8_t*)mSurface->GetBaseAddressOfPlane(0); data.mYStride = mSurface->GetBytesPerRow(0); data.mYSize = IntSize(mSurface->GetDevicePixelWidth(0), mSurface->GetDevicePixelHeight(0)); data.mCbChannel = cbPlane.get(); data.mCrChannel = crPlane.get(); data.mCbCrStride = cbCrWidth; data.mCbCrSize = IntSize(cbCrWidth, cbCrHeight); data.mPicSize = data.mYSize; ConvertYCbCrToRGB(data, SurfaceFormat::B8G8R8X8, IntSize(ioWidth, ioHeight), mappedSurface.mData, mappedSurface.mStride); } else { unsigned char* ioData = (unsigned char*)mSurface->GetBaseAddress(); 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.forget(); }
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; }