Bug 1610357 [wpt PR 21278] - Update wpt metadata, a=testonly
[gecko.git] / image / imgTools.cpp
blobd26d0c8a359eb91e671697f5c6a7d24911cac053
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "imgTools.h"
9 #include "DecodePool.h"
10 #include "gfxUtils.h"
11 #include "mozilla/gfx/2D.h"
12 #include "mozilla/gfx/Logging.h"
13 #include "mozilla/RefPtr.h"
14 #include "nsCOMPtr.h"
15 #include "mozilla/dom/Document.h"
16 #include "nsError.h"
17 #include "imgLoader.h"
18 #include "imgICache.h"
19 #include "imgIContainer.h"
20 #include "imgIEncoder.h"
21 #include "nsNetUtil.h" // for NS_NewBufferedInputStream
22 #include "nsStreamUtils.h"
23 #include "nsStringStream.h"
24 #include "nsContentUtils.h"
25 #include "nsProxyRelease.h"
26 #include "nsIStreamListener.h"
27 #include "ImageFactory.h"
28 #include "Image.h"
29 #include "IProgressObserver.h"
30 #include "ScriptedNotificationObserver.h"
31 #include "imgIScriptedNotificationObserver.h"
32 #include "gfxPlatform.h"
33 #include "js/ArrayBuffer.h"
34 #include "js/RootingAPI.h" // JS::{Handle,Rooted}
35 #include "js/Value.h" // JS::Value
37 using namespace mozilla::gfx;
39 namespace mozilla {
40 namespace image {
42 namespace {
44 static nsresult sniff_mimetype_callback(nsIInputStream* in, void* data,
45 const char* fromRawSegment,
46 uint32_t toOffset, uint32_t count,
47 uint32_t* writeCount) {
48 nsCString* mimeType = static_cast<nsCString*>(data);
49 MOZ_ASSERT(mimeType, "mimeType is null!");
51 if (count > 0) {
52 imgLoader::GetMimeTypeFromContent(fromRawSegment, count, *mimeType);
55 *writeCount = 0;
56 return NS_ERROR_FAILURE;
59 // Provides WeakPtr for imgINotificationObserver
60 class NotificationObserverWrapper
61 : public imgINotificationObserver,
62 public mozilla::SupportsWeakPtr<NotificationObserverWrapper> {
63 public:
64 NS_DECL_ISUPPORTS
65 NS_FORWARD_IMGINOTIFICATIONOBSERVER(mObserver->)
66 MOZ_DECLARE_WEAKREFERENCE_TYPENAME(nsGeolocationRequest)
68 explicit NotificationObserverWrapper(imgINotificationObserver* observer)
69 : mObserver(observer) {}
71 private:
72 virtual ~NotificationObserverWrapper() = default;
73 nsCOMPtr<imgINotificationObserver> mObserver;
76 NS_IMPL_ISUPPORTS(NotificationObserverWrapper, imgINotificationObserver)
78 class ImageDecoderListener final : public nsIStreamListener,
79 public IProgressObserver,
80 public imgIContainer {
81 public:
82 NS_DECL_ISUPPORTS
84 ImageDecoderListener(nsIURI* aURI, imgIContainerCallback* aCallback,
85 imgINotificationObserver* aObserver)
86 : mURI(aURI),
87 mImage(nullptr),
88 mCallback(aCallback),
89 mObserver(aObserver ? new NotificationObserverWrapper(aObserver)
90 : nullptr) {
91 MOZ_ASSERT(NS_IsMainThread());
94 NS_IMETHOD
95 OnDataAvailable(nsIRequest* aRequest, nsIInputStream* aInputStream,
96 uint64_t aOffset, uint32_t aCount) override {
97 if (!mImage) {
98 nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
100 nsCString mimeType;
101 channel->GetContentType(mimeType);
103 if (aInputStream) {
104 // Look at the first few bytes and see if we can tell what the data is
105 // from that since servers tend to lie. :(
106 uint32_t unused;
107 aInputStream->ReadSegments(sniff_mimetype_callback, &mimeType, aCount,
108 &unused);
111 RefPtr<ProgressTracker> tracker = new ProgressTracker();
112 if (mObserver) {
113 tracker->AddObserver(this);
116 mImage = ImageFactory::CreateImage(channel, tracker, mimeType, mURI,
117 /* aIsMultiPart */ false, 0);
119 if (mImage->HasError()) {
120 return NS_ERROR_FAILURE;
124 return mImage->OnImageDataAvailable(aRequest, nullptr, aInputStream,
125 aOffset, aCount);
128 NS_IMETHOD
129 OnStartRequest(nsIRequest* aRequest) override { return NS_OK; }
131 NS_IMETHOD
132 OnStopRequest(nsIRequest* aRequest, nsresult aStatus) override {
133 // Depending on the error, we might not have received any data yet, in which
134 // case we would not have an |mImage|
135 if (mImage) {
136 mImage->OnImageDataComplete(aRequest, nullptr, aStatus, true);
139 nsCOMPtr<imgIContainer> container;
140 if (NS_SUCCEEDED(aStatus)) {
141 container = this;
144 mCallback->OnImageReady(container, aStatus);
145 return NS_OK;
148 virtual void Notify(int32_t aType,
149 const nsIntRect* aRect = nullptr) override {
150 if (mObserver) {
151 mObserver->Notify(nullptr, aType, aRect);
155 virtual void OnLoadComplete(bool aLastPart) override {}
157 // Other notifications are ignored.
158 virtual void SetHasImage() override {}
159 virtual bool NotificationsDeferred() const override { return false; }
160 virtual void MarkPendingNotify() override {}
161 virtual void ClearPendingNotify() override {}
163 // imgIContainer
164 NS_FORWARD_IMGICONTAINER(mImage->)
166 nsresult GetNativeSizes(nsTArray<nsIntSize>& aNativeSizes) const override {
167 return mImage->GetNativeSizes(aNativeSizes);
170 size_t GetNativeSizesLength() const override {
171 return mImage->GetNativeSizesLength();
174 private:
175 virtual ~ImageDecoderListener() = default;
177 nsCOMPtr<nsIURI> mURI;
178 RefPtr<image::Image> mImage;
179 nsCOMPtr<imgIContainerCallback> mCallback;
180 WeakPtr<NotificationObserverWrapper> mObserver;
183 NS_IMPL_ISUPPORTS(ImageDecoderListener, nsIStreamListener, imgIContainer)
185 class ImageDecoderHelper final : public Runnable,
186 public nsIInputStreamCallback {
187 public:
188 NS_DECL_ISUPPORTS_INHERITED
190 ImageDecoderHelper(already_AddRefed<image::Image> aImage,
191 already_AddRefed<nsIInputStream> aInputStream,
192 nsIEventTarget* aEventTarget,
193 imgIContainerCallback* aCallback,
194 nsIEventTarget* aCallbackEventTarget)
195 : Runnable("ImageDecoderHelper"),
196 mImage(std::move(aImage)),
197 mInputStream(std::move(aInputStream)),
198 mEventTarget(aEventTarget),
199 mCallback(aCallback),
200 mCallbackEventTarget(aCallbackEventTarget),
201 mStatus(NS_OK) {
202 MOZ_ASSERT(NS_IsMainThread());
205 NS_IMETHOD
206 Run() override {
207 // This runnable is dispatched on the Image thread when reading data, but
208 // at the end, it goes back to the main-thread in order to complete the
209 // operation.
210 if (NS_IsMainThread()) {
211 // Let the Image know we've sent all the data.
212 mImage->OnImageDataComplete(nullptr, nullptr, mStatus, true);
214 RefPtr<ProgressTracker> tracker = mImage->GetProgressTracker();
215 tracker->SyncNotifyProgress(FLAG_LOAD_COMPLETE);
217 nsCOMPtr<imgIContainer> container;
218 if (NS_SUCCEEDED(mStatus)) {
219 container = mImage;
222 mCallback->OnImageReady(container, mStatus);
223 return NS_OK;
226 uint64_t length;
227 nsresult rv = mInputStream->Available(&length);
228 if (rv == NS_BASE_STREAM_CLOSED) {
229 return OperationCompleted(NS_OK);
232 if (NS_WARN_IF(NS_FAILED(rv))) {
233 return OperationCompleted(rv);
236 // Nothing else to read, but maybe we just need to wait.
237 if (length == 0) {
238 nsCOMPtr<nsIAsyncInputStream> asyncInputStream =
239 do_QueryInterface(mInputStream);
240 if (asyncInputStream) {
241 rv = asyncInputStream->AsyncWait(this, 0, 0, mEventTarget);
242 if (NS_WARN_IF(NS_FAILED(rv))) {
243 return OperationCompleted(rv);
245 return NS_OK;
248 // We really have nothing else to read.
249 if (length == 0) {
250 return OperationCompleted(NS_OK);
254 // Send the source data to the Image.
255 rv = mImage->OnImageDataAvailable(nullptr, nullptr, mInputStream, 0,
256 uint32_t(length));
257 if (NS_WARN_IF(NS_FAILED(rv))) {
258 return OperationCompleted(rv);
261 rv = mEventTarget->Dispatch(this, NS_DISPATCH_NORMAL);
262 if (NS_WARN_IF(NS_FAILED(rv))) {
263 return OperationCompleted(rv);
266 return NS_OK;
269 NS_IMETHOD
270 OnInputStreamReady(nsIAsyncInputStream* aAsyncInputStream) override {
271 MOZ_ASSERT(!NS_IsMainThread());
272 return Run();
275 nsresult OperationCompleted(nsresult aStatus) {
276 MOZ_ASSERT(!NS_IsMainThread());
278 mStatus = aStatus;
279 mCallbackEventTarget->Dispatch(this, NS_DISPATCH_NORMAL);
280 return NS_OK;
283 private:
284 ~ImageDecoderHelper() {
285 NS_ReleaseOnMainThreadSystemGroup("ImageDecoderHelper::mImage",
286 mImage.forget());
287 NS_ReleaseOnMainThreadSystemGroup("ImageDecoderHelper::mCallback",
288 mCallback.forget());
291 RefPtr<image::Image> mImage;
293 nsCOMPtr<nsIInputStream> mInputStream;
294 nsCOMPtr<nsIEventTarget> mEventTarget;
295 nsCOMPtr<imgIContainerCallback> mCallback;
296 nsCOMPtr<nsIEventTarget> mCallbackEventTarget;
298 nsresult mStatus;
301 NS_IMPL_ISUPPORTS_INHERITED(ImageDecoderHelper, Runnable,
302 nsIInputStreamCallback)
304 } // namespace
306 /* ========== imgITools implementation ========== */
308 NS_IMPL_ISUPPORTS(imgTools, imgITools)
310 imgTools::imgTools() { /* member initializers and constructor code */
313 imgTools::~imgTools() { /* destructor code */
316 NS_IMETHODIMP
317 imgTools::DecodeImageFromArrayBuffer(JS::Handle<JS::Value> aArrayBuffer,
318 const nsACString& aMimeType,
319 JSContext* aCx,
320 imgIContainer** aContainer) {
321 if (!aArrayBuffer.isObject()) {
322 return NS_ERROR_FAILURE;
325 JS::Rooted<JSObject*> obj(aCx,
326 JS::UnwrapArrayBuffer(&aArrayBuffer.toObject()));
327 if (!obj) {
328 return NS_ERROR_FAILURE;
331 uint8_t* bufferData = nullptr;
332 uint32_t bufferLength = 0;
333 bool isSharedMemory = false;
335 JS::GetArrayBufferLengthAndData(obj, &bufferLength, &isSharedMemory,
336 &bufferData);
337 return DecodeImageFromBuffer((char*)bufferData, bufferLength, aMimeType,
338 aContainer);
341 NS_IMETHODIMP
342 imgTools::DecodeImageFromBuffer(const char* aBuffer, uint32_t aSize,
343 const nsACString& aMimeType,
344 imgIContainer** aContainer) {
345 MOZ_ASSERT(NS_IsMainThread());
347 NS_ENSURE_ARG_POINTER(aBuffer);
349 // Create a new image container to hold the decoded data.
350 nsAutoCString mimeType(aMimeType);
351 RefPtr<image::Image> image =
352 ImageFactory::CreateAnonymousImage(mimeType, aSize);
353 RefPtr<ProgressTracker> tracker = image->GetProgressTracker();
355 if (image->HasError()) {
356 return NS_ERROR_FAILURE;
359 // Let's create a temporary inputStream.
360 nsCOMPtr<nsIInputStream> stream;
361 nsresult rv = NS_NewByteInputStream(
362 getter_AddRefs(stream), MakeSpan(aBuffer, aSize), NS_ASSIGNMENT_DEPEND);
363 NS_ENSURE_SUCCESS(rv, rv);
364 MOZ_ASSERT(stream);
365 MOZ_ASSERT(NS_InputStreamIsBuffered(stream));
367 rv = image->OnImageDataAvailable(nullptr, nullptr, stream, 0, aSize);
368 NS_ENSURE_SUCCESS(rv, rv);
370 // Let the Image know we've sent all the data.
371 rv = image->OnImageDataComplete(nullptr, nullptr, NS_OK, true);
372 tracker->SyncNotifyProgress(FLAG_LOAD_COMPLETE);
373 NS_ENSURE_SUCCESS(rv, rv);
375 // All done.
376 image.forget(aContainer);
377 return NS_OK;
380 NS_IMETHODIMP
381 imgTools::DecodeImageFromChannelAsync(nsIURI* aURI, nsIChannel* aChannel,
382 imgIContainerCallback* aCallback,
383 imgINotificationObserver* aObserver) {
384 MOZ_ASSERT(NS_IsMainThread());
386 NS_ENSURE_ARG_POINTER(aURI);
387 NS_ENSURE_ARG_POINTER(aChannel);
388 NS_ENSURE_ARG_POINTER(aCallback);
390 RefPtr<ImageDecoderListener> listener =
391 new ImageDecoderListener(aURI, aCallback, aObserver);
393 return aChannel->AsyncOpen(listener);
396 NS_IMETHODIMP
397 imgTools::DecodeImageAsync(nsIInputStream* aInStr, const nsACString& aMimeType,
398 imgIContainerCallback* aCallback,
399 nsIEventTarget* aEventTarget) {
400 MOZ_ASSERT(NS_IsMainThread());
402 NS_ENSURE_ARG_POINTER(aInStr);
403 NS_ENSURE_ARG_POINTER(aCallback);
404 NS_ENSURE_ARG_POINTER(aEventTarget);
406 nsresult rv;
408 // Let's continuing the reading on a separate thread.
409 DecodePool* decodePool = DecodePool::Singleton();
410 MOZ_ASSERT(decodePool);
412 RefPtr<nsIEventTarget> target = decodePool->GetIOEventTarget();
413 NS_ENSURE_TRUE(target, NS_ERROR_FAILURE);
415 // Prepare the input stream.
416 nsCOMPtr<nsIInputStream> stream = aInStr;
417 if (!NS_InputStreamIsBuffered(aInStr)) {
418 nsCOMPtr<nsIInputStream> bufStream;
419 rv = NS_NewBufferedInputStream(getter_AddRefs(bufStream), stream.forget(),
420 1024);
421 NS_ENSURE_SUCCESS(rv, rv);
422 stream = bufStream.forget();
425 // Create a new image container to hold the decoded data.
426 nsAutoCString mimeType(aMimeType);
427 RefPtr<image::Image> image = ImageFactory::CreateAnonymousImage(mimeType, 0);
429 // Already an error?
430 if (image->HasError()) {
431 return NS_ERROR_FAILURE;
434 RefPtr<ImageDecoderHelper> helper = new ImageDecoderHelper(
435 image.forget(), stream.forget(), target, aCallback, aEventTarget);
436 rv = target->Dispatch(helper.forget(), NS_DISPATCH_NORMAL);
437 NS_ENSURE_SUCCESS(rv, rv);
439 return NS_OK;
443 * This takes a DataSourceSurface rather than a SourceSurface because some
444 * of the callers have a DataSourceSurface and we don't want to call
445 * GetDataSurface on such surfaces since that may incur a conversion to
446 * SurfaceType::DATA which we don't need.
448 static nsresult EncodeImageData(DataSourceSurface* aDataSurface,
449 DataSourceSurface::ScopedMap& aMap,
450 const nsACString& aMimeType,
451 const nsAString& aOutputOptions,
452 nsIInputStream** aStream) {
453 MOZ_ASSERT(aDataSurface->GetFormat() == SurfaceFormat::B8G8R8A8 ||
454 aDataSurface->GetFormat() == SurfaceFormat::B8G8R8X8,
455 "We're assuming B8G8R8A8/X8");
457 // Get an image encoder for the media type
458 nsAutoCString encoderCID(
459 NS_LITERAL_CSTRING("@mozilla.org/image/encoder;2?type=") + aMimeType);
461 nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(encoderCID.get());
462 if (!encoder) {
463 return NS_IMAGELIB_ERROR_NO_ENCODER;
466 IntSize size = aDataSurface->GetSize();
467 uint32_t dataLength = aMap.GetStride() * size.height;
469 // Encode the bitmap
470 nsresult rv = encoder->InitFromData(
471 aMap.GetData(), dataLength, size.width, size.height, aMap.GetStride(),
472 imgIEncoder::INPUT_FORMAT_HOSTARGB, aOutputOptions);
473 NS_ENSURE_SUCCESS(rv, rv);
475 encoder.forget(aStream);
476 return NS_OK;
479 static nsresult EncodeImageData(DataSourceSurface* aDataSurface,
480 const nsACString& aMimeType,
481 const nsAString& aOutputOptions,
482 nsIInputStream** aStream) {
483 DataSourceSurface::ScopedMap map(aDataSurface, DataSourceSurface::READ);
484 if (!map.IsMapped()) {
485 return NS_ERROR_FAILURE;
488 return EncodeImageData(aDataSurface, map, aMimeType, aOutputOptions, aStream);
491 NS_IMETHODIMP
492 imgTools::EncodeImage(imgIContainer* aContainer, const nsACString& aMimeType,
493 const nsAString& aOutputOptions,
494 nsIInputStream** aStream) {
495 // Use frame 0 from the image container.
496 RefPtr<SourceSurface> frame = aContainer->GetFrame(
497 imgIContainer::FRAME_FIRST,
498 imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_ASYNC_NOTIFY);
499 NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
501 RefPtr<DataSourceSurface> dataSurface;
503 if (frame->GetFormat() == SurfaceFormat::B8G8R8A8 ||
504 frame->GetFormat() == SurfaceFormat::B8G8R8X8) {
505 dataSurface = frame->GetDataSurface();
506 } else {
507 // Convert format to SurfaceFormat::B8G8R8A8
508 dataSurface = gfxUtils::CopySurfaceToDataSourceSurfaceWithFormat(
509 frame, SurfaceFormat::B8G8R8A8);
512 NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE);
514 return EncodeImageData(dataSurface, aMimeType, aOutputOptions, aStream);
517 NS_IMETHODIMP
518 imgTools::EncodeScaledImage(imgIContainer* aContainer,
519 const nsACString& aMimeType, int32_t aScaledWidth,
520 int32_t aScaledHeight,
521 const nsAString& aOutputOptions,
522 nsIInputStream** aStream) {
523 NS_ENSURE_ARG(aScaledWidth >= 0 && aScaledHeight >= 0);
525 // If no scaled size is specified, we'll just encode the image at its
526 // original size (no scaling).
527 if (aScaledWidth == 0 && aScaledHeight == 0) {
528 return EncodeImage(aContainer, aMimeType, aOutputOptions, aStream);
531 // Retrieve the image's size.
532 int32_t imageWidth = 0;
533 int32_t imageHeight = 0;
534 aContainer->GetWidth(&imageWidth);
535 aContainer->GetHeight(&imageHeight);
537 // If the given width or height is zero we'll replace it with the image's
538 // original dimensions.
539 IntSize scaledSize(aScaledWidth == 0 ? imageWidth : aScaledWidth,
540 aScaledHeight == 0 ? imageHeight : aScaledHeight);
542 // Use frame 0 from the image container.
543 RefPtr<SourceSurface> frame = aContainer->GetFrameAtSize(
544 scaledSize, imgIContainer::FRAME_FIRST,
545 imgIContainer::FLAG_HIGH_QUALITY_SCALING |
546 imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_ASYNC_NOTIFY);
547 NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
549 // If the given surface is the right size/format, we can encode it directly.
550 if (scaledSize == frame->GetSize() &&
551 (frame->GetFormat() == SurfaceFormat::B8G8R8A8 ||
552 frame->GetFormat() == SurfaceFormat::B8G8R8X8)) {
553 RefPtr<DataSourceSurface> dataSurface = frame->GetDataSurface();
554 if (dataSurface) {
555 return EncodeImageData(dataSurface, aMimeType, aOutputOptions, aStream);
559 // Otherwise we need to scale it using a draw target.
560 RefPtr<DataSourceSurface> dataSurface =
561 Factory::CreateDataSourceSurface(scaledSize, SurfaceFormat::B8G8R8A8);
562 if (NS_WARN_IF(!dataSurface)) {
563 return NS_ERROR_FAILURE;
566 DataSourceSurface::ScopedMap map(dataSurface, DataSourceSurface::READ_WRITE);
567 if (!map.IsMapped()) {
568 return NS_ERROR_FAILURE;
571 RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(
572 BackendType::SKIA, map.GetData(), dataSurface->GetSize(), map.GetStride(),
573 SurfaceFormat::B8G8R8A8);
574 if (!dt) {
575 gfxWarning() << "imgTools::EncodeImage failed in CreateDrawTargetForData";
576 return NS_ERROR_OUT_OF_MEMORY;
579 IntSize frameSize = frame->GetSize();
580 dt->DrawSurface(frame, Rect(0, 0, scaledSize.width, scaledSize.height),
581 Rect(0, 0, frameSize.width, frameSize.height),
582 DrawSurfaceOptions(),
583 DrawOptions(1.0f, CompositionOp::OP_SOURCE));
585 return EncodeImageData(dataSurface, map, aMimeType, aOutputOptions, aStream);
588 NS_IMETHODIMP
589 imgTools::EncodeCroppedImage(imgIContainer* aContainer,
590 const nsACString& aMimeType, int32_t aOffsetX,
591 int32_t aOffsetY, int32_t aWidth, int32_t aHeight,
592 const nsAString& aOutputOptions,
593 nsIInputStream** aStream) {
594 NS_ENSURE_ARG(aOffsetX >= 0 && aOffsetY >= 0 && aWidth >= 0 && aHeight >= 0);
596 // Offsets must be zero when no width and height are given or else we're out
597 // of bounds.
598 NS_ENSURE_ARG(aWidth + aHeight > 0 || aOffsetX + aOffsetY == 0);
600 // If no size is specified then we'll preserve the image's original dimensions
601 // and don't need to crop.
602 if (aWidth == 0 && aHeight == 0) {
603 return EncodeImage(aContainer, aMimeType, aOutputOptions, aStream);
606 // Use frame 0 from the image container.
607 RefPtr<SourceSurface> frame = aContainer->GetFrame(
608 imgIContainer::FRAME_FIRST,
609 imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_ASYNC_NOTIFY);
610 NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
612 int32_t frameWidth = frame->GetSize().width;
613 int32_t frameHeight = frame->GetSize().height;
615 // If the given width or height is zero we'll replace it with the image's
616 // original dimensions.
617 if (aWidth == 0) {
618 aWidth = frameWidth;
619 } else if (aHeight == 0) {
620 aHeight = frameHeight;
623 // Check that the given crop rectangle is within image bounds.
624 NS_ENSURE_ARG(frameWidth >= aOffsetX + aWidth &&
625 frameHeight >= aOffsetY + aHeight);
627 RefPtr<DataSourceSurface> dataSurface = Factory::CreateDataSourceSurface(
628 IntSize(aWidth, aHeight), SurfaceFormat::B8G8R8A8,
629 /* aZero = */ true);
630 if (NS_WARN_IF(!dataSurface)) {
631 return NS_ERROR_FAILURE;
634 DataSourceSurface::ScopedMap map(dataSurface, DataSourceSurface::READ_WRITE);
635 if (!map.IsMapped()) {
636 return NS_ERROR_FAILURE;
639 RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(
640 BackendType::SKIA, map.GetData(), dataSurface->GetSize(), map.GetStride(),
641 SurfaceFormat::B8G8R8A8);
642 if (!dt) {
643 gfxWarning()
644 << "imgTools::EncodeCroppedImage failed in CreateDrawTargetForData";
645 return NS_ERROR_OUT_OF_MEMORY;
647 dt->CopySurface(frame, IntRect(aOffsetX, aOffsetY, aWidth, aHeight),
648 IntPoint(0, 0));
650 return EncodeImageData(dataSurface, map, aMimeType, aOutputOptions, aStream);
653 NS_IMETHODIMP
654 imgTools::CreateScriptedObserver(imgIScriptedNotificationObserver* aInner,
655 imgINotificationObserver** aObserver) {
656 NS_ADDREF(*aObserver = new ScriptedNotificationObserver(aInner));
657 return NS_OK;
660 NS_IMETHODIMP
661 imgTools::GetImgLoaderForDocument(dom::Document* aDoc, imgILoader** aLoader) {
662 NS_IF_ADDREF(*aLoader = nsContentUtils::GetImgLoaderForDocument(aDoc));
663 return NS_OK;
666 NS_IMETHODIMP
667 imgTools::GetImgCacheForDocument(dom::Document* aDoc, imgICache** aCache) {
668 nsCOMPtr<imgILoader> loader;
669 nsresult rv = GetImgLoaderForDocument(aDoc, getter_AddRefs(loader));
670 NS_ENSURE_SUCCESS(rv, rv);
671 return CallQueryInterface(loader, aCache);
674 } // namespace image
675 } // namespace mozilla