VectorImage::GetFrameAtSize(const IntSize& aSize, uint32_t aWhichFrame, uint32_t aFlags) { MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE); if (aSize.IsEmpty()) { return nullptr; } if (aWhichFrame > FRAME_MAX_VALUE) { return nullptr; } if (mError || !mIsFullyLoaded) { return nullptr; } // Make our surface the size of what will ultimately be drawn to it. // (either the full image size, or the restricted region) RefPtr<DrawTarget> dt = gfxPlatform::GetPlatform()-> CreateOffscreenContentDrawTarget(aSize, SurfaceFormat::B8G8R8A8); if (!dt || !dt->IsValid()) { NS_ERROR("Could not create a DrawTarget"); return nullptr; } RefPtr<gfxContext> context = gfxContext::ForDrawTarget(dt); MOZ_ASSERT(context); // already checked the draw target above auto result = Draw(context, aSize, ImageRegion::Create(aSize), aWhichFrame, Filter::POINT, Nothing(), aFlags); return result == DrawResult::SUCCESS ? dt->Snapshot() : nullptr; }
already_AddRefed<DrawTarget> gfxAlphaBoxBlur::InitDrawTarget(const DrawTarget* aReferenceDT, const Rect& aRect, const IntSize& aSpreadRadius, const IntSize& aBlurRadius, const Rect* aDirtyRect, const Rect* aSkipRect) { mBlur.Init(aRect, aSpreadRadius, aBlurRadius, aDirtyRect, aSkipRect); size_t blurDataSize = mBlur.GetSurfaceAllocationSize(); if (blurDataSize == 0) { return nullptr; } BackendType backend = aReferenceDT->GetBackendType(); // Check if the backend has an accelerated DrawSurfaceWithShadow. // Currently, only D2D1.1 supports this. // Otherwise, DrawSurfaceWithShadow only supports square blurs without spread. if (aBlurRadius.IsSquare() && aSpreadRadius.IsEmpty() && backend == BackendType::DIRECT2D1_1) { mAccelerated = true; mDrawTarget = aReferenceDT->CreateShadowDrawTarget(mBlur.GetSize(), SurfaceFormat::A8, AlphaBoxBlur::CalculateBlurSigma(aBlurRadius.width)); } else { // Make an alpha-only surface to draw on. We will play with the data after // everything is drawn to create a blur effect. mData = static_cast<uint8_t*>(calloc(1, blurDataSize)); if (!mData) { return nullptr; } mDrawTarget = Factory::DoesBackendSupportDataDrawtarget(backend) ? Factory::CreateDrawTargetForData(backend, mData, mBlur.GetSize(), mBlur.GetStride(), SurfaceFormat::A8) : gfxPlatform::CreateDrawTargetForData(mData, mBlur.GetSize(), mBlur.GetStride(), SurfaceFormat::A8); } if (!mDrawTarget || !mDrawTarget->IsValid()) { return nullptr; } mDrawTarget->SetTransform(Matrix::Translation(-mBlur.GetRect().TopLeft())); return do_AddRef(mDrawTarget); }
void WinCompositorWidget::ClearTransparentWindow() { if (!mTransparentSurface) { return; } EnsureTransparentSurface(); IntSize size = mTransparentSurface->GetSize(); if (!size.IsEmpty()) { RefPtr<DrawTarget> drawTarget = gfxPlatform::GetPlatform()-> CreateDrawTargetForSurface(mTransparentSurface, size); drawTarget->ClearRect(Rect(0, 0, size.width, size.height)); RedrawTransparentWindow(); } }
Pair<DrawResult, RefPtr<SourceSurface>> RasterImage::GetFrameInternal(const IntSize& aSize, uint32_t aWhichFrame, uint32_t aFlags) { MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE); if (aSize.IsEmpty()) { return MakePair(DrawResult::BAD_ARGS, RefPtr<SourceSurface>()); } if (aWhichFrame > FRAME_MAX_VALUE) { return MakePair(DrawResult::BAD_ARGS, RefPtr<SourceSurface>()); } if (mError) { return MakePair(DrawResult::BAD_IMAGE, RefPtr<SourceSurface>()); } // Get the frame. If it's not there, it's probably the caller's fault for // not waiting for the data to be loaded from the network or not passing // FLAG_SYNC_DECODE. DrawableSurface surface = LookupFrame(aSize, aFlags, ToPlaybackType(aWhichFrame)); if (!surface) { // The OS threw this frame away and we couldn't redecode it. return MakePair(DrawResult::TEMPORARY_ERROR, RefPtr<SourceSurface>()); } RefPtr<SourceSurface> sourceSurface = surface->GetSourceSurface(); if (!surface->IsFinished()) { return MakePair(DrawResult::INCOMPLETE, Move(sourceSurface)); } return MakePair(DrawResult::SUCCESS, Move(sourceSurface)); }
already_AddRefed<DrawTarget> gfxAlphaBoxBlur::InitDrawTarget(const DrawTarget* aReferenceDT, const Rect& aRect, const IntSize& aSpreadRadius, const IntSize& aBlurRadius, const Rect* aDirtyRect, const Rect* aSkipRect, bool aUseHardwareAccel) { mBlur.Init(aRect, aSpreadRadius, aBlurRadius, aDirtyRect, aSkipRect); size_t blurDataSize = mBlur.GetSurfaceAllocationSize(); if (blurDataSize == 0) { return nullptr; } BackendType backend = aReferenceDT->GetBackendType(); // Check if the backend has an accelerated DrawSurfaceWithShadow. // Currently, only D2D1.1 supports this. // Otherwise, DrawSurfaceWithShadow only supports square blurs without spread. // When blurring small draw targets such as short spans text, the cost of // creating and flushing an accelerated draw target may exceed the speedup // gained from the faster blur. It's up to the users of this blur // to determine whether they want to use hardware acceleration. if (aBlurRadius.IsSquare() && aSpreadRadius.IsEmpty() && aUseHardwareAccel && backend == BackendType::DIRECT2D1_1) { mAccelerated = true; mDrawTarget = aReferenceDT->CreateShadowDrawTarget(mBlur.GetSize(), SurfaceFormat::A8, AlphaBoxBlur::CalculateBlurSigma(aBlurRadius.width)); } else { // Make an alpha-only surface to draw on. We will play with the data after // everything is drawn to create a blur effect. // This will be freed when the DrawTarget dies mData = static_cast<uint8_t*>(calloc(1, blurDataSize)); if (!mData) { return nullptr; } mDrawTarget = Factory::DoesBackendSupportDataDrawtarget(backend) ? Factory::CreateDrawTargetForData(backend, mData, mBlur.GetSize(), mBlur.GetStride(), SurfaceFormat::A8) : gfxPlatform::CreateDrawTargetForData(mData, mBlur.GetSize(), mBlur.GetStride(), SurfaceFormat::A8); } if (!mDrawTarget || !mDrawTarget->IsValid()) { if (mData) { free(mData); } return nullptr; } if (mData) { mDrawTarget->AddUserData(reinterpret_cast<UserDataKey*>(mDrawTarget.get()), mData, free); } mDrawTarget->SetTransform(Matrix::Translation(-mBlur.GetRect().TopLeft())); return do_AddRef(mDrawTarget); }
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; }
DrawableSurface RasterImage::LookupFrame(const IntSize& aSize, uint32_t aFlags, PlaybackType aPlaybackType) { MOZ_ASSERT(NS_IsMainThread()); // If we're opaque, we don't need to care about premultiplied alpha, because // that can only matter for frames with transparency. if (IsOpaque()) { aFlags &= ~FLAG_DECODE_NO_PREMULTIPLY_ALPHA; } IntSize requestedSize = CanDownscaleDuringDecode(aSize, aFlags) ? aSize : mSize; if (requestedSize.IsEmpty()) { return DrawableSurface(); // Can't decode to a surface of zero size. } LookupResult result = LookupFrameInternal(requestedSize, aFlags, aPlaybackType); if (!result && !mHasSize) { // We can't request a decode without knowing our intrinsic size. Give up. return DrawableSurface(); } if (result.Type() == MatchType::NOT_FOUND || result.Type() == MatchType::SUBSTITUTE_BECAUSE_NOT_FOUND || ((aFlags & FLAG_SYNC_DECODE) && !result)) { // We don't have a copy of this frame, and there's no decoder working on // one. (Or we're sync decoding and the existing decoder hasn't even started // yet.) Trigger decoding so it'll be available next time. MOZ_ASSERT(aPlaybackType != PlaybackType::eAnimated || !mAnimationState || mAnimationState->KnownFrameCount() < 1, "Animated frames should be locked"); Decode(requestedSize, aFlags, aPlaybackType); // If we can sync decode, we should already have the frame. if (aFlags & FLAG_SYNC_DECODE) { result = LookupFrameInternal(requestedSize, aFlags, aPlaybackType); } } if (!result) { // We still weren't able to get a frame. Give up. return DrawableSurface(); } if (result.Surface()->GetCompositingFailed()) { return DrawableSurface(); } MOZ_ASSERT(!result.Surface()->GetIsPaletted(), "Should not have a paletted frame"); // Sync decoding guarantees that we got the frame, but if it's owned by an // async decoder that's currently running, the contents of the frame may not // be available yet. Make sure we get everything. if (mHasSourceData && (aFlags & FLAG_SYNC_DECODE)) { result.Surface()->WaitUntilFinished(); } // If we could have done some decoding in this function we need to check if // that decoding encountered an error and hence aborted the surface. We want // to avoid calling IsAborted if we weren't passed any sync decode flag because // IsAborted acquires the monitor for the imgFrame. if (aFlags & (FLAG_SYNC_DECODE | FLAG_SYNC_DECODE_IF_FAST) && result.Surface()->IsAborted()) { return DrawableSurface(); } return Move(result.Surface()); }