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
;
29 /* static */ already_AddRefed
<Image
> ImageOps::Freeze(Image
* aImage
) {
30 RefPtr
<Image
> frozenImage
= new FrozenImage(aImage
);
31 return frozenImage
.forget();
34 /* static */ already_AddRefed
<imgIContainer
> ImageOps::Freeze(
35 imgIContainer
* aImage
) {
36 nsCOMPtr
<imgIContainer
> frozenImage
=
37 new FrozenImage(static_cast<Image
*>(aImage
));
38 return frozenImage
.forget();
41 /* static */ already_AddRefed
<Image
> ImageOps::Clip(
42 Image
* aImage
, nsIntRect aClip
, const Maybe
<nsSize
>& aSVGViewportSize
) {
43 RefPtr
<Image
> clippedImage
=
44 new ClippedImage(aImage
, aClip
, aSVGViewportSize
);
45 return clippedImage
.forget();
48 /* static */ already_AddRefed
<imgIContainer
> ImageOps::Clip(
49 imgIContainer
* aImage
, nsIntRect aClip
,
50 const Maybe
<nsSize
>& aSVGViewportSize
) {
51 nsCOMPtr
<imgIContainer
> clippedImage
=
52 new ClippedImage(static_cast<Image
*>(aImage
), aClip
, aSVGViewportSize
);
53 return clippedImage
.forget();
56 /* static */ already_AddRefed
<Image
> ImageOps::Orient(
57 Image
* aImage
, Orientation aOrientation
) {
58 RefPtr
<Image
> orientedImage
= new OrientedImage(aImage
, aOrientation
);
59 return orientedImage
.forget();
62 /* static */ already_AddRefed
<imgIContainer
> ImageOps::Orient(
63 imgIContainer
* aImage
, Orientation aOrientation
) {
64 nsCOMPtr
<imgIContainer
> orientedImage
=
65 new OrientedImage(static_cast<Image
*>(aImage
), aOrientation
);
66 return orientedImage
.forget();
69 /* static */ already_AddRefed
<imgIContainer
> ImageOps::CreateFromDrawable(
70 gfxDrawable
* aDrawable
) {
71 nsCOMPtr
<imgIContainer
> drawableImage
= new DynamicImage(aDrawable
);
72 return drawableImage
.forget();
75 class ImageOps::ImageBufferImpl final
: public ImageOps::ImageBuffer
{
77 explicit ImageBufferImpl(already_AddRefed
<SourceBuffer
> aSourceBuffer
)
78 : mSourceBuffer(aSourceBuffer
) {}
81 ~ImageBufferImpl() override
{}
83 already_AddRefed
<SourceBuffer
> GetSourceBuffer() const override
{
84 RefPtr
<SourceBuffer
> sourceBuffer
= mSourceBuffer
;
85 return sourceBuffer
.forget();
89 RefPtr
<SourceBuffer
> mSourceBuffer
;
92 /* static */ already_AddRefed
<ImageOps::ImageBuffer
>
93 ImageOps::CreateImageBuffer(already_AddRefed
<nsIInputStream
> aInputStream
) {
94 nsCOMPtr
<nsIInputStream
> inputStream
= std::move(aInputStream
);
95 MOZ_ASSERT(inputStream
);
99 // Prepare the input stream.
100 if (!NS_InputStreamIsBuffered(inputStream
)) {
101 nsCOMPtr
<nsIInputStream
> bufStream
;
102 rv
= NS_NewBufferedInputStream(getter_AddRefs(bufStream
),
103 inputStream
.forget(), 1024);
104 if (NS_WARN_IF(NS_FAILED(rv
))) {
109 // Figure out how much data we've been passed.
111 rv
= inputStream
->Available(&length
);
112 if (NS_FAILED(rv
) || length
> UINT32_MAX
) {
116 // Write the data into a SourceBuffer.
117 RefPtr
<SourceBuffer
> sourceBuffer
= new SourceBuffer();
118 sourceBuffer
->ExpectLength(length
);
119 rv
= sourceBuffer
->AppendFromInputStream(inputStream
, length
);
123 // Make sure our sourceBuffer is marked as complete.
124 if (sourceBuffer
->IsComplete()) {
126 "The SourceBuffer was unexpectedly marked as complete. This may "
127 "indicate either an OOM condition, or that imagelib was not "
128 "initialized properly.");
131 sourceBuffer
->Complete(NS_OK
);
133 RefPtr
<ImageBuffer
> imageBuffer
= new ImageBufferImpl(sourceBuffer
.forget());
134 return imageBuffer
.forget();
137 /* static */ nsresult
ImageOps::DecodeMetadata(
138 already_AddRefed
<nsIInputStream
> aInputStream
, const nsACString
& aMimeType
,
139 ImageMetadata
& aMetadata
) {
140 nsCOMPtr
<nsIInputStream
> inputStream
= std::move(aInputStream
);
141 RefPtr
<ImageBuffer
> buffer
= CreateImageBuffer(inputStream
.forget());
142 return DecodeMetadata(buffer
, aMimeType
, aMetadata
);
145 /* static */ nsresult
ImageOps::DecodeMetadata(ImageBuffer
* aBuffer
,
146 const nsACString
& aMimeType
,
147 ImageMetadata
& aMetadata
) {
149 return NS_ERROR_FAILURE
;
152 RefPtr
<SourceBuffer
> sourceBuffer
= aBuffer
->GetSourceBuffer();
153 if (NS_WARN_IF(!sourceBuffer
)) {
154 return NS_ERROR_FAILURE
;
158 DecoderType decoderType
=
159 DecoderFactory::GetDecoderType(PromiseFlatCString(aMimeType
).get());
160 RefPtr
<Decoder
> decoder
= DecoderFactory::CreateAnonymousMetadataDecoder(
161 decoderType
, WrapNotNull(sourceBuffer
));
163 return NS_ERROR_FAILURE
;
166 // Run the decoder synchronously.
167 RefPtr
<IDecodingTask
> task
=
168 new AnonymousDecodingTask(WrapNotNull(decoder
), /* aResumable */ false);
170 if (!decoder
->GetDecodeDone() || decoder
->HasError()) {
171 return NS_ERROR_FAILURE
;
174 aMetadata
= decoder
->GetImageMetadata();
175 if (aMetadata
.GetNativeSizes().IsEmpty() && aMetadata
.HasSize()) {
176 aMetadata
.AddNativeSize(aMetadata
.GetSize());
182 /* static */ already_AddRefed
<gfx::SourceSurface
> ImageOps::DecodeToSurface(
183 already_AddRefed
<nsIInputStream
> aInputStream
, const nsACString
& aMimeType
,
184 uint32_t aFlags
, const Maybe
<IntSize
>& aSize
/* = Nothing() */) {
185 nsCOMPtr
<nsIInputStream
> inputStream
= std::move(aInputStream
);
186 RefPtr
<ImageBuffer
> buffer
= CreateImageBuffer(inputStream
.forget());
187 return DecodeToSurface(buffer
, aMimeType
, aFlags
, aSize
);
190 /* static */ already_AddRefed
<gfx::SourceSurface
> ImageOps::DecodeToSurface(
191 ImageBuffer
* aBuffer
, const nsACString
& aMimeType
, uint32_t aFlags
,
192 const Maybe
<IntSize
>& aSize
/* = Nothing() */) {
197 RefPtr
<SourceBuffer
> sourceBuffer
= aBuffer
->GetSourceBuffer();
198 if (NS_WARN_IF(!sourceBuffer
)) {
203 DecoderType decoderType
=
204 DecoderFactory::GetDecoderType(PromiseFlatCString(aMimeType
).get());
205 RefPtr
<Decoder
> decoder
= DecoderFactory::CreateAnonymousDecoder(
206 decoderType
, WrapNotNull(sourceBuffer
), aSize
,
207 DecoderFlags::FIRST_FRAME_ONLY
, ToSurfaceFlags(aFlags
));
212 // Run the decoder synchronously.
213 RefPtr
<IDecodingTask
> task
=
214 new AnonymousDecodingTask(WrapNotNull(decoder
), /* aResumable */ false);
216 if (!decoder
->GetDecodeDone() || decoder
->HasError()) {
220 // Pull out the surface.
221 RawAccessFrameRef frame
= decoder
->GetCurrentFrameRef();
226 RefPtr
<SourceSurface
> surface
= frame
->GetSourceSurface();
231 return surface
.forget();
235 } // namespace mozilla