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/. */
5
6 #include "ImageBitmapRenderingContext.h"
7 #include "mozilla/dom/ImageBitmapRenderingContextBinding.h"
8 #include "ImageContainer.h"
9 #include "ImageLayers.h"
10
11 namespace mozilla {
12 namespace dom {
13
ImageBitmapRenderingContext()14 ImageBitmapRenderingContext::ImageBitmapRenderingContext()
15 : mWidth(0), mHeight(0) {}
16
~ImageBitmapRenderingContext()17 ImageBitmapRenderingContext::~ImageBitmapRenderingContext() {
18 RemovePostRefreshObserver();
19 }
20
WrapObject(JSContext * aCx,JS::Handle<JSObject * > aGivenProto)21 JSObject* ImageBitmapRenderingContext::WrapObject(
22 JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
23 return ImageBitmapRenderingContextBinding::Wrap(aCx, this, aGivenProto);
24 }
25
26 already_AddRefed<layers::Image>
ClipToIntrinsicSize()27 ImageBitmapRenderingContext::ClipToIntrinsicSize() {
28 if (!mImage) {
29 return nullptr;
30 }
31
32 // If image is larger than canvas intrinsic size, clip it to the intrinsic
33 // size.
34 RefPtr<gfx::SourceSurface> surface;
35 RefPtr<layers::Image> result;
36 if (mWidth < mImage->GetSize().width || mHeight < mImage->GetSize().height) {
37 surface = MatchWithIntrinsicSize();
38 } else {
39 surface = mImage->GetAsSourceSurface();
40 }
41 if (!surface) {
42 return nullptr;
43 }
44 result =
45 new layers::SourceSurfaceImage(gfx::IntSize(mWidth, mHeight), surface);
46 return result.forget();
47 }
48
TransferImageBitmap(ImageBitmap & aImageBitmap)49 void ImageBitmapRenderingContext::TransferImageBitmap(
50 ImageBitmap& aImageBitmap) {
51 TransferFromImageBitmap(aImageBitmap);
52 }
53
TransferFromImageBitmap(ImageBitmap & aImageBitmap)54 void ImageBitmapRenderingContext::TransferFromImageBitmap(
55 ImageBitmap& aImageBitmap) {
56 Reset();
57 mImage = aImageBitmap.TransferAsImage();
58
59 if (!mImage) {
60 return;
61 }
62
63 if (aImageBitmap.IsWriteOnly() && mCanvasElement) {
64 mCanvasElement->SetWriteOnly();
65 }
66
67 Redraw(gfxRect(0, 0, mWidth, mHeight));
68 }
69
70 NS_IMETHODIMP
SetDimensions(int32_t aWidth,int32_t aHeight)71 ImageBitmapRenderingContext::SetDimensions(int32_t aWidth, int32_t aHeight) {
72 mWidth = aWidth;
73 mHeight = aHeight;
74 return NS_OK;
75 }
76
77 NS_IMETHODIMP
InitializeWithDrawTarget(nsIDocShell * aDocShell,NotNull<gfx::DrawTarget * > aTarget)78 ImageBitmapRenderingContext::InitializeWithDrawTarget(
79 nsIDocShell* aDocShell, NotNull<gfx::DrawTarget*> aTarget) {
80 return NS_ERROR_NOT_IMPLEMENTED;
81 }
82
83 already_AddRefed<DataSourceSurface>
MatchWithIntrinsicSize()84 ImageBitmapRenderingContext::MatchWithIntrinsicSize() {
85 RefPtr<SourceSurface> surface = mImage->GetAsSourceSurface();
86 RefPtr<DataSourceSurface> temp = Factory::CreateDataSourceSurface(
87 IntSize(mWidth, mHeight), surface->GetFormat());
88 if (!temp) {
89 return nullptr;
90 }
91
92 DataSourceSurface::ScopedMap map(temp, DataSourceSurface::READ_WRITE);
93 if (!map.IsMapped()) {
94 return nullptr;
95 }
96
97 RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(
98 gfxPlatform::GetPlatform()->GetSoftwareBackend(), map.GetData(),
99 temp->GetSize(), map.GetStride(), temp->GetFormat());
100 if (!dt || !dt->IsValid()) {
101 gfxWarning()
102 << "ImageBitmapRenderingContext::MatchWithIntrinsicSize failed";
103 return nullptr;
104 }
105
106 dt->ClearRect(Rect(0, 0, mWidth, mHeight));
107 dt->CopySurface(
108 surface,
109 IntRect(0, 0, surface->GetSize().width, surface->GetSize().height),
110 IntPoint(0, 0));
111
112 return temp.forget();
113 }
114
GetImageBuffer(int32_t * aFormat)115 mozilla::UniquePtr<uint8_t[]> ImageBitmapRenderingContext::GetImageBuffer(
116 int32_t* aFormat) {
117 *aFormat = 0;
118
119 if (!mImage) {
120 return nullptr;
121 }
122
123 RefPtr<SourceSurface> surface = mImage->GetAsSourceSurface();
124 RefPtr<DataSourceSurface> data = surface->GetDataSurface();
125 if (!data) {
126 return nullptr;
127 }
128
129 if (data->GetSize() != IntSize(mWidth, mHeight)) {
130 data = MatchWithIntrinsicSize();
131 if (!data) {
132 return nullptr;
133 }
134 }
135
136 *aFormat = imgIEncoder::INPUT_FORMAT_HOSTARGB;
137 return SurfaceToPackedBGRA(data);
138 }
139
140 NS_IMETHODIMP
GetInputStream(const char * aMimeType,const char16_t * aEncoderOptions,nsIInputStream ** aStream)141 ImageBitmapRenderingContext::GetInputStream(const char* aMimeType,
142 const char16_t* aEncoderOptions,
143 nsIInputStream** aStream) {
144 nsCString enccid("@mozilla.org/image/encoder;2?type=");
145 enccid += aMimeType;
146 nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(enccid.get());
147 if (!encoder) {
148 return NS_ERROR_FAILURE;
149 }
150
151 int32_t format = 0;
152 UniquePtr<uint8_t[]> imageBuffer = GetImageBuffer(&format);
153 if (!imageBuffer) {
154 return NS_ERROR_FAILURE;
155 }
156
157 return ImageEncoder::GetInputStream(mWidth, mHeight, imageBuffer.get(),
158 format, encoder, aEncoderOptions,
159 aStream);
160 }
161
162 already_AddRefed<mozilla::gfx::SourceSurface>
GetSurfaceSnapshot(gfxAlphaType * const aOutAlphaType)163 ImageBitmapRenderingContext::GetSurfaceSnapshot(
164 gfxAlphaType* const aOutAlphaType) {
165 if (!mImage) {
166 return nullptr;
167 }
168
169 if (aOutAlphaType) {
170 *aOutAlphaType =
171 (GetIsOpaque() ? gfxAlphaType::Opaque : gfxAlphaType::Premult);
172 }
173
174 RefPtr<SourceSurface> surface = mImage->GetAsSourceSurface();
175 if (surface->GetSize() != IntSize(mWidth, mHeight)) {
176 return MatchWithIntrinsicSize();
177 }
178
179 return surface.forget();
180 }
181
SetIsOpaque(bool aIsOpaque)182 void ImageBitmapRenderingContext::SetIsOpaque(bool aIsOpaque) {}
183
GetIsOpaque()184 bool ImageBitmapRenderingContext::GetIsOpaque() { return false; }
185
186 NS_IMETHODIMP
Reset()187 ImageBitmapRenderingContext::Reset() {
188 if (mCanvasElement) {
189 mCanvasElement->InvalidateCanvas();
190 }
191
192 mImage = nullptr;
193
194 return NS_OK;
195 }
196
GetCanvasLayer(nsDisplayListBuilder * aBuilder,Layer * aOldLayer,LayerManager * aManager)197 already_AddRefed<Layer> ImageBitmapRenderingContext::GetCanvasLayer(
198 nsDisplayListBuilder* aBuilder, Layer* aOldLayer, LayerManager* aManager) {
199 if (!mImage) {
200 // No DidTransactionCallback will be received, so mark the context clean
201 // now so future invalidations will be dispatched.
202 MarkContextClean();
203 return nullptr;
204 }
205
206 RefPtr<ImageLayer> imageLayer;
207
208 if (aOldLayer) {
209 imageLayer = static_cast<ImageLayer*>(aOldLayer);
210 } else {
211 imageLayer = aManager->CreateImageLayer();
212 }
213
214 RefPtr<ImageContainer> imageContainer = imageLayer->GetContainer();
215 if (!imageContainer) {
216 imageContainer = aManager->CreateImageContainer();
217 imageLayer->SetContainer(imageContainer);
218 }
219
220 AutoTArray<ImageContainer::NonOwningImage, 1> imageList;
221 RefPtr<layers::Image> image = ClipToIntrinsicSize();
222 if (!image) {
223 return nullptr;
224 }
225 imageList.AppendElement(ImageContainer::NonOwningImage(image));
226 imageContainer->SetCurrentImages(imageList);
227
228 return imageLayer.forget();
229 }
230
MarkContextClean()231 void ImageBitmapRenderingContext::MarkContextClean() {}
232
233 NS_IMETHODIMP
Redraw(const gfxRect & aDirty)234 ImageBitmapRenderingContext::Redraw(const gfxRect& aDirty) {
235 if (!mCanvasElement) {
236 return NS_OK;
237 }
238
239 mozilla::gfx::Rect rect = ToRect(aDirty);
240 mCanvasElement->InvalidateCanvasContent(&rect);
241 return NS_OK;
242 }
243
244 NS_IMETHODIMP
SetIsIPC(bool aIsIPC)245 ImageBitmapRenderingContext::SetIsIPC(bool aIsIPC) { return NS_OK; }
246
DidRefresh()247 void ImageBitmapRenderingContext::DidRefresh() {}
248
MarkContextCleanForFrameCapture()249 void ImageBitmapRenderingContext::MarkContextCleanForFrameCapture() {}
250
IsContextCleanForFrameCapture()251 bool ImageBitmapRenderingContext::IsContextCleanForFrameCapture() {
252 return true;
253 }
254
255 NS_IMPL_CYCLE_COLLECTING_ADDREF(ImageBitmapRenderingContext)
256 NS_IMPL_CYCLE_COLLECTING_RELEASE(ImageBitmapRenderingContext)
257
258 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ImageBitmapRenderingContext,
259 mCanvasElement, mOffscreenCanvas)
260
261 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ImageBitmapRenderingContext)
262 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
263 NS_INTERFACE_MAP_ENTRY(nsICanvasRenderingContextInternal)
264 NS_INTERFACE_MAP_ENTRY(nsISupports)
265 NS_INTERFACE_MAP_END
266
267 } // namespace dom
268 } // namespace mozilla
269