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 "nsStreamUtils.h"
20 #include "OrientedImage.h"
21 #include "SourceBuffer.h"
23 using namespace mozilla::gfx
;
28 /* static */ already_AddRefed
<Image
>
29 ImageOps::Freeze(Image
* aImage
)
31 RefPtr
<Image
> frozenImage
= new FrozenImage(aImage
);
32 return frozenImage
.forget();
35 /* static */ already_AddRefed
<imgIContainer
>
36 ImageOps::Freeze(imgIContainer
* aImage
)
38 nsCOMPtr
<imgIContainer
> frozenImage
=
39 new FrozenImage(static_cast<Image
*>(aImage
));
40 return frozenImage
.forget();
43 /* static */ already_AddRefed
<Image
>
44 ImageOps::Clip(Image
* aImage
, nsIntRect aClip
,
45 const Maybe
<nsSize
>& aSVGViewportSize
)
47 RefPtr
<Image
> clippedImage
= new ClippedImage(aImage
, aClip
, aSVGViewportSize
);
48 return clippedImage
.forget();
51 /* static */ already_AddRefed
<imgIContainer
>
52 ImageOps::Clip(imgIContainer
* aImage
, nsIntRect aClip
,
53 const Maybe
<nsSize
>& aSVGViewportSize
)
55 nsCOMPtr
<imgIContainer
> clippedImage
=
56 new ClippedImage(static_cast<Image
*>(aImage
), aClip
, aSVGViewportSize
);
57 return clippedImage
.forget();
60 /* static */ already_AddRefed
<Image
>
61 ImageOps::Orient(Image
* aImage
, Orientation aOrientation
)
63 RefPtr
<Image
> orientedImage
= new OrientedImage(aImage
, aOrientation
);
64 return orientedImage
.forget();
67 /* static */ already_AddRefed
<imgIContainer
>
68 ImageOps::Orient(imgIContainer
* aImage
, Orientation aOrientation
)
70 nsCOMPtr
<imgIContainer
> orientedImage
=
71 new OrientedImage(static_cast<Image
*>(aImage
), aOrientation
);
72 return orientedImage
.forget();
75 /* static */ already_AddRefed
<imgIContainer
>
76 ImageOps::CreateFromDrawable(gfxDrawable
* aDrawable
)
78 nsCOMPtr
<imgIContainer
> drawableImage
= new DynamicImage(aDrawable
);
79 return drawableImage
.forget();
82 class ImageOps::ImageBufferImpl final
: public ImageOps::ImageBuffer
{
84 explicit ImageBufferImpl(already_AddRefed
<SourceBuffer
> aSourceBuffer
)
85 : mSourceBuffer(aSourceBuffer
)
89 ~ImageBufferImpl() override
{ }
91 already_AddRefed
<SourceBuffer
> GetSourceBuffer() const override
93 RefPtr
<SourceBuffer
> sourceBuffer
= mSourceBuffer
;
94 return sourceBuffer
.forget();
98 RefPtr
<SourceBuffer
> mSourceBuffer
;
101 /* static */ already_AddRefed
<ImageOps::ImageBuffer
>
102 ImageOps::CreateImageBuffer(already_AddRefed
<nsIInputStream
> aInputStream
)
104 nsCOMPtr
<nsIInputStream
> inputStream
= Move(aInputStream
);
105 MOZ_ASSERT(inputStream
);
109 // Prepare the input stream.
110 if (!NS_InputStreamIsBuffered(inputStream
)) {
111 nsCOMPtr
<nsIInputStream
> bufStream
;
112 rv
= NS_NewBufferedInputStream(getter_AddRefs(bufStream
),
113 inputStream
.forget(), 1024);
114 if (NS_WARN_IF(NS_FAILED(rv
))) {
119 // Figure out how much data we've been passed.
121 rv
= inputStream
->Available(&length
);
122 if (NS_FAILED(rv
) || length
> UINT32_MAX
) {
126 // Write the data into a SourceBuffer.
127 RefPtr
<SourceBuffer
> sourceBuffer
= new SourceBuffer();
128 sourceBuffer
->ExpectLength(length
);
129 rv
= sourceBuffer
->AppendFromInputStream(inputStream
, length
);
133 // Make sure our sourceBuffer is marked as complete.
134 if (sourceBuffer
->IsComplete()) {
135 NS_WARNING("The SourceBuffer was unexpectedly marked as complete. This may "
136 "indicate either an OOM condition, or that imagelib was not "
137 "initialized properly.");
140 sourceBuffer
->Complete(NS_OK
);
142 RefPtr
<ImageBuffer
> imageBuffer
= new ImageBufferImpl(sourceBuffer
.forget());
143 return imageBuffer
.forget();
146 /* static */ nsresult
147 ImageOps::DecodeMetadata(already_AddRefed
<nsIInputStream
> aInputStream
,
148 const nsACString
& aMimeType
,
149 ImageMetadata
& aMetadata
)
151 nsCOMPtr
<nsIInputStream
> inputStream
= Move(aInputStream
);
152 RefPtr
<ImageBuffer
> buffer
= CreateImageBuffer(inputStream
.forget());
153 return DecodeMetadata(buffer
, aMimeType
, aMetadata
);
156 /* static */ nsresult
157 ImageOps::DecodeMetadata(ImageBuffer
* aBuffer
,
158 const nsACString
& aMimeType
,
159 ImageMetadata
& aMetadata
)
162 return NS_ERROR_FAILURE
;
165 RefPtr
<SourceBuffer
> sourceBuffer
= aBuffer
->GetSourceBuffer();
166 if (NS_WARN_IF(!sourceBuffer
)) {
167 return NS_ERROR_FAILURE
;
171 DecoderType decoderType
=
172 DecoderFactory::GetDecoderType(PromiseFlatCString(aMimeType
).get());
173 RefPtr
<Decoder
> decoder
=
174 DecoderFactory::CreateAnonymousMetadataDecoder(decoderType
,
175 WrapNotNull(sourceBuffer
));
177 return NS_ERROR_FAILURE
;
180 // Run the decoder synchronously.
181 RefPtr
<IDecodingTask
> task
= new AnonymousDecodingTask(WrapNotNull(decoder
));
183 if (!decoder
->GetDecodeDone() || decoder
->HasError()) {
184 return NS_ERROR_FAILURE
;
187 aMetadata
= decoder
->GetImageMetadata();
188 if (aMetadata
.GetNativeSizes().IsEmpty() && aMetadata
.HasSize()) {
189 aMetadata
.AddNativeSize(aMetadata
.GetSize());
195 /* static */ already_AddRefed
<gfx::SourceSurface
>
196 ImageOps::DecodeToSurface(already_AddRefed
<nsIInputStream
> aInputStream
,
197 const nsACString
& aMimeType
,
199 const Maybe
<IntSize
>& aSize
/* = Nothing() */)
201 nsCOMPtr
<nsIInputStream
> inputStream
= Move(aInputStream
);
202 RefPtr
<ImageBuffer
> buffer
= CreateImageBuffer(inputStream
.forget());
203 return DecodeToSurface(buffer
, aMimeType
, aFlags
, aSize
);
206 /* static */ already_AddRefed
<gfx::SourceSurface
>
207 ImageOps::DecodeToSurface(ImageBuffer
* aBuffer
,
208 const nsACString
& aMimeType
,
210 const Maybe
<IntSize
>& aSize
/* = Nothing() */)
216 RefPtr
<SourceBuffer
> sourceBuffer
= aBuffer
->GetSourceBuffer();
217 if (NS_WARN_IF(!sourceBuffer
)) {
222 DecoderType decoderType
=
223 DecoderFactory::GetDecoderType(PromiseFlatCString(aMimeType
).get());
224 RefPtr
<Decoder
> decoder
=
225 DecoderFactory::CreateAnonymousDecoder(decoderType
,
226 WrapNotNull(sourceBuffer
),
227 aSize
, ToSurfaceFlags(aFlags
));
232 // Run the decoder synchronously.
233 RefPtr
<IDecodingTask
> task
= new AnonymousDecodingTask(WrapNotNull(decoder
));
235 if (!decoder
->GetDecodeDone() || decoder
->HasError()) {
239 // Pull out the surface.
240 RawAccessFrameRef frame
= decoder
->GetCurrentFrameRef();
245 RefPtr
<SourceSurface
> surface
= frame
->GetSourceSurface();
250 return surface
.forget();
254 } // namespace mozilla