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