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 // Note that this is reentrant and will call back into SetDimensions.
85 mCanvasElement
->SetSize(mImage
->GetSize(), aRv
);
86 } else if (mOffscreenCanvas
) {
87 mOffscreenCanvas
->SetSize(mImage
->GetSize(), aRv
);
90 if (NS_WARN_IF(aRv
.Failed())) {
95 if (aImageBitmap
->IsWriteOnly()) {
97 mCanvasElement
->SetWriteOnly();
98 } else if (mOffscreenCanvas
) {
99 mOffscreenCanvas
->SetWriteOnly();
104 Redraw(gfxRect(0, 0, mWidth
, mHeight
));
108 ImageBitmapRenderingContext::SetDimensions(int32_t aWidth
, int32_t aHeight
) {
112 if (mOffscreenCanvas
) {
113 OffscreenCanvasDisplayData data
;
114 data
.mSize
= {mWidth
, mHeight
};
115 data
.mIsOpaque
= GetIsOpaque();
116 data
.mIsAlphaPremult
= true;
117 data
.mDoPaintCallbacks
= false;
118 mOffscreenCanvas
->UpdateDisplayData(data
);
125 ImageBitmapRenderingContext::InitializeWithDrawTarget(
126 nsIDocShell
* aDocShell
, NotNull
<gfx::DrawTarget
*> aTarget
) {
127 return NS_ERROR_NOT_IMPLEMENTED
;
130 already_AddRefed
<gfx::DataSourceSurface
>
131 ImageBitmapRenderingContext::MatchWithIntrinsicSize() {
132 RefPtr
<gfx::SourceSurface
> surface
= mImage
->GetAsSourceSurface();
136 RefPtr
<gfx::DataSourceSurface
> temp
= gfx::Factory::CreateDataSourceSurface(
137 gfx::IntSize(mWidth
, mHeight
), surface
->GetFormat());
142 gfx::DataSourceSurface::ScopedMap
map(temp
,
143 gfx::DataSourceSurface::READ_WRITE
);
144 if (!map
.IsMapped()) {
148 RefPtr
<gfx::DrawTarget
> dt
= gfx::Factory::CreateDrawTargetForData(
149 gfxPlatform::GetPlatform()->GetSoftwareBackend(), map
.GetData(),
150 temp
->GetSize(), map
.GetStride(), temp
->GetFormat());
151 if (!dt
|| !dt
->IsValid()) {
153 << "ImageBitmapRenderingContext::MatchWithIntrinsicSize failed";
157 dt
->ClearRect(gfx::Rect(0, 0, mWidth
, mHeight
));
160 gfx::IntRect(0, 0, surface
->GetSize().width
, surface
->GetSize().height
),
161 gfx::IntPoint(0, 0));
163 return temp
.forget();
166 mozilla::UniquePtr
<uint8_t[]> ImageBitmapRenderingContext::GetImageBuffer(
167 int32_t* aFormat
, gfx::IntSize
* aImageSize
) {
175 RefPtr
<gfx::SourceSurface
> surface
= mImage
->GetAsSourceSurface();
179 RefPtr
<gfx::DataSourceSurface
> data
= surface
->GetDataSurface();
184 if (data
->GetSize() != gfx::IntSize(mWidth
, mHeight
)) {
185 data
= MatchWithIntrinsicSize();
191 *aFormat
= imgIEncoder::INPUT_FORMAT_HOSTARGB
;
192 *aImageSize
= data
->GetSize();
194 UniquePtr
<uint8_t[]> ret
= gfx::SurfaceToPackedBGRA(data
);
196 if (ret
&& ShouldResistFingerprinting(RFPTarget::CanvasRandomization
)) {
197 nsRFPService::RandomizePixels(
198 GetCookieJarSettings(), ret
.get(), data
->GetSize().width
,
199 data
->GetSize().height
,
200 data
->GetSize().width
* data
->GetSize().height
* 4,
201 gfx::SurfaceFormat::A8R8G8B8_UINT32
);
207 ImageBitmapRenderingContext::GetInputStream(const char* aMimeType
,
208 const nsAString
& aEncoderOptions
,
209 nsIInputStream
** aStream
) {
210 nsCString
enccid("@mozilla.org/image/encoder;2?type=");
212 nsCOMPtr
<imgIEncoder
> encoder
= do_CreateInstance(enccid
.get());
214 return NS_ERROR_FAILURE
;
218 gfx::IntSize imageSize
= {};
219 UniquePtr
<uint8_t[]> imageBuffer
= GetImageBuffer(&format
, &imageSize
);
221 return NS_ERROR_FAILURE
;
224 return ImageEncoder::GetInputStream(imageSize
.width
, imageSize
.height
,
225 imageBuffer
.get(), format
, encoder
,
226 aEncoderOptions
, aStream
);
229 already_AddRefed
<mozilla::gfx::SourceSurface
>
230 ImageBitmapRenderingContext::GetSurfaceSnapshot(
231 gfxAlphaType
* const aOutAlphaType
) {
238 (GetIsOpaque() ? gfxAlphaType::Opaque
: gfxAlphaType::Premult
);
241 RefPtr
<gfx::SourceSurface
> surface
= mImage
->GetAsSourceSurface();
246 if (surface
->GetSize() != gfx::IntSize(mWidth
, mHeight
)) {
247 return MatchWithIntrinsicSize();
250 return surface
.forget();
253 void ImageBitmapRenderingContext::SetOpaqueValueFromOpaqueAttr(
254 bool aOpaqueAttrValue
) {
258 bool ImageBitmapRenderingContext::GetIsOpaque() { return false; }
260 void ImageBitmapRenderingContext::ResetBitmap() {
261 if (mCanvasElement
) {
262 mCanvasElement
->InvalidateCanvas();
266 mFrameCaptureState
= FrameCaptureState::CLEAN
;
269 bool ImageBitmapRenderingContext::UpdateWebRenderCanvasData(
270 nsDisplayListBuilder
* aBuilder
, WebRenderCanvasData
* aCanvasData
) {
272 // No DidTransactionCallback will be received, so mark the context clean
273 // now so future invalidations will be dispatched.
278 RefPtr
<layers::ImageContainer
> imageContainer
=
279 aCanvasData
->GetImageContainer();
280 AutoTArray
<layers::ImageContainer::NonOwningImage
, 1> imageList
;
281 RefPtr
<layers::Image
> image
= ClipToIntrinsicSize();
286 imageList
.AppendElement(layers::ImageContainer::NonOwningImage(image
));
287 imageContainer
->SetCurrentImages(imageList
);
291 void ImageBitmapRenderingContext::MarkContextClean() {}
294 ImageBitmapRenderingContext::Redraw(const gfxRect
& aDirty
) {
295 mFrameCaptureState
= FrameCaptureState::DIRTY
;
297 if (mOffscreenCanvas
) {
298 mOffscreenCanvas
->CommitFrameToCompositor();
299 } else if (mCanvasElement
) {
300 mozilla::gfx::Rect rect
= ToRect(aDirty
);
301 mCanvasElement
->InvalidateCanvasContent(&rect
);
307 void ImageBitmapRenderingContext::DidRefresh() {}
309 NS_IMPL_CYCLE_COLLECTING_ADDREF(ImageBitmapRenderingContext
)
310 NS_IMPL_CYCLE_COLLECTING_RELEASE(ImageBitmapRenderingContext
)
312 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_WEAK_PTR(ImageBitmapRenderingContext
,
313 mCanvasElement
, mOffscreenCanvas
)
315 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ImageBitmapRenderingContext
)
316 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
317 NS_INTERFACE_MAP_ENTRY(nsICanvasRenderingContextInternal
)
318 NS_INTERFACE_MAP_ENTRY(nsISupports
)
321 } // namespace mozilla::dom