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/. */
9 #include "ClippedImage.h"
11 #include "DecoderFactory.h"
12 #include "DynamicImage.h"
13 #include "FrozenImage.h"
14 #include "IDecodingTask.h"
16 #include "ImageMetadata.h"
17 #include "imgIContainer.h"
18 #include "mozilla/gfx/2D.h"
19 #include "nsNetUtil.h" // for NS_NewBufferedInputStream
20 #include "nsStreamUtils.h"
21 #include "OrientedImage.h"
22 #include "SourceBuffer.h"
24 using namespace mozilla::gfx
;
26 namespace mozilla::image
{
29 already_AddRefed
<Image
> ImageOps::Freeze(Image
* aImage
) {
30 RefPtr
<Image
> frozenImage
= new FrozenImage(aImage
);
31 return frozenImage
.forget();
35 already_AddRefed
<imgIContainer
> ImageOps::Freeze(imgIContainer
* aImage
) {
36 nsCOMPtr
<imgIContainer
> frozenImage
=
37 new FrozenImage(static_cast<Image
*>(aImage
));
38 return frozenImage
.forget();
42 already_AddRefed
<Image
> ImageOps::Clip(Image
* aImage
, nsIntRect aClip
,
43 const Maybe
<nsSize
>& aSVGViewportSize
) {
44 RefPtr
<Image
> clippedImage
=
45 new ClippedImage(aImage
, aClip
, aSVGViewportSize
);
46 return clippedImage
.forget();
50 already_AddRefed
<imgIContainer
> ImageOps::Clip(
51 imgIContainer
* aImage
, nsIntRect aClip
,
52 const Maybe
<nsSize
>& aSVGViewportSize
) {
53 nsCOMPtr
<imgIContainer
> clippedImage
=
54 new ClippedImage(static_cast<Image
*>(aImage
), aClip
, aSVGViewportSize
);
55 return clippedImage
.forget();
59 already_AddRefed
<Image
> ImageOps::Orient(Image
* aImage
,
60 Orientation aOrientation
) {
61 if (aOrientation
.IsIdentity()) {
62 return do_AddRef(aImage
);
64 RefPtr
<Image
> image
= new OrientedImage(aImage
, aOrientation
);
65 return image
.forget();
69 already_AddRefed
<imgIContainer
> ImageOps::Orient(imgIContainer
* aImage
,
70 Orientation aOrientation
) {
71 return Orient(static_cast<Image
*>(aImage
), aOrientation
);
75 already_AddRefed
<imgIContainer
> ImageOps::Unorient(imgIContainer
* aImage
) {
76 return Orient(aImage
, aImage
->GetOrientation().Reversed());
80 already_AddRefed
<imgIContainer
> ImageOps::CreateFromDrawable(
81 gfxDrawable
* aDrawable
) {
82 nsCOMPtr
<imgIContainer
> drawableImage
= new DynamicImage(aDrawable
);
83 return drawableImage
.forget();
86 class ImageOps::ImageBufferImpl final
: public ImageOps::ImageBuffer
{
88 explicit ImageBufferImpl(already_AddRefed
<SourceBuffer
> aSourceBuffer
)
89 : mSourceBuffer(aSourceBuffer
) {}
92 ~ImageBufferImpl() override
{}
94 already_AddRefed
<SourceBuffer
> GetSourceBuffer() const override
{
95 RefPtr
<SourceBuffer
> sourceBuffer
= mSourceBuffer
;
96 return sourceBuffer
.forget();
100 RefPtr
<SourceBuffer
> mSourceBuffer
;
103 /* static */ already_AddRefed
<ImageOps::ImageBuffer
>
104 ImageOps::CreateImageBuffer(already_AddRefed
<nsIInputStream
> aInputStream
) {
105 nsCOMPtr
<nsIInputStream
> inputStream
= std::move(aInputStream
);
106 MOZ_ASSERT(inputStream
);
110 // Prepare the input stream.
111 if (!NS_InputStreamIsBuffered(inputStream
)) {
112 nsCOMPtr
<nsIInputStream
> bufStream
;
113 rv
= NS_NewBufferedInputStream(getter_AddRefs(bufStream
),
114 inputStream
.forget(), 1024);
115 if (NS_WARN_IF(NS_FAILED(rv
))) {
118 inputStream
= std::move(bufStream
);
121 // Figure out how much data we've been passed.
123 rv
= inputStream
->Available(&length
);
124 if (NS_FAILED(rv
) || length
> UINT32_MAX
) {
128 // Write the data into a SourceBuffer.
129 RefPtr
<SourceBuffer
> sourceBuffer
= new SourceBuffer();
130 sourceBuffer
->ExpectLength(length
);
131 rv
= sourceBuffer
->AppendFromInputStream(inputStream
, length
);
135 // Make sure our sourceBuffer is marked as complete.
136 if (sourceBuffer
->IsComplete()) {
138 "The SourceBuffer was unexpectedly marked as complete. This may "
139 "indicate either an OOM condition, or that imagelib was not "
140 "initialized properly.");
143 sourceBuffer
->Complete(NS_OK
);
145 RefPtr
<ImageBuffer
> imageBuffer
= new ImageBufferImpl(sourceBuffer
.forget());
146 return imageBuffer
.forget();
150 nsresult
ImageOps::DecodeMetadata(already_AddRefed
<nsIInputStream
> aInputStream
,
151 const nsACString
& aMimeType
,
152 ImageMetadata
& aMetadata
) {
153 nsCOMPtr
<nsIInputStream
> inputStream
= std::move(aInputStream
);
154 RefPtr
<ImageBuffer
> buffer
= CreateImageBuffer(inputStream
.forget());
155 return DecodeMetadata(buffer
, aMimeType
, aMetadata
);
159 nsresult
ImageOps::DecodeMetadata(ImageBuffer
* aBuffer
,
160 const nsACString
& aMimeType
,
161 ImageMetadata
& aMetadata
) {
163 return NS_ERROR_FAILURE
;
166 RefPtr
<SourceBuffer
> sourceBuffer
= aBuffer
->GetSourceBuffer();
167 if (NS_WARN_IF(!sourceBuffer
)) {
168 return NS_ERROR_FAILURE
;
172 DecoderType decoderType
=
173 DecoderFactory::GetDecoderType(PromiseFlatCString(aMimeType
).get());
174 RefPtr
<Decoder
> decoder
= DecoderFactory::CreateAnonymousMetadataDecoder(
175 decoderType
, WrapNotNull(sourceBuffer
));
177 return NS_ERROR_FAILURE
;
180 // Run the decoder synchronously.
181 RefPtr
<IDecodingTask
> task
=
182 new AnonymousDecodingTask(WrapNotNull(decoder
), /* aResumable */ false);
184 if (!decoder
->GetDecodeDone() || decoder
->HasError()) {
185 return NS_ERROR_FAILURE
;
188 aMetadata
= decoder
->GetImageMetadata();
189 if (aMetadata
.GetNativeSizes().IsEmpty() && aMetadata
.HasSize()) {
190 aMetadata
.AddNativeSize(aMetadata
.GetSize());
196 /* static */ already_AddRefed
<gfx::SourceSurface
> ImageOps::DecodeToSurface(
197 already_AddRefed
<nsIInputStream
> aInputStream
, const nsACString
& aMimeType
,
198 uint32_t aFlags
, const Maybe
<IntSize
>& aSize
/* = Nothing() */) {
199 nsCOMPtr
<nsIInputStream
> inputStream
= std::move(aInputStream
);
200 RefPtr
<ImageBuffer
> buffer
= CreateImageBuffer(inputStream
.forget());
201 return DecodeToSurface(buffer
, aMimeType
, aFlags
, aSize
);
204 /* static */ already_AddRefed
<gfx::SourceSurface
> ImageOps::DecodeToSurface(
205 ImageBuffer
* aBuffer
, const nsACString
& aMimeType
, uint32_t aFlags
,
206 const Maybe
<IntSize
>& aSize
/* = Nothing() */) {
211 RefPtr
<SourceBuffer
> sourceBuffer
= aBuffer
->GetSourceBuffer();
212 if (NS_WARN_IF(!sourceBuffer
)) {
217 DecoderType decoderType
=
218 DecoderFactory::GetDecoderType(PromiseFlatCString(aMimeType
).get());
219 RefPtr
<Decoder
> decoder
= DecoderFactory::CreateAnonymousDecoder(
220 decoderType
, WrapNotNull(sourceBuffer
), aSize
,
221 DecoderFlags::FIRST_FRAME_ONLY
, ToSurfaceFlags(aFlags
));
226 // Run the decoder synchronously.
227 RefPtr
<IDecodingTask
> task
=
228 new AnonymousDecodingTask(WrapNotNull(decoder
), /* aResumable */ false);
230 if (!decoder
->GetDecodeDone() || decoder
->HasError()) {
234 // Pull out the surface.
235 RawAccessFrameRef frame
= decoder
->GetCurrentFrameRef();
240 RefPtr
<SourceSurface
> surface
= frame
->GetSourceSurface();
245 return surface
.forget();
248 } // namespace mozilla::image