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
;
30 already_AddRefed
<Image
> ImageOps::Freeze(Image
* aImage
) {
31 RefPtr
<Image
> frozenImage
= new FrozenImage(aImage
);
32 return frozenImage
.forget();
36 already_AddRefed
<imgIContainer
> ImageOps::Freeze(imgIContainer
* aImage
) {
37 nsCOMPtr
<imgIContainer
> frozenImage
=
38 new FrozenImage(static_cast<Image
*>(aImage
));
39 return frozenImage
.forget();
43 already_AddRefed
<Image
> ImageOps::Clip(Image
* aImage
, nsIntRect aClip
,
44 const Maybe
<nsSize
>& aSVGViewportSize
) {
45 RefPtr
<Image
> clippedImage
=
46 new ClippedImage(aImage
, aClip
, aSVGViewportSize
);
47 return clippedImage
.forget();
51 already_AddRefed
<imgIContainer
> ImageOps::Clip(
52 imgIContainer
* aImage
, nsIntRect aClip
,
53 const Maybe
<nsSize
>& aSVGViewportSize
) {
54 nsCOMPtr
<imgIContainer
> clippedImage
=
55 new ClippedImage(static_cast<Image
*>(aImage
), aClip
, aSVGViewportSize
);
56 return clippedImage
.forget();
60 already_AddRefed
<Image
> ImageOps::Orient(Image
* aImage
,
61 Orientation aOrientation
) {
62 RefPtr
<Image
> orientedImage
= new OrientedImage(aImage
, aOrientation
);
63 return orientedImage
.forget();
67 already_AddRefed
<imgIContainer
> ImageOps::Orient(imgIContainer
* aImage
,
68 Orientation aOrientation
) {
69 nsCOMPtr
<imgIContainer
> orientedImage
=
70 new OrientedImage(static_cast<Image
*>(aImage
), aOrientation
);
71 return orientedImage
.forget();
75 already_AddRefed
<imgIContainer
> ImageOps::Unorient(imgIContainer
* aImage
) {
76 Orientation orientation
= aImage
->GetOrientation().Reversed();
77 nsCOMPtr
<imgIContainer
> orientedImage
=
78 new OrientedImage(static_cast<Image
*>(aImage
), orientation
);
79 return orientedImage
.forget();
83 already_AddRefed
<imgIContainer
> ImageOps::CreateFromDrawable(
84 gfxDrawable
* aDrawable
) {
85 nsCOMPtr
<imgIContainer
> drawableImage
= new DynamicImage(aDrawable
);
86 return drawableImage
.forget();
89 class ImageOps::ImageBufferImpl final
: public ImageOps::ImageBuffer
{
91 explicit ImageBufferImpl(already_AddRefed
<SourceBuffer
> aSourceBuffer
)
92 : mSourceBuffer(aSourceBuffer
) {}
95 ~ImageBufferImpl() override
{}
97 already_AddRefed
<SourceBuffer
> GetSourceBuffer() const override
{
98 RefPtr
<SourceBuffer
> sourceBuffer
= mSourceBuffer
;
99 return sourceBuffer
.forget();
103 RefPtr
<SourceBuffer
> mSourceBuffer
;
106 /* static */ already_AddRefed
<ImageOps::ImageBuffer
>
107 ImageOps::CreateImageBuffer(already_AddRefed
<nsIInputStream
> aInputStream
) {
108 nsCOMPtr
<nsIInputStream
> inputStream
= std::move(aInputStream
);
109 MOZ_ASSERT(inputStream
);
113 // Prepare the input stream.
114 if (!NS_InputStreamIsBuffered(inputStream
)) {
115 nsCOMPtr
<nsIInputStream
> bufStream
;
116 rv
= NS_NewBufferedInputStream(getter_AddRefs(bufStream
),
117 inputStream
.forget(), 1024);
118 if (NS_WARN_IF(NS_FAILED(rv
))) {
121 inputStream
= std::move(bufStream
);
124 // Figure out how much data we've been passed.
126 rv
= inputStream
->Available(&length
);
127 if (NS_FAILED(rv
) || length
> UINT32_MAX
) {
131 // Write the data into a SourceBuffer.
132 RefPtr
<SourceBuffer
> sourceBuffer
= new SourceBuffer();
133 sourceBuffer
->ExpectLength(length
);
134 rv
= sourceBuffer
->AppendFromInputStream(inputStream
, length
);
138 // Make sure our sourceBuffer is marked as complete.
139 if (sourceBuffer
->IsComplete()) {
141 "The SourceBuffer was unexpectedly marked as complete. This may "
142 "indicate either an OOM condition, or that imagelib was not "
143 "initialized properly.");
146 sourceBuffer
->Complete(NS_OK
);
148 RefPtr
<ImageBuffer
> imageBuffer
= new ImageBufferImpl(sourceBuffer
.forget());
149 return imageBuffer
.forget();
153 nsresult
ImageOps::DecodeMetadata(already_AddRefed
<nsIInputStream
> aInputStream
,
154 const nsACString
& aMimeType
,
155 ImageMetadata
& aMetadata
) {
156 nsCOMPtr
<nsIInputStream
> inputStream
= std::move(aInputStream
);
157 RefPtr
<ImageBuffer
> buffer
= CreateImageBuffer(inputStream
.forget());
158 return DecodeMetadata(buffer
, aMimeType
, aMetadata
);
162 nsresult
ImageOps::DecodeMetadata(ImageBuffer
* aBuffer
,
163 const nsACString
& aMimeType
,
164 ImageMetadata
& aMetadata
) {
166 return NS_ERROR_FAILURE
;
169 RefPtr
<SourceBuffer
> sourceBuffer
= aBuffer
->GetSourceBuffer();
170 if (NS_WARN_IF(!sourceBuffer
)) {
171 return NS_ERROR_FAILURE
;
175 DecoderType decoderType
=
176 DecoderFactory::GetDecoderType(PromiseFlatCString(aMimeType
).get());
177 RefPtr
<Decoder
> decoder
= DecoderFactory::CreateAnonymousMetadataDecoder(
178 decoderType
, WrapNotNull(sourceBuffer
));
180 return NS_ERROR_FAILURE
;
183 // Run the decoder synchronously.
184 RefPtr
<IDecodingTask
> task
=
185 new AnonymousDecodingTask(WrapNotNull(decoder
), /* aResumable */ false);
187 if (!decoder
->GetDecodeDone() || decoder
->HasError()) {
188 return NS_ERROR_FAILURE
;
191 aMetadata
= decoder
->GetImageMetadata();
192 if (aMetadata
.GetNativeSizes().IsEmpty() && aMetadata
.HasSize()) {
193 aMetadata
.AddNativeSize(aMetadata
.GetSize());
199 /* static */ already_AddRefed
<gfx::SourceSurface
> ImageOps::DecodeToSurface(
200 already_AddRefed
<nsIInputStream
> aInputStream
, const nsACString
& aMimeType
,
201 uint32_t aFlags
, const Maybe
<IntSize
>& aSize
/* = Nothing() */) {
202 nsCOMPtr
<nsIInputStream
> inputStream
= std::move(aInputStream
);
203 RefPtr
<ImageBuffer
> buffer
= CreateImageBuffer(inputStream
.forget());
204 return DecodeToSurface(buffer
, aMimeType
, aFlags
, aSize
);
207 /* static */ already_AddRefed
<gfx::SourceSurface
> ImageOps::DecodeToSurface(
208 ImageBuffer
* aBuffer
, const nsACString
& aMimeType
, uint32_t aFlags
,
209 const Maybe
<IntSize
>& aSize
/* = Nothing() */) {
214 RefPtr
<SourceBuffer
> sourceBuffer
= aBuffer
->GetSourceBuffer();
215 if (NS_WARN_IF(!sourceBuffer
)) {
220 DecoderType decoderType
=
221 DecoderFactory::GetDecoderType(PromiseFlatCString(aMimeType
).get());
222 RefPtr
<Decoder
> decoder
= DecoderFactory::CreateAnonymousDecoder(
223 decoderType
, WrapNotNull(sourceBuffer
), aSize
,
224 DecoderFlags::FIRST_FRAME_ONLY
, ToSurfaceFlags(aFlags
));
229 // Run the decoder synchronously.
230 RefPtr
<IDecodingTask
> task
=
231 new AnonymousDecodingTask(WrapNotNull(decoder
), /* aResumable */ false);
233 if (!decoder
->GetDecodeDone() || decoder
->HasError()) {
237 // Pull out the surface.
238 RawAccessFrameRef frame
= decoder
->GetCurrentFrameRef();
243 RefPtr
<SourceSurface
> surface
= frame
->GetSourceSurface();
248 return surface
.forget();
252 } // namespace mozilla