void BasicTextureImage::EndUpdate() { NS_ASSERTION(!!mUpdateDrawTarget, "EndUpdate() without BeginUpdate()?"); // FIXME: this is the slow boat. Make me fast (with GLXPixmap?). RefPtr<gfx::SourceSurface> updateSnapshot = mUpdateDrawTarget->Snapshot(); RefPtr<gfx::DataSourceSurface> updateData = updateSnapshot->GetDataSurface(); bool relative = FinishedSurfaceUpdate(); mTextureFormat = UploadSurfaceToTexture(mGLContext, updateData, mUpdateRegion, mTexture, mTextureState == Created, mUpdateOffset, relative); FinishedSurfaceUpload(); mUpdateDrawTarget = nullptr; mTextureState = Valid; }
/* static */ already_AddRefed<ImageBitmap> ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLCanvasElement& aCanvasEl, const Maybe<IntRect>& aCropRect, ErrorResult& aRv) { if (aCanvasEl.Width() == 0 || aCanvasEl.Height() == 0) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return nullptr; } RefPtr<SourceSurface> surface = GetSurfaceFromElement(aGlobal, aCanvasEl, aRv); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } // Crop the source surface if needed. RefPtr<SourceSurface> croppedSurface; IntRect cropRect = aCropRect.valueOr(IntRect()); // If the HTMLCanvasElement's rendering context is WebGL, then the snapshot // we got from the HTMLCanvasElement is a DataSourceSurface which is a copy // of the rendering context. We handle cropping in this case. if ((aCanvasEl.GetCurrentContextType() == CanvasContextType::WebGL1 || aCanvasEl.GetCurrentContextType() == CanvasContextType::WebGL2) && aCropRect.isSome()) { // The _surface_ must be a DataSourceSurface. MOZ_ASSERT(surface->GetType() == SurfaceType::DATA, "The snapshot SourceSurface from WebGL rendering contest is not \ DataSourceSurface."); RefPtr<DataSourceSurface> dataSurface = surface->GetDataSurface(); croppedSurface = CropAndCopyDataSourceSurface(dataSurface, cropRect); cropRect.MoveTo(0, 0); }
NS_IMETHODIMP imgTools::EncodeImage(imgIContainer* aContainer, const nsACString& aMimeType, const nsAString& aOutputOptions, nsIInputStream** 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); RefPtr<DataSourceSurface> dataSurface; if (frame->GetFormat() == SurfaceFormat::B8G8R8A8) { dataSurface = frame->GetDataSurface(); } else { // Convert format to SurfaceFormat::B8G8R8A8 dataSurface = gfxUtils:: CopySurfaceToDataSourceSurfaceWithFormat(frame, SurfaceFormat::B8G8R8A8); } NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE); return EncodeImageData(dataSurface, aMimeType, aOutputOptions, aStream); }
void TextureImageEGL::EndUpdate() { NS_ASSERTION(!!mUpdateDrawTarget, "EndUpdate() without BeginUpdate()?"); //printf_stderr("EndUpdate: slow path"); // This is the slower path -- we didn't have any way to set up // a fast mapping between our cairo target surface and the GL // texture, so we have to upload data. RefPtr<gfx::SourceSurface> updateSurface = nullptr; RefPtr<gfx::DataSourceSurface> uploadImage = nullptr; gfx::IntSize updateSize(mUpdateRect.width, mUpdateRect.height); NS_ASSERTION(mUpdateDrawTarget->GetSize() == updateSize, "Upload image is the wrong size!"); updateSurface = mUpdateDrawTarget->Snapshot(); uploadImage = updateSurface->GetDataSurface(); if (!uploadImage) { return; } mGLContext->MakeCurrent(); mGLContext->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture); if (mTextureState != Valid) { NS_ASSERTION(mUpdateRect.x == 0 && mUpdateRect.y == 0 && mUpdateRect.Size() == mSize, "Bad initial update on non-created texture!"); mGLContext->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, GLFormatForImage(mUpdateFormat), mUpdateRect.width, mUpdateRect.height, 0, GLFormatForImage(uploadImage->GetFormat()), GLTypeForImage(uploadImage->GetFormat()), uploadImage->GetData()); } else { mGLContext->fTexSubImage2D(LOCAL_GL_TEXTURE_2D, 0, mUpdateRect.x, mUpdateRect.y, mUpdateRect.width, mUpdateRect.height, GLFormatForImage(uploadImage->GetFormat()), GLTypeForImage(uploadImage->GetFormat()), uploadImage->GetData()); } mUpdateDrawTarget = nullptr; mTextureState = Valid; return; // mTexture is bound }
static nsresult ConvertSourceSurfaceToNV12(const RefPtr<SourceSurface>& aSurface, uint8_t* aDestination) { if (!aSurface) { CODEC_ERROR("Getting surface from image failed"); return NS_ERROR_FAILURE; } uint32_t width = aSurface->GetSize().width; uint32_t height = aSurface->GetSize().height; uint8_t* y = aDestination; int yStride = width; uint8_t* uv = y + (yStride * height); int uvStride = width / 2; RefPtr<DataSourceSurface> data = aSurface->GetDataSurface(); if (!data) { CODEC_ERROR("Getting data surface from %s image with %s surface failed", Stringify(aSurface->GetFormat()).c_str(), Stringify(aSurface->GetType()).c_str()); return NS_ERROR_FAILURE; } DataSourceSurface::ScopedMap map(data, DataSourceSurface::READ); if (!map.IsMapped()) { CODEC_ERROR("Reading DataSourceSurface from %s image with %s surface failed", Stringify(aSurface->GetFormat()).c_str(), Stringify(aSurface->GetType()).c_str()); return NS_ERROR_FAILURE; } int rv; switch (aSurface->GetFormat()) { case SurfaceFormat::B8G8R8A8: case SurfaceFormat::B8G8R8X8: rv = libyuv::ARGBToNV12(static_cast<uint8*>(map.GetData()), map.GetStride(), y, yStride, uv, uvStride, width, height); break; default: CODEC_ERROR("Unsupported SourceSurface format %s", Stringify(aSurface->GetFormat()).c_str()); NS_ASSERTION(false, "Unsupported SourceSurface format"); return NS_ERROR_NOT_IMPLEMENTED; } if (rv != 0) { CODEC_ERROR("%s to I420 conversion failed", Stringify(aSurface->GetFormat()).c_str()); return NS_ERROR_FAILURE; } return NS_OK; }
ImageBitmapCloneData* ImageBitmap::ToCloneData() { ImageBitmapCloneData* result = new ImageBitmapCloneData(); result->mPictureRect = mPictureRect; RefPtr<SourceSurface> surface = mData->GetAsSourceSurface(); result->mSurface = surface->GetDataSurface(); MOZ_ASSERT(result->mSurface); return result; }
nsresult nsDragServiceProxy::InvokeDragSessionImpl(nsIArray* aArrayTransferables, nsIScriptableRegion* aRegion, uint32_t aActionType) { nsCOMPtr<nsIDocument> doc = do_QueryInterface(mSourceDocument); NS_ENSURE_STATE(doc->GetDocShell()); TabChild* child = TabChild::GetFrom(doc->GetDocShell()); NS_ENSURE_STATE(child); nsTArray<mozilla::dom::IPCDataTransfer> dataTransfers; nsContentUtils::TransferablesToIPCTransferables(aArrayTransferables, dataTransfers, false, child->Manager(), nullptr); LayoutDeviceIntRect dragRect; if (mHasImage || mSelection) { nsPresContext* pc; RefPtr<mozilla::gfx::SourceSurface> surface; DrawDrag(mSourceNode, aRegion, mScreenPosition, &dragRect, &surface, &pc); if (surface) { RefPtr<mozilla::gfx::DataSourceSurface> dataSurface = surface->GetDataSurface(); if (dataSurface) { size_t length; int32_t stride; Shmem surfaceData; nsContentUtils::GetSurfaceData(dataSurface, &length, &stride, child, &surfaceData); // Save the surface data to shared memory. if (!surfaceData.IsReadable() || !surfaceData.get<char>()) { NS_WARNING("Failed to create shared memory for drag session."); return NS_ERROR_FAILURE; } mozilla::Unused << child->SendInvokeDragSession(dataTransfers, aActionType, surfaceData, stride, static_cast<uint8_t>(dataSurface->GetFormat()), dragRect); StartDragSession(); return NS_OK; } } } mozilla::Unused << child->SendInvokeDragSession(dataTransfers, aActionType, mozilla::void_t(), 0, 0, dragRect); StartDragSession(); return NS_OK; }
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(); }
NS_IMETHODIMP PuppetWidget::SetCursor(imgIContainer* aCursor, uint32_t aHotspotX, uint32_t aHotspotY) { if (!aCursor || !mTabChild) { return NS_OK; } #if !defined(XP_WIN) if (mCustomCursor == aCursor && mCursorHotspotX == aHotspotX && mCursorHotspotY == aHotspotY && !mUpdateCursor) { return NS_OK; } #endif RefPtr<mozilla::gfx::SourceSurface> surface = aCursor->GetFrame(imgIContainer::FRAME_CURRENT, imgIContainer::FLAG_SYNC_DECODE); if (!surface) { return NS_ERROR_FAILURE; } RefPtr<mozilla::gfx::DataSourceSurface> dataSurface = surface->GetDataSurface(); if (!dataSurface) { return NS_ERROR_FAILURE; } size_t length; int32_t stride; mozilla::UniquePtr<char[]> surfaceData = nsContentUtils::GetSurfaceData(WrapNotNull(dataSurface), &length, &stride); nsDependentCString cursorData(surfaceData.get(), length); mozilla::gfx::IntSize size = dataSurface->GetSize(); if (!mTabChild->SendSetCustomCursor(cursorData, size.width, size.height, stride, static_cast<uint8_t>(dataSurface->GetFormat()), aHotspotX, aHotspotY, mUpdateCursor)) { return NS_ERROR_FAILURE; } mCursor = nsCursor(-1); mCustomCursor = aCursor; mCursorHotspotX = aHotspotX; mCursorHotspotY = aHotspotY; mUpdateCursor = false; return NS_OK; }
nsresult nsDragServiceProxy::InvokeDragSessionImpl(nsISupportsArray* aArrayTransferables, nsIScriptableRegion* aRegion, uint32_t aActionType) { nsCOMPtr<nsIDocument> doc = do_QueryInterface(mSourceDocument); NS_ENSURE_STATE(doc->GetDocShell()); mozilla::dom::TabChild* child = mozilla::dom::TabChild::GetFrom(doc->GetDocShell()); NS_ENSURE_STATE(child); nsTArray<mozilla::dom::IPCDataTransfer> dataTransfers; nsContentUtils::TransferablesToIPCTransferables(aArrayTransferables, dataTransfers, false, child->Manager(), nullptr); if (mHasImage || mSelection) { nsIntRect dragRect; nsPresContext* pc; RefPtr<mozilla::gfx::SourceSurface> surface; DrawDrag(mSourceNode, aRegion, mScreenX, mScreenY, &dragRect, &surface, &pc); if (surface) { RefPtr<mozilla::gfx::DataSourceSurface> dataSurface = surface->GetDataSurface(); mozilla::gfx::IntSize size = dataSurface->GetSize(); size_t length; int32_t stride; mozilla::UniquePtr<char[]> surfaceData = nsContentUtils::GetSurfaceData(dataSurface, &length, &stride); nsDependentCString dragImage(surfaceData.get(), length); mozilla::unused << child->SendInvokeDragSession(dataTransfers, aActionType, dragImage, size.width, size.height, stride, static_cast<uint8_t>(dataSurface->GetFormat()), dragRect.x, dragRect.y); StartDragSession(); return NS_OK; } } mozilla::unused << child->SendInvokeDragSession(dataTransfers, aActionType, nsCString(), 0, 0, 0, 0, 0, 0); StartDragSession(); return NS_OK; }
void TiledTextureImage::EndUpdate() { NS_ASSERTION(mInUpdate, "EndUpdate not in update"); if (!mUpdateDrawTarget) { // update was to a single TextureImage mImages[mCurrentImage]->EndUpdate(); mInUpdate = false; mTextureState = Valid; mTextureFormat = mImages[mCurrentImage]->GetTextureFormat(); return; } RefPtr<gfx::SourceSurface> updateSnapshot = mUpdateDrawTarget->Snapshot(); RefPtr<gfx::DataSourceSurface> updateData = updateSnapshot->GetDataSurface(); // upload tiles from temp surface for (unsigned i = 0; i < mImages.Length(); i++) { int xPos = (i % mColumns) * mTileSize; int yPos = (i / mColumns) * mTileSize; IntRect imageRect = IntRect(IntPoint(xPos,yPos), mImages[i]->GetSize()); nsIntRegion subregion; subregion.And(mUpdateRegion, imageRect); if (subregion.IsEmpty()) continue; subregion.MoveBy(-xPos, -yPos); // Tile-local space // copy tile from temp target gfx::DrawTarget* drawTarget = mImages[i]->BeginUpdate(subregion); MOZ_ASSERT(drawTarget->GetBackendType() == BackendType::CAIRO, "updateSnapshot should not have been converted to data"); gfxUtils::ClipToRegion(drawTarget, subregion); Size size(updateData->GetSize().width, updateData->GetSize().height); drawTarget->DrawSurface(updateData, Rect(Point(-xPos, -yPos), size), Rect(Point(0, 0), size), DrawSurfaceOptions(), DrawOptions(1.0, CompositionOp::OP_SOURCE, AntialiasMode::NONE)); drawTarget->PopClip(); mImages[i]->EndUpdate(); } mUpdateDrawTarget = nullptr; mInUpdate = false; mTextureFormat = mImages[0]->GetTextureFormat(); mTextureState = Valid; }
already_AddRefed<gfxASurface> gfxPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget) { // If we have already created a thebes surface, we can just return it. void *surface = aTarget->GetUserData(&kThebesSurfaceKey); if (surface) { nsRefPtr<gfxASurface> surf = static_cast<gfxASurface*>(surface); return surf.forget(); } nsRefPtr<gfxASurface> surf; if (aTarget->GetType() == BACKEND_CAIRO) { cairo_surface_t* csurf = static_cast<cairo_surface_t*>(aTarget->GetNativeSurface(NATIVE_SURFACE_CAIRO_SURFACE)); surf = gfxASurface::Wrap(csurf); } else { // The semantics of this part of the function are sort of weird. If we // don't have direct support for the backend, we snapshot the first time // and then return the snapshotted surface for the lifetime of the draw // target. Sometimes it seems like this works out, but it seems like it // might result in no updates ever. RefPtr<SourceSurface> source = aTarget->Snapshot(); RefPtr<DataSourceSurface> data = source->GetDataSurface(); if (!data) { return NULL; } IntSize size = data->GetSize(); gfxASurface::gfxImageFormat format = gfxASurface::FormatFromContent(ContentForFormat(data->GetFormat())); // We need to make a copy here because data might change its data under us nsRefPtr<gfxImageSurface> imageSurf = new gfxImageSurface(gfxIntSize(size.width, size.height), format, false); bool resultOfCopy = imageSurf->CopyFrom(source); NS_ASSERTION(resultOfCopy, "Failed to copy surface."); surf = imageSurf; } // add a reference to be held by the drawTarget // careful, the reference graph is getting complicated here surf->AddRef(); aTarget->AddUserData(&kThebesSurfaceKey, surf.get(), DestroyThebesSurface); return surf.forget(); }
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; }
void DIBTextureClient::Unlock() { MOZ_ASSERT(mIsLocked, "Unlocked called while the texture is not locked!"); if (mDrawTarget) { if (mReadbackSink) { RefPtr<SourceSurface> snapshot = mDrawTarget->Snapshot(); RefPtr<DataSourceSurface> dataSurf = snapshot->GetDataSurface(); mReadbackSink->ProcessReadback(dataSurf); } mDrawTarget->Flush(); mDrawTarget = nullptr; } mIsLocked = false; }
already_AddRefed<gfx::DataSourceSurface> X11TextureHost::GetAsSurface() { if (!mTextureSource || !mTextureSource->AsSourceBasic()) { return nullptr; } RefPtr<DrawTarget> tempDT = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget( GetSize(), GetFormat()); if (!tempDT) { return nullptr; } RefPtr<SourceSurface> surf = mTextureSource->AsSourceBasic()->GetSurface(tempDT); if (!surf) { return nullptr; } return surf->GetDataSurface(); }
already_AddRefed<gfxASurface> gfxPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget) { RefPtr<SourceSurface> source = aTarget->Snapshot(); RefPtr<DataSourceSurface> data = source->GetDataSurface(); if (!data) { return NULL; } IntSize size = data->GetSize(); gfxASurface::gfxImageFormat format = gfxASurface::FormatFromContent(ContentForFormat(data->GetFormat())); nsRefPtr<gfxImageSurface> image = new gfxImageSurface(data->GetData(), gfxIntSize(size.width, size.height), data->Stride(), format); image->SetData(&kDrawSourceSurface, data.forget().drop(), DataSourceSurfaceDestroy); return image.forget(); }
mozilla::UniquePtr<uint8_t[]> ImageBitmapRenderingContext::GetImageBuffer(int32_t* aFormat) { *aFormat = 0; if (!mImage) { return nullptr; } RefPtr<SourceSurface> surface = mImage->GetAsSourceSurface(); RefPtr<DataSourceSurface> data = surface->GetDataSurface(); if (!data) { return nullptr; } if (data->GetSize() != IntSize(mWidth, mHeight)) { data = MatchWithIntrinsicSize(); } *aFormat = imgIEncoder::INPUT_FORMAT_HOSTARGB; return SurfaceToPackedBGRA(data); }
void WriteSnapshotToDumpFile(Compositor* aCompositor, DrawTarget* aTarget) { RefPtr<SourceSurface> surf = aTarget->Snapshot(); RefPtr<DataSourceSurface> dSurf = surf->GetDataSurface(); WriteSnapshotToDumpFile_internal(aCompositor, dSurf); }
NS_IMETHODIMP nsClipboard::SetData(nsITransferable *aTransferable, nsIClipboardOwner *anOwner, int32_t aWhichClipboard) { if (aWhichClipboard != kGlobalClipboard) { return NS_ERROR_NOT_IMPLEMENTED; } if (!XRE_IsParentProcess()) { // Re-direct to the clipboard proxy. RefPtr<nsClipboardProxy> clipboardProxy = new nsClipboardProxy(); return clipboardProxy->SetData(aTransferable, anOwner, aWhichClipboard); } // Clear out the clipboard in order to set the new data. EmptyClipboard(aWhichClipboard); // Use a pref to toggle rich text/non-text support. if (Preferences::GetBool("clipboard.plainTextOnly")) { nsCOMPtr<nsISupports> clip; uint32_t len; nsresult rv = aTransferable->GetTransferData(kUnicodeMime, getter_AddRefs(clip), &len); if (NS_FAILED(rv)) { return rv; } nsCOMPtr<nsISupportsString> wideString = do_QueryInterface(clip); if (!wideString) { return NS_ERROR_NOT_IMPLEMENTED; } nsAutoString utf16string; wideString->GetData(utf16string); mClipboard->SetText(utf16string); return NS_OK; } // Get the types of supported flavors. nsCOMPtr<nsISupportsArray> flavorList; nsresult rv = aTransferable->FlavorsTransferableCanExport(getter_AddRefs(flavorList)); if (!flavorList || NS_FAILED(rv)) { return NS_ERROR_FAILURE; } uint32_t flavorCount = 0; flavorList->Count(&flavorCount); bool imageAdded = false; for (uint32_t i = 0; i < flavorCount; ++i) { nsCOMPtr<nsISupportsCString> currentFlavor = do_QueryElementAt(flavorList, i); if (currentFlavor) { // MIME type nsXPIDLCString flavorStr; currentFlavor->ToString(getter_Copies(flavorStr)); // Clip is the data which will be sent to the clipboard. nsCOMPtr<nsISupports> clip; uint32_t len; if (flavorStr.EqualsLiteral(kUnicodeMime)) { // text/plain rv = aTransferable->GetTransferData(flavorStr, getter_AddRefs(clip), &len); nsCOMPtr<nsISupportsString> wideString = do_QueryInterface(clip); if (!wideString || NS_FAILED(rv)) { continue; } nsAutoString utf16string; wideString->GetData(utf16string); mClipboard->SetText(utf16string); } else if (flavorStr.EqualsLiteral(kHTMLMime)) { // text/html rv = aTransferable->GetTransferData(flavorStr, getter_AddRefs(clip), &len); nsCOMPtr<nsISupportsString> wideString = do_QueryInterface(clip); if (!wideString || NS_FAILED(rv)) { continue; } nsAutoString utf16string; wideString->GetData(utf16string); mClipboard->SetHTML(utf16string); } else if (!imageAdded && // image is added only once to the clipboard. (flavorStr.EqualsLiteral(kNativeImageMime) || flavorStr.EqualsLiteral(kPNGImageMime) || flavorStr.EqualsLiteral(kJPEGImageMime) || flavorStr.EqualsLiteral(kJPGImageMime))) { // image/[png|jpeg|jpg] or application/x-moz-nativeimage // Look through our transfer data for the image. static const char* const imageMimeTypes[] = { kNativeImageMime, kPNGImageMime, kJPEGImageMime, kJPGImageMime }; nsCOMPtr<nsISupportsInterfacePointer> imgPtr; for (uint32_t i = 0; !imgPtr && i < ArrayLength(imageMimeTypes); ++i) { aTransferable->GetTransferData(imageMimeTypes[i], getter_AddRefs(clip), &len); imgPtr = do_QueryInterface(clip); } if (!imgPtr) { continue; } nsCOMPtr<nsISupports> imageData; imgPtr->GetData(getter_AddRefs(imageData)); nsCOMPtr<imgIContainer> image(do_QueryInterface(imageData)); if (!image) { continue; } RefPtr<gfx::SourceSurface> surface = image->GetFrame(imgIContainer::FRAME_CURRENT, imgIContainer::FLAG_SYNC_DECODE); if (!surface) { continue; } RefPtr<gfx::DataSourceSurface> dataSurface; if (surface->GetFormat() == gfx::SurfaceFormat::B8G8R8A8) { dataSurface = surface->GetDataSurface(); } else { // Convert format to SurfaceFormat::B8G8R8A8. dataSurface = gfxUtils::CopySurfaceToDataSourceSurfaceWithFormat(surface, gfx::SurfaceFormat::B8G8R8A8); } mClipboard->SetImage(dataSurface); imageAdded = true; } } } 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) 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; }
nsresult VP8TrackEncoder::PrepareRawFrame(VideoChunk &aChunk) { RefPtr<Image> img; if (aChunk.mFrame.GetForceBlack() || aChunk.IsNull()) { if (!mMuteFrame) { mMuteFrame = VideoFrame::CreateBlackImage(gfx::IntSize(mFrameWidth, mFrameHeight)); MOZ_ASSERT(mMuteFrame); } img = mMuteFrame; } else { img = aChunk.mFrame.GetImage(); } if (img->GetSize() != IntSize(mFrameWidth, mFrameHeight)) { VP8LOG("Dynamic resolution changes (was %dx%d, now %dx%d) are unsupported\n", mFrameWidth, mFrameHeight, img->GetSize().width, img->GetSize().height); return NS_ERROR_FAILURE; } ImageFormat format = img->GetFormat(); if (format == ImageFormat::PLANAR_YCBCR) { PlanarYCbCrImage* yuv = static_cast<PlanarYCbCrImage *>(img.get()); MOZ_RELEASE_ASSERT(yuv); if (!yuv->IsValid()) { NS_WARNING("PlanarYCbCrImage is not valid"); return NS_ERROR_FAILURE; } const PlanarYCbCrImage::Data *data = yuv->GetData(); if (isYUV420(data) && !data->mCbSkip) { // 420 planar, no need for conversions mVPXImageWrapper->planes[VPX_PLANE_Y] = data->mYChannel; mVPXImageWrapper->planes[VPX_PLANE_U] = data->mCbChannel; mVPXImageWrapper->planes[VPX_PLANE_V] = data->mCrChannel; mVPXImageWrapper->stride[VPX_PLANE_Y] = data->mYStride; mVPXImageWrapper->stride[VPX_PLANE_U] = data->mCbCrStride; mVPXImageWrapper->stride[VPX_PLANE_V] = data->mCbCrStride; return NS_OK; } } // Not 420 planar, have to convert uint32_t yPlaneSize = mFrameWidth * mFrameHeight; uint32_t halfWidth = (mFrameWidth + 1) / 2; uint32_t halfHeight = (mFrameHeight + 1) / 2; uint32_t uvPlaneSize = halfWidth * halfHeight; if (mI420Frame.IsEmpty()) { mI420Frame.SetLength(yPlaneSize + uvPlaneSize * 2); } uint8_t *y = mI420Frame.Elements(); uint8_t *cb = mI420Frame.Elements() + yPlaneSize; uint8_t *cr = mI420Frame.Elements() + yPlaneSize + uvPlaneSize; if (format == ImageFormat::PLANAR_YCBCR) { PlanarYCbCrImage* yuv = static_cast<PlanarYCbCrImage *>(img.get()); MOZ_RELEASE_ASSERT(yuv); if (!yuv->IsValid()) { NS_WARNING("PlanarYCbCrImage is not valid"); return NS_ERROR_FAILURE; } const PlanarYCbCrImage::Data *data = yuv->GetData(); int rv; std::string yuvFormat; if (isYUV420(data) && data->mCbSkip) { // If mCbSkip is set, we assume it's nv12 or nv21. if (data->mCbChannel < data->mCrChannel) { // nv12 rv = libyuv::NV12ToI420(data->mYChannel, data->mYStride, data->mCbChannel, data->mCbCrStride, y, mFrameWidth, cb, halfWidth, cr, halfWidth, mFrameWidth, mFrameHeight); yuvFormat = "NV12"; } else { // nv21 rv = libyuv::NV21ToI420(data->mYChannel, data->mYStride, data->mCrChannel, data->mCbCrStride, y, mFrameWidth, cb, halfWidth, cr, halfWidth, mFrameWidth, mFrameHeight); yuvFormat = "NV21"; } } else if (isYUV444(data) && !data->mCbSkip) { rv = libyuv::I444ToI420(data->mYChannel, data->mYStride, data->mCbChannel, data->mCbCrStride, data->mCrChannel, data->mCbCrStride, y, mFrameWidth, cb, halfWidth, cr, halfWidth, mFrameWidth, mFrameHeight); yuvFormat = "I444"; } else if (isYUV422(data) && !data->mCbSkip) { rv = libyuv::I422ToI420(data->mYChannel, data->mYStride, data->mCbChannel, data->mCbCrStride, data->mCrChannel, data->mCbCrStride, y, mFrameWidth, cb, halfWidth, cr, halfWidth, mFrameWidth, mFrameHeight); yuvFormat = "I422"; } else { VP8LOG("Unsupported planar format\n"); NS_ASSERTION(false, "Unsupported planar format"); return NS_ERROR_NOT_IMPLEMENTED; } if (rv != 0) { VP8LOG("Converting an %s frame to I420 failed\n", yuvFormat.c_str()); return NS_ERROR_FAILURE; } VP8LOG("Converted an %s frame to I420\n"); } else { // Not YCbCr at all. Try to get access to the raw data and convert. RefPtr<SourceSurface> surf = img->GetAsSourceSurface(); if (!surf) { VP8LOG("Getting surface from %s image failed\n", Stringify(format).c_str()); return NS_ERROR_FAILURE; } RefPtr<DataSourceSurface> data = surf->GetDataSurface(); if (!data) { VP8LOG("Getting data surface from %s image with %s (%s) surface failed\n", Stringify(format).c_str(), Stringify(surf->GetType()).c_str(), Stringify(surf->GetFormat()).c_str()); return NS_ERROR_FAILURE; } DataSourceSurface::ScopedMap map(data, DataSourceSurface::READ); if (!map.IsMapped()) { VP8LOG("Reading DataSourceSurface from %s image with %s (%s) surface failed\n", Stringify(format).c_str(), Stringify(surf->GetType()).c_str(), Stringify(surf->GetFormat()).c_str()); return NS_ERROR_FAILURE; } int rv; switch (surf->GetFormat()) { case SurfaceFormat::B8G8R8A8: case SurfaceFormat::B8G8R8X8: rv = libyuv::ARGBToI420(static_cast<uint8*>(map.GetData()), map.GetStride(), y, mFrameWidth, cb, halfWidth, cr, halfWidth, mFrameWidth, mFrameHeight); break; case SurfaceFormat::R5G6B5_UINT16: rv = libyuv::RGB565ToI420(static_cast<uint8*>(map.GetData()), map.GetStride(), y, mFrameWidth, cb, halfWidth, cr, halfWidth, mFrameWidth, mFrameHeight); break; default: VP8LOG("Unsupported SourceSurface format %s\n", Stringify(surf->GetFormat()).c_str()); NS_ASSERTION(false, "Unsupported SourceSurface format"); return NS_ERROR_NOT_IMPLEMENTED; } if (rv != 0) { VP8LOG("%s to I420 conversion failed\n", Stringify(surf->GetFormat()).c_str()); return NS_ERROR_FAILURE; } VP8LOG("Converted a %s frame to I420\n", Stringify(surf->GetFormat()).c_str()); } mVPXImageWrapper->planes[VPX_PLANE_Y] = y; mVPXImageWrapper->planes[VPX_PLANE_U] = cb; mVPXImageWrapper->planes[VPX_PLANE_V] = cr; mVPXImageWrapper->stride[VPX_PLANE_Y] = mFrameWidth; mVPXImageWrapper->stride[VPX_PLANE_U] = halfWidth; mVPXImageWrapper->stride[VPX_PLANE_V] = halfWidth; 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, 0); 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. 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; }
already_AddRefed<DataSourceSurface> MacIOSurfaceTextureData::GetAsSurface() { RefPtr<SourceSurface> surf = CreateSourceSurfaceFromMacIOSurface(mSurface); return surf->GetDataSurface(); }
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; }
bool TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName, WebGLTexture* tex, TexImageTarget target, GLint level, const webgl::DriverUnpackInfo* dui, GLint xOffset, GLint yOffset, GLint zOffset, GLenum* const out_error) const { MOZ_ASSERT_IF(needsRespec, !isSubImage); WebGLContext* webgl = tex->mContext; gl::GLContext* gl = webgl->GL(); gl->MakeCurrent(); if (needsRespec) { *out_error = DoTexOrSubImage(isSubImage, gl, target.get(), level, dui, xOffset, yOffset, zOffset, mWidth, mHeight, mDepth, nullptr); if (*out_error) return false; } do { if (mDepth != 1) break; const bool isDstPremult = webgl->mPixelStore_PremultiplyAlpha; if (mIsSrcPremult != isDstPremult) break; if (dui->unpackFormat != LOCAL_GL_RGB && dui->unpackFormat != LOCAL_GL_RGBA) break; if (dui->unpackType != LOCAL_GL_UNSIGNED_BYTE) break; gl::ScopedFramebuffer scopedFB(gl); gl::ScopedBindFramebuffer bindFB(gl, scopedFB.FB()); { gl::GLContext::LocalErrorScope errorScope(*gl); gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, target.get(), tex->mGLName, level); if (errorScope.GetError()) break; } const GLenum status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) break; const gfx::IntSize destSize(mWidth, mHeight); const auto dstOrigin = (webgl->mPixelStore_FlipY ? gl::OriginPos::TopLeft : gl::OriginPos::BottomLeft); if (!gl->BlitHelper()->BlitImageToFramebuffer(mImage, destSize, scopedFB.FB(), dstOrigin)) { break; } // Blitting was successful, so we're done! *out_error = 0; return true; } while (false); webgl->GenerateWarning("%s: Failed to hit GPU-copy fast-path. Falling back to CPU" " upload.", funcName); const RefPtr<gfx::SourceSurface> surf = mImage->GetAsSourceSurface(); RefPtr<gfx::DataSourceSurface> dataSurf; if (surf) { // WARNING: OSX can lose our MakeCurrent here. dataSurf = surf->GetDataSurface(); } if (!dataSurf) { webgl->ErrorOutOfMemory("%s: GetAsSourceSurface or GetDataSurface failed after" " blit failed for TexUnpackImage.", funcName); return false; } const TexUnpackSurface surfBlob(webgl, target, mWidth, mHeight, mDepth, dataSurf, mIsSrcPremult); return surfBlob.TexOrSubImage(isSubImage, needsRespec, funcName, tex, target, level, dui, xOffset, yOffset, zOffset, out_error); }
void BasicCompositor::DrawQuad(const gfx::Rect& aRect, const gfx::Rect& aClipRect, const EffectChain &aEffectChain, gfx::Float aOpacity, const gfx::Matrix4x4& aTransform, const gfx::Rect& aVisibleRect) { RefPtr<DrawTarget> buffer = mRenderTarget->mDrawTarget; // For 2D drawing, |dest| and |buffer| are the same surface. For 3D drawing, // |dest| is a temporary surface. RefPtr<DrawTarget> dest = buffer; buffer->PushClipRect(aClipRect); AutoRestoreTransform autoRestoreTransform(dest); Matrix newTransform; Rect transformBounds; gfx3DMatrix new3DTransform; IntPoint offset = mRenderTarget->GetOrigin(); if (aTransform.Is2D()) { newTransform = aTransform.As2D(); } else { // Create a temporary surface for the transform. dest = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(RoundOut(aRect).Size(), SurfaceFormat::B8G8R8A8); if (!dest) { return; } dest->SetTransform(Matrix::Translation(-aRect.x, -aRect.y)); // Get the bounds post-transform. new3DTransform = To3DMatrix(aTransform); gfxRect bounds = new3DTransform.TransformBounds(ThebesRect(aRect)); bounds.IntersectRect(bounds, gfxRect(offset.x, offset.y, buffer->GetSize().width, buffer->GetSize().height)); transformBounds = ToRect(bounds); transformBounds.RoundOut(); // Propagate the coordinate offset to our 2D draw target. newTransform = Matrix::Translation(transformBounds.x, transformBounds.y); // When we apply the 3D transformation, we do it against a temporary // surface, so undo the coordinate offset. new3DTransform = gfx3DMatrix::Translation(aRect.x, aRect.y, 0) * new3DTransform; } newTransform.PostTranslate(-offset.x, -offset.y); buffer->SetTransform(newTransform); RefPtr<SourceSurface> sourceMask; Matrix maskTransform; if (aEffectChain.mSecondaryEffects[EffectTypes::MASK]) { EffectMask *effectMask = static_cast<EffectMask*>(aEffectChain.mSecondaryEffects[EffectTypes::MASK].get()); sourceMask = effectMask->mMaskTexture->AsSourceBasic()->GetSurface(dest); MOZ_ASSERT(effectMask->mMaskTransform.Is2D(), "How did we end up with a 3D transform here?!"); MOZ_ASSERT(!effectMask->mIs3D); maskTransform = effectMask->mMaskTransform.As2D(); maskTransform.PreTranslate(-offset.x, -offset.y); } switch (aEffectChain.mPrimaryEffect->mType) { case EffectTypes::SOLID_COLOR: { EffectSolidColor* effectSolidColor = static_cast<EffectSolidColor*>(aEffectChain.mPrimaryEffect.get()); FillRectWithMask(dest, aRect, effectSolidColor->mColor, DrawOptions(aOpacity), sourceMask, &maskTransform); break; } case EffectTypes::RGB: { TexturedEffect* texturedEffect = static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get()); TextureSourceBasic* source = texturedEffect->mTexture->AsSourceBasic(); if (texturedEffect->mPremultiplied) { DrawSurfaceWithTextureCoords(dest, aRect, source->GetSurface(dest), texturedEffect->mTextureCoords, texturedEffect->mFilter, aOpacity, sourceMask, &maskTransform); } else { RefPtr<DataSourceSurface> srcData = source->GetSurface(dest)->GetDataSurface(); // Yes, we re-create the premultiplied data every time. // This might be better with a cache, eventually. RefPtr<DataSourceSurface> premultData = gfxUtils::CreatePremultipliedDataSurface(srcData); DrawSurfaceWithTextureCoords(dest, aRect, premultData, texturedEffect->mTextureCoords, texturedEffect->mFilter, aOpacity, sourceMask, &maskTransform); } break; } case EffectTypes::YCBCR: { NS_RUNTIMEABORT("Can't (easily) support component alpha with BasicCompositor!"); break; } case EffectTypes::RENDER_TARGET: { EffectRenderTarget* effectRenderTarget = static_cast<EffectRenderTarget*>(aEffectChain.mPrimaryEffect.get()); RefPtr<BasicCompositingRenderTarget> surface = static_cast<BasicCompositingRenderTarget*>(effectRenderTarget->mRenderTarget.get()); RefPtr<SourceSurface> sourceSurf = surface->mDrawTarget->Snapshot(); DrawSurfaceWithTextureCoords(dest, aRect, sourceSurf, effectRenderTarget->mTextureCoords, effectRenderTarget->mFilter, aOpacity, sourceMask, &maskTransform); break; } case EffectTypes::COMPONENT_ALPHA: { NS_RUNTIMEABORT("Can't (easily) support component alpha with BasicCompositor!"); break; } default: { NS_RUNTIMEABORT("Invalid effect type!"); break; } } if (!aTransform.Is2D()) { dest->Flush(); RefPtr<SourceSurface> snapshot = dest->Snapshot(); RefPtr<DataSourceSurface> source = snapshot->GetDataSurface(); RefPtr<DataSourceSurface> temp = Factory::CreateDataSourceSurface(RoundOut(transformBounds).Size(), SurfaceFormat::B8G8R8A8 #ifdef MOZ_ENABLE_SKIA , true #endif ); if (NS_WARN_IF(!temp)) { buffer->PopClip(); return; } Transform(temp, source, new3DTransform, transformBounds.TopLeft()); transformBounds.MoveTo(0, 0); buffer->DrawSurface(temp, transformBounds, transformBounds); } buffer->PopClip(); }
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; }
void TestDrawTargetBase::RefreshSnapshot() { RefPtr<SourceSurface> snapshot = mDT->Snapshot(); mDataSnapshot = snapshot->GetDataSurface(); }
bool TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName, WebGLTexture* tex, TexImageTarget target, GLint level, const webgl::DriverUnpackInfo* dui, GLint xOffset, GLint yOffset, GLint zOffset, const webgl::PackingInfo& pi, GLenum* const out_error) const { MOZ_ASSERT_IF(needsRespec, !isSubImage); WebGLContext* webgl = tex->mContext; gl::GLContext* gl = webgl->GL(); gl->MakeCurrent(); if (needsRespec) { *out_error = DoTexOrSubImage(isSubImage, gl, target.get(), level, dui, xOffset, yOffset, zOffset, mWidth, mHeight, mDepth, nullptr); if (*out_error) return true; } const char* fallbackReason; do { if (mDepth != 1) { fallbackReason = "depth is not 1"; break; } if (webgl->mPixelStore_UnpackSkipPixels || webgl->mPixelStore_UnpackSkipRows || webgl->mPixelStore_UnpackSkipImages) { fallbackReason = "non-zero UNPACK_SKIP_* not yet supported"; break; } const auto fnHasPremultMismatch = [&]() { if (mSrcAlphaType == gfxAlphaType::Opaque) return false; const bool srcIsPremult = (mSrcAlphaType == gfxAlphaType::Premult); const auto& dstIsPremult = webgl->mPixelStore_PremultiplyAlpha; if (srcIsPremult == dstIsPremult) return false; if (dstIsPremult) { fallbackReason = "UNPACK_PREMULTIPLY_ALPHA_WEBGL is not true"; } else { fallbackReason = "UNPACK_PREMULTIPLY_ALPHA_WEBGL is not false"; } return true; }; if (fnHasPremultMismatch()) break; if (dui->unpackFormat != LOCAL_GL_RGB && dui->unpackFormat != LOCAL_GL_RGBA) { fallbackReason = "`format` is not RGB or RGBA"; break; } if (dui->unpackType != LOCAL_GL_UNSIGNED_BYTE) { fallbackReason = "`type` is not UNSIGNED_BYTE"; break; } gl::ScopedFramebuffer scopedFB(gl); gl::ScopedBindFramebuffer bindFB(gl, scopedFB.FB()); { gl::GLContext::LocalErrorScope errorScope(*gl); gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, target.get(), tex->mGLName, level); if (errorScope.GetError()) { fallbackReason = "bug: failed to attach to FB for blit"; break; } } const GLenum status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) { fallbackReason = "bug: failed to confirm FB for blit"; break; } const gfx::IntSize destSize(mWidth, mHeight); const auto dstOrigin = (webgl->mPixelStore_FlipY ? gl::OriginPos::TopLeft : gl::OriginPos::BottomLeft); if (!gl->BlitHelper()->BlitImageToFramebuffer(mImage, destSize, scopedFB.FB(), dstOrigin)) { fallbackReason = "likely bug: failed to blit"; break; } // Blitting was successful, so we're done! *out_error = 0; return true; } while (false); const nsPrintfCString perfMsg("%s: Failed to hit GPU-copy fast-path: %s (src type %u)", funcName, fallbackReason, uint32_t(mImage->GetFormat())); if (webgl->mPixelStore_RequireFastPath) { webgl->ErrorInvalidOperation("%s", perfMsg.BeginReading()); return false; } webgl->GeneratePerfWarning("%s Falling back to CPU upload.", perfMsg.BeginReading()); const RefPtr<gfx::SourceSurface> surf = mImage->GetAsSourceSurface(); RefPtr<gfx::DataSourceSurface> dataSurf; if (surf) { // WARNING: OSX can lose our MakeCurrent here. dataSurf = surf->GetDataSurface(); } if (!dataSurf) { webgl->ErrorOutOfMemory("%s: GetAsSourceSurface or GetDataSurface failed after" " blit failed for TexUnpackImage.", funcName); return false; } const TexUnpackSurface surfBlob(webgl, target, mWidth, mHeight, mDepth, dataSurf, mSrcAlphaType); return surfBlob.TexOrSubImage(isSubImage, needsRespec, funcName, tex, target, level, dui, xOffset, yOffset, zOffset, pi, out_error); }
static void DrawVelGraph(const nsIntRect& aClipRect, LayerManagerComposite* aManager, Layer* aLayer) { Compositor* compositor = aManager->GetCompositor(); gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height); TimeStamp now = TimeStamp::Now(); LayerVelocityUserData* velocityData = GetVelocityData(aLayer); if (velocityData->mData.size() >= 1 && now > velocityData->mData[velocityData->mData.size() - 1].mFrameTime + TimeDuration::FromMilliseconds(200)) { // clear stale data velocityData->mData.clear(); } const gfx::Point layerTransform = GetScrollData(aLayer); velocityData->mData.push_back( LayerVelocityUserData::VelocityData(now, static_cast<int>(layerTransform.x), static_cast<int>(layerTransform.y))); // TODO: dump to file // XXX: Uncomment these lines to enable ScrollGraph logging. This is // useful for HVGA phones or to output the data to accurate // graphing software. // printf_stderr("ScrollGraph (%p): %f, %f\n", // aLayer, layerTransform.x, layerTransform.y); // Keep a circular buffer of 100. size_t circularBufferSize = 100; if (velocityData->mData.size() > circularBufferSize) { velocityData->mData.erase(velocityData->mData.begin()); } if (velocityData->mData.size() == 1) { return; } // Clear and disable the graph when it's flat for (size_t i = 1; i < velocityData->mData.size(); i++) { if (velocityData->mData[i - 1].mPoint != velocityData->mData[i].mPoint) { break; } if (i == velocityData->mData.size() - 1) { velocityData->mData.clear(); return; } } if (aLayer->GetEffectiveVisibleRegion().GetBounds().width < 300 || aLayer->GetEffectiveVisibleRegion().GetBounds().height < 300) { // Don't want a graph for smaller layers return; } aManager->SetDebugOverlayWantsNextFrame(true); const Matrix4x4& transform = aLayer->GetEffectiveTransform(); nsIntRect bounds = aLayer->GetEffectiveVisibleRegion().GetBounds(); IntSize graphSize = IntSize(200, 100); Rect graphRect = Rect(bounds.x, bounds.y, graphSize.width, graphSize.height); RefPtr<DrawTarget> dt = aManager->CreateDrawTarget(graphSize, SurfaceFormat::B8G8R8A8); dt->FillRect(Rect(0, 0, graphSize.width, graphSize.height), ColorPattern(Color(0.2f,0,0,1))); int yScaleFactor = 3; Point prev = Point(0,0); bool first = true; for (int32_t i = (int32_t)velocityData->mData.size() - 2; i >= 0; i--) { const gfx::Point& p1 = velocityData->mData[i+1].mPoint; const gfx::Point& p2 = velocityData->mData[i].mPoint; int vel = sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)); Point next = Point(graphRect.width / circularBufferSize * i, graphRect.height - vel/yScaleFactor); if (first) { first = false; } else { dt->StrokeLine(prev, next, ColorPattern(Color(0,1,0,1))); } prev = next; } RefPtr<DataTextureSource> textureSource = compositor->CreateDataTextureSource(); RefPtr<SourceSurface> snapshot = dt->Snapshot(); RefPtr<DataSourceSurface> data = snapshot->GetDataSurface(); textureSource->Update(data); EffectChain effectChain; effectChain.mPrimaryEffect = CreateTexturedEffect(SurfaceFormat::B8G8R8A8, textureSource, Filter::POINT, true); compositor->DrawQuad(graphRect, clipRect, effectChain, 1.0f, transform); }