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