1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "ImageBitmapRenderingContext.h"
7 #include "gfxPlatform.h"
9 #include "mozilla/dom/ImageBitmapRenderingContextBinding.h"
10 #include "mozilla/gfx/Types.h"
11 #include "nsComponentManagerUtils.h"
13 #include "ImageContainer.h"
15 namespace mozilla::dom
{
17 ImageBitmapRenderingContext::ImageBitmapRenderingContext()
20 mFrameCaptureState(FrameCaptureState::CLEAN
,
21 "ImageBitmapRenderingContext::mFrameCaptureState") {}
23 ImageBitmapRenderingContext::~ImageBitmapRenderingContext() {
24 RemovePostRefreshObserver();
27 JSObject
* ImageBitmapRenderingContext::WrapObject(
28 JSContext
* aCx
, JS::Handle
<JSObject
*> aGivenProto
) {
29 return ImageBitmapRenderingContext_Binding::Wrap(aCx
, this, aGivenProto
);
32 already_AddRefed
<layers::Image
>
33 ImageBitmapRenderingContext::ClipToIntrinsicSize() {
38 // If image is larger than canvas intrinsic size, clip it to the intrinsic
40 RefPtr
<gfx::SourceSurface
> surface
;
41 RefPtr
<layers::Image
> result
;
42 if (mWidth
< mImage
->GetSize().width
|| mHeight
< mImage
->GetSize().height
) {
43 surface
= MatchWithIntrinsicSize();
45 surface
= mImage
->GetAsSourceSurface();
51 new layers::SourceSurfaceImage(gfx::IntSize(mWidth
, mHeight
), surface
);
52 return result
.forget();
55 void ImageBitmapRenderingContext::GetCanvas(
56 Nullable
<OwningHTMLCanvasElementOrOffscreenCanvas
>& retval
) const {
57 if (mCanvasElement
&& !mCanvasElement
->IsInNativeAnonymousSubtree()) {
58 retval
.SetValue().SetAsHTMLCanvasElement() = mCanvasElement
;
59 } else if (mOffscreenCanvas
) {
60 retval
.SetValue().SetAsOffscreenCanvas() = mOffscreenCanvas
;
66 void ImageBitmapRenderingContext::TransferImageBitmap(ImageBitmap
& aImageBitmap
,
68 TransferFromImageBitmap(&aImageBitmap
, aRv
);
71 void ImageBitmapRenderingContext::TransferFromImageBitmap(
72 ImageBitmap
* aImageBitmap
, ErrorResult
& aRv
) {
76 mImage
= aImageBitmap
->TransferAsImage();
79 aRv
.ThrowInvalidStateError("The input ImageBitmap has been detached");
83 if (aImageBitmap
->IsWriteOnly()) {
85 mCanvasElement
->SetWriteOnly();
86 } else if (mOffscreenCanvas
) {
87 mOffscreenCanvas
->SetWriteOnly();
92 Redraw(gfxRect(0, 0, mWidth
, mHeight
));
96 ImageBitmapRenderingContext::SetDimensions(int32_t aWidth
, int32_t aHeight
) {
103 ImageBitmapRenderingContext::InitializeWithDrawTarget(
104 nsIDocShell
* aDocShell
, NotNull
<gfx::DrawTarget
*> aTarget
) {
105 return NS_ERROR_NOT_IMPLEMENTED
;
108 already_AddRefed
<gfx::DataSourceSurface
>
109 ImageBitmapRenderingContext::MatchWithIntrinsicSize() {
110 RefPtr
<gfx::SourceSurface
> surface
= mImage
->GetAsSourceSurface();
114 RefPtr
<gfx::DataSourceSurface
> temp
= gfx::Factory::CreateDataSourceSurface(
115 gfx::IntSize(mWidth
, mHeight
), surface
->GetFormat());
120 gfx::DataSourceSurface::ScopedMap
map(temp
,
121 gfx::DataSourceSurface::READ_WRITE
);
122 if (!map
.IsMapped()) {
126 RefPtr
<gfx::DrawTarget
> dt
= gfx::Factory::CreateDrawTargetForData(
127 gfxPlatform::GetPlatform()->GetSoftwareBackend(), map
.GetData(),
128 temp
->GetSize(), map
.GetStride(), temp
->GetFormat());
129 if (!dt
|| !dt
->IsValid()) {
131 << "ImageBitmapRenderingContext::MatchWithIntrinsicSize failed";
135 dt
->ClearRect(gfx::Rect(0, 0, mWidth
, mHeight
));
138 gfx::IntRect(0, 0, surface
->GetSize().width
, surface
->GetSize().height
),
139 gfx::IntPoint(0, 0));
141 return temp
.forget();
144 mozilla::UniquePtr
<uint8_t[]> ImageBitmapRenderingContext::GetImageBuffer(
145 int32_t* aFormat
, gfx::IntSize
* aImageSize
) {
153 RefPtr
<gfx::SourceSurface
> surface
= mImage
->GetAsSourceSurface();
157 RefPtr
<gfx::DataSourceSurface
> data
= surface
->GetDataSurface();
162 if (data
->GetSize() != gfx::IntSize(mWidth
, mHeight
)) {
163 data
= MatchWithIntrinsicSize();
169 *aFormat
= imgIEncoder::INPUT_FORMAT_HOSTARGB
;
170 *aImageSize
= data
->GetSize();
172 UniquePtr
<uint8_t[]> ret
= gfx::SurfaceToPackedBGRA(data
);
174 if (ret
&& ShouldResistFingerprinting(RFPTarget::CanvasRandomization
)) {
175 nsRFPService::RandomizePixels(
176 GetCookieJarSettings(), ret
.get(),
177 data
->GetSize().width
* data
->GetSize().height
* 4,
178 gfx::SurfaceFormat::A8R8G8B8_UINT32
);
184 ImageBitmapRenderingContext::GetInputStream(const char* aMimeType
,
185 const nsAString
& aEncoderOptions
,
186 nsIInputStream
** aStream
) {
187 nsCString
enccid("@mozilla.org/image/encoder;2?type=");
189 nsCOMPtr
<imgIEncoder
> encoder
= do_CreateInstance(enccid
.get());
191 return NS_ERROR_FAILURE
;
195 gfx::IntSize imageSize
= {};
196 UniquePtr
<uint8_t[]> imageBuffer
= GetImageBuffer(&format
, &imageSize
);
198 return NS_ERROR_FAILURE
;
201 return ImageEncoder::GetInputStream(imageSize
.width
, imageSize
.height
,
202 imageBuffer
.get(), format
, encoder
,
203 aEncoderOptions
, aStream
);
206 already_AddRefed
<mozilla::gfx::SourceSurface
>
207 ImageBitmapRenderingContext::GetSurfaceSnapshot(
208 gfxAlphaType
* const aOutAlphaType
) {
215 (GetIsOpaque() ? gfxAlphaType::Opaque
: gfxAlphaType::Premult
);
218 RefPtr
<gfx::SourceSurface
> surface
= mImage
->GetAsSourceSurface();
223 if (surface
->GetSize() != gfx::IntSize(mWidth
, mHeight
)) {
224 return MatchWithIntrinsicSize();
227 return surface
.forget();
230 void ImageBitmapRenderingContext::SetOpaqueValueFromOpaqueAttr(
231 bool aOpaqueAttrValue
) {
235 bool ImageBitmapRenderingContext::GetIsOpaque() { return false; }
237 void ImageBitmapRenderingContext::ResetBitmap() {
238 if (mCanvasElement
) {
239 mCanvasElement
->InvalidateCanvas();
243 mFrameCaptureState
= FrameCaptureState::CLEAN
;
246 bool ImageBitmapRenderingContext::UpdateWebRenderCanvasData(
247 nsDisplayListBuilder
* aBuilder
, WebRenderCanvasData
* aCanvasData
) {
249 // No DidTransactionCallback will be received, so mark the context clean
250 // now so future invalidations will be dispatched.
255 RefPtr
<layers::ImageContainer
> imageContainer
=
256 aCanvasData
->GetImageContainer();
257 AutoTArray
<layers::ImageContainer::NonOwningImage
, 1> imageList
;
258 RefPtr
<layers::Image
> image
= ClipToIntrinsicSize();
263 imageList
.AppendElement(layers::ImageContainer::NonOwningImage(image
));
264 imageContainer
->SetCurrentImages(imageList
);
268 void ImageBitmapRenderingContext::MarkContextClean() {}
271 ImageBitmapRenderingContext::Redraw(const gfxRect
& aDirty
) {
272 mFrameCaptureState
= FrameCaptureState::DIRTY
;
274 if (mOffscreenCanvas
) {
275 mOffscreenCanvas
->CommitFrameToCompositor();
276 } else if (mCanvasElement
) {
277 mozilla::gfx::Rect rect
= ToRect(aDirty
);
278 mCanvasElement
->InvalidateCanvasContent(&rect
);
284 void ImageBitmapRenderingContext::DidRefresh() {}
286 NS_IMPL_CYCLE_COLLECTING_ADDREF(ImageBitmapRenderingContext
)
287 NS_IMPL_CYCLE_COLLECTING_RELEASE(ImageBitmapRenderingContext
)
289 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_WEAK_PTR(ImageBitmapRenderingContext
,
290 mCanvasElement
, mOffscreenCanvas
)
292 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ImageBitmapRenderingContext
)
293 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
294 NS_INTERFACE_MAP_ENTRY(nsICanvasRenderingContextInternal
)
295 NS_INTERFACE_MAP_ENTRY(nsISupports
)
298 } // namespace mozilla::dom