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 "mozilla/dom/ImageBitmapRenderingContextBinding.h"
8 #include "nsComponentManagerUtils.h"
9 #include "ImageContainer.h"
10 #include "ImageLayers.h"
12 namespace mozilla::dom
{
14 ImageBitmapRenderingContext::ImageBitmapRenderingContext()
15 : mWidth(0), mHeight(0), mIsCapturedFrameInvalid(false) {}
17 ImageBitmapRenderingContext::~ImageBitmapRenderingContext() {
18 RemovePostRefreshObserver();
21 JSObject
* ImageBitmapRenderingContext::WrapObject(
22 JSContext
* aCx
, JS::Handle
<JSObject
*> aGivenProto
) {
23 return ImageBitmapRenderingContext_Binding::Wrap(aCx
, this, aGivenProto
);
26 already_AddRefed
<layers::Image
>
27 ImageBitmapRenderingContext::ClipToIntrinsicSize() {
32 // If image is larger than canvas intrinsic size, clip it to the intrinsic
34 RefPtr
<gfx::SourceSurface
> surface
;
35 RefPtr
<layers::Image
> result
;
36 if (mWidth
< mImage
->GetSize().width
|| mHeight
< mImage
->GetSize().height
) {
37 surface
= MatchWithIntrinsicSize();
39 surface
= mImage
->GetAsSourceSurface();
45 new layers::SourceSurfaceImage(gfx::IntSize(mWidth
, mHeight
), surface
);
46 return result
.forget();
49 void ImageBitmapRenderingContext::TransferImageBitmap(
50 ImageBitmap
& aImageBitmap
) {
51 TransferFromImageBitmap(aImageBitmap
);
54 void ImageBitmapRenderingContext::TransferFromImageBitmap(
55 ImageBitmap
& aImageBitmap
) {
57 mImage
= aImageBitmap
.TransferAsImage();
63 if (aImageBitmap
.IsWriteOnly() && mCanvasElement
) {
64 mCanvasElement
->SetWriteOnly();
67 Redraw(gfxRect(0, 0, mWidth
, mHeight
));
71 ImageBitmapRenderingContext::SetDimensions(int32_t aWidth
, int32_t aHeight
) {
78 ImageBitmapRenderingContext::InitializeWithDrawTarget(
79 nsIDocShell
* aDocShell
, NotNull
<gfx::DrawTarget
*> aTarget
) {
80 return NS_ERROR_NOT_IMPLEMENTED
;
83 already_AddRefed
<gfx::DataSourceSurface
>
84 ImageBitmapRenderingContext::MatchWithIntrinsicSize() {
85 RefPtr
<gfx::SourceSurface
> surface
= mImage
->GetAsSourceSurface();
86 RefPtr
<gfx::DataSourceSurface
> temp
= gfx::Factory::CreateDataSourceSurface(
87 gfx::IntSize(mWidth
, mHeight
), surface
->GetFormat());
92 gfx::DataSourceSurface::ScopedMap
map(temp
,
93 gfx::DataSourceSurface::READ_WRITE
);
94 if (!map
.IsMapped()) {
98 RefPtr
<gfx::DrawTarget
> dt
= gfx::Factory::CreateDrawTargetForData(
99 gfxPlatform::GetPlatform()->GetSoftwareBackend(), map
.GetData(),
100 temp
->GetSize(), map
.GetStride(), temp
->GetFormat());
101 if (!dt
|| !dt
->IsValid()) {
103 << "ImageBitmapRenderingContext::MatchWithIntrinsicSize failed";
107 dt
->ClearRect(gfx::Rect(0, 0, mWidth
, mHeight
));
110 gfx::IntRect(0, 0, surface
->GetSize().width
, surface
->GetSize().height
),
111 gfx::IntPoint(0, 0));
113 return temp
.forget();
116 mozilla::UniquePtr
<uint8_t[]> ImageBitmapRenderingContext::GetImageBuffer(
124 RefPtr
<gfx::SourceSurface
> surface
= mImage
->GetAsSourceSurface();
125 RefPtr
<gfx::DataSourceSurface
> data
= surface
->GetDataSurface();
130 if (data
->GetSize() != gfx::IntSize(mWidth
, mHeight
)) {
131 data
= MatchWithIntrinsicSize();
137 *aFormat
= imgIEncoder::INPUT_FORMAT_HOSTARGB
;
138 return gfx::SurfaceToPackedBGRA(data
);
142 ImageBitmapRenderingContext::GetInputStream(const char* aMimeType
,
143 const nsAString
& aEncoderOptions
,
144 nsIInputStream
** aStream
) {
145 nsCString
enccid("@mozilla.org/image/encoder;2?type=");
147 nsCOMPtr
<imgIEncoder
> encoder
= do_CreateInstance(enccid
.get());
149 return NS_ERROR_FAILURE
;
153 UniquePtr
<uint8_t[]> imageBuffer
= GetImageBuffer(&format
);
155 return NS_ERROR_FAILURE
;
158 return ImageEncoder::GetInputStream(mWidth
, mHeight
, imageBuffer
.get(),
159 format
, encoder
, aEncoderOptions
,
163 already_AddRefed
<mozilla::gfx::SourceSurface
>
164 ImageBitmapRenderingContext::GetSurfaceSnapshot(
165 gfxAlphaType
* const aOutAlphaType
) {
172 (GetIsOpaque() ? gfxAlphaType::Opaque
: gfxAlphaType::Premult
);
175 RefPtr
<gfx::SourceSurface
> surface
= mImage
->GetAsSourceSurface();
176 if (surface
->GetSize() != gfx::IntSize(mWidth
, mHeight
)) {
177 return MatchWithIntrinsicSize();
180 return surface
.forget();
183 void ImageBitmapRenderingContext::SetOpaqueValueFromOpaqueAttr(
184 bool aOpaqueAttrValue
) {
188 bool ImageBitmapRenderingContext::GetIsOpaque() { return false; }
191 ImageBitmapRenderingContext::Reset() {
192 if (mCanvasElement
) {
193 mCanvasElement
->InvalidateCanvas();
197 mIsCapturedFrameInvalid
= false;
201 already_AddRefed
<layers::Layer
> ImageBitmapRenderingContext::GetCanvasLayer(
202 nsDisplayListBuilder
* aBuilder
, Layer
* aOldLayer
, LayerManager
* aManager
) {
204 // No DidTransactionCallback will be received, so mark the context clean
205 // now so future invalidations will be dispatched.
210 RefPtr
<layers::ImageLayer
> imageLayer
;
213 imageLayer
= static_cast<layers::ImageLayer
*>(aOldLayer
);
215 imageLayer
= aManager
->CreateImageLayer();
218 RefPtr
<layers::ImageContainer
> imageContainer
= imageLayer
->GetContainer();
219 if (!imageContainer
) {
220 imageContainer
= LayerManager::CreateImageContainer();
221 imageLayer
->SetContainer(imageContainer
);
224 AutoTArray
<layers::ImageContainer::NonOwningImage
, 1> imageList
;
225 RefPtr
<layers::Image
> image
= ClipToIntrinsicSize();
229 imageList
.AppendElement(layers::ImageContainer::NonOwningImage(image
));
230 imageContainer
->SetCurrentImages(imageList
);
232 return imageLayer
.forget();
235 bool ImageBitmapRenderingContext::UpdateWebRenderCanvasData(
236 nsDisplayListBuilder
* aBuilder
, WebRenderCanvasData
* aCanvasData
) {
238 // No DidTransactionCallback will be received, so mark the context clean
239 // now so future invalidations will be dispatched.
244 RefPtr
<layers::ImageContainer
> imageContainer
=
245 aCanvasData
->GetImageContainer();
246 AutoTArray
<layers::ImageContainer::NonOwningImage
, 1> imageList
;
247 RefPtr
<layers::Image
> image
= ClipToIntrinsicSize();
252 imageList
.AppendElement(layers::ImageContainer::NonOwningImage(image
));
253 imageContainer
->SetCurrentImages(imageList
);
257 void ImageBitmapRenderingContext::MarkContextClean() {}
260 ImageBitmapRenderingContext::Redraw(const gfxRect
& aDirty
) {
261 mIsCapturedFrameInvalid
= true;
263 if (mOffscreenCanvas
) {
264 RefPtr
<layers::ImageContainer
> imageContainer
=
265 mOffscreenCanvas
->GetImageContainer();
266 if (imageContainer
) {
267 RefPtr
<layers::Image
> image
= ClipToIntrinsicSize();
269 AutoTArray
<layers::ImageContainer::NonOwningImage
, 1> imageList
;
270 imageList
.AppendElement(layers::ImageContainer::NonOwningImage(image
));
271 imageContainer
->SetCurrentImages(imageList
);
273 imageContainer
->ClearAllImages();
276 mOffscreenCanvas
->CommitFrameToCompositor();
279 if (!mCanvasElement
) {
283 mozilla::gfx::Rect rect
= ToRect(aDirty
);
284 mCanvasElement
->InvalidateCanvasContent(&rect
);
289 ImageBitmapRenderingContext::SetIsIPC(bool aIsIPC
) { return NS_OK
; }
291 void ImageBitmapRenderingContext::DidRefresh() {}
293 void ImageBitmapRenderingContext::MarkContextCleanForFrameCapture() {
294 mIsCapturedFrameInvalid
= false;
297 bool ImageBitmapRenderingContext::IsContextCleanForFrameCapture() {
298 return !mIsCapturedFrameInvalid
;
301 NS_IMPL_CYCLE_COLLECTING_ADDREF(ImageBitmapRenderingContext
)
302 NS_IMPL_CYCLE_COLLECTING_RELEASE(ImageBitmapRenderingContext
)
304 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ImageBitmapRenderingContext
,
305 mCanvasElement
, mOffscreenCanvas
)
307 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ImageBitmapRenderingContext
)
308 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
309 NS_INTERFACE_MAP_ENTRY(nsICanvasRenderingContextInternal
)
310 NS_INTERFACE_MAP_ENTRY(nsISupports
)
313 } // namespace mozilla::dom