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::CreateFromDrawable(
76 gfxDrawable
* aDrawable
) {
77 nsCOMPtr
<imgIContainer
> drawableImage
= new DynamicImage(aDrawable
);
78 return drawableImage
.forget();
81 class ImageOps::ImageBufferImpl final
: public ImageOps::ImageBuffer
{
83 explicit ImageBufferImpl(already_AddRefed
<SourceBuffer
> aSourceBuffer
)
84 : mSourceBuffer(aSourceBuffer
) {}
87 ~ImageBufferImpl() override
{}
89 already_AddRefed
<SourceBuffer
> GetSourceBuffer() const override
{
90 RefPtr
<SourceBuffer
> sourceBuffer
= mSourceBuffer
;
91 return sourceBuffer
.forget();
95 RefPtr
<SourceBuffer
> mSourceBuffer
;
98 /* static */ already_AddRefed
<ImageOps::ImageBuffer
>
99 ImageOps::CreateImageBuffer(already_AddRefed
<nsIInputStream
> aInputStream
) {
100 nsCOMPtr
<nsIInputStream
> inputStream
= std::move(aInputStream
);
101 MOZ_ASSERT(inputStream
);
105 // Prepare the input stream.
106 if (!NS_InputStreamIsBuffered(inputStream
)) {
107 nsCOMPtr
<nsIInputStream
> bufStream
;
108 rv
= NS_NewBufferedInputStream(getter_AddRefs(bufStream
),
109 inputStream
.forget(), 1024);
110 if (NS_WARN_IF(NS_FAILED(rv
))) {
113 inputStream
= std::move(bufStream
);
116 // Figure out how much data we've been passed.
118 rv
= inputStream
->Available(&length
);
119 if (NS_FAILED(rv
) || length
> UINT32_MAX
) {
123 // Write the data into a SourceBuffer.
124 RefPtr
<SourceBuffer
> sourceBuffer
= new SourceBuffer();
125 sourceBuffer
->ExpectLength(length
);
126 rv
= sourceBuffer
->AppendFromInputStream(inputStream
, length
);
130 // Make sure our sourceBuffer is marked as complete.
131 if (sourceBuffer
->IsComplete()) {
133 "The SourceBuffer was unexpectedly marked as complete. This may "
134 "indicate either an OOM condition, or that imagelib was not "
135 "initialized properly.");
138 sourceBuffer
->Complete(NS_OK
);
140 RefPtr
<ImageBuffer
> imageBuffer
= new ImageBufferImpl(sourceBuffer
.forget());
141 return imageBuffer
.forget();
145 nsresult
ImageOps::DecodeMetadata(already_AddRefed
<nsIInputStream
> aInputStream
,
146 const nsACString
& aMimeType
,
147 ImageMetadata
& aMetadata
) {
148 nsCOMPtr
<nsIInputStream
> inputStream
= std::move(aInputStream
);
149 RefPtr
<ImageBuffer
> buffer
= CreateImageBuffer(inputStream
.forget());
150 return DecodeMetadata(buffer
, aMimeType
, aMetadata
);
154 nsresult
ImageOps::DecodeMetadata(ImageBuffer
* aBuffer
,
155 const nsACString
& aMimeType
,
156 ImageMetadata
& aMetadata
) {
158 return NS_ERROR_FAILURE
;
161 RefPtr
<SourceBuffer
> sourceBuffer
= aBuffer
->GetSourceBuffer();
162 if (NS_WARN_IF(!sourceBuffer
)) {
163 return NS_ERROR_FAILURE
;
167 DecoderType decoderType
=
168 DecoderFactory::GetDecoderType(PromiseFlatCString(aMimeType
).get());
169 RefPtr
<Decoder
> decoder
= DecoderFactory::CreateAnonymousMetadataDecoder(
170 decoderType
, WrapNotNull(sourceBuffer
));
172 return NS_ERROR_FAILURE
;
175 // Run the decoder synchronously.
176 RefPtr
<IDecodingTask
> task
=
177 new AnonymousDecodingTask(WrapNotNull(decoder
), /* aResumable */ false);
179 if (!decoder
->GetDecodeDone() || decoder
->HasError()) {
180 return NS_ERROR_FAILURE
;
183 aMetadata
= decoder
->GetImageMetadata();
184 if (aMetadata
.GetNativeSizes().IsEmpty() && aMetadata
.HasSize()) {
185 aMetadata
.AddNativeSize(aMetadata
.GetSize());
191 /* static */ already_AddRefed
<gfx::SourceSurface
> ImageOps::DecodeToSurface(
192 already_AddRefed
<nsIInputStream
> aInputStream
, const nsACString
& aMimeType
,
193 uint32_t aFlags
, const Maybe
<IntSize
>& aSize
/* = Nothing() */) {
194 nsCOMPtr
<nsIInputStream
> inputStream
= std::move(aInputStream
);
195 RefPtr
<ImageBuffer
> buffer
= CreateImageBuffer(inputStream
.forget());
196 return DecodeToSurface(buffer
, aMimeType
, aFlags
, aSize
);
199 /* static */ already_AddRefed
<gfx::SourceSurface
> ImageOps::DecodeToSurface(
200 ImageBuffer
* aBuffer
, const nsACString
& aMimeType
, uint32_t aFlags
,
201 const Maybe
<IntSize
>& aSize
/* = Nothing() */) {
206 RefPtr
<SourceBuffer
> sourceBuffer
= aBuffer
->GetSourceBuffer();
207 if (NS_WARN_IF(!sourceBuffer
)) {
212 DecoderType decoderType
=
213 DecoderFactory::GetDecoderType(PromiseFlatCString(aMimeType
).get());
214 RefPtr
<Decoder
> decoder
= DecoderFactory::CreateAnonymousDecoder(
215 decoderType
, WrapNotNull(sourceBuffer
), aSize
,
216 DecoderFlags::FIRST_FRAME_ONLY
, ToSurfaceFlags(aFlags
));
221 // Run the decoder synchronously.
222 RefPtr
<IDecodingTask
> task
=
223 new AnonymousDecodingTask(WrapNotNull(decoder
), /* aResumable */ false);
225 if (!decoder
->GetDecodeDone() || decoder
->HasError()) {
229 // Pull out the surface.
230 RawAccessFrameRef frame
= decoder
->GetCurrentFrameRef();
235 RefPtr
<SourceSurface
> surface
= frame
->GetSourceSurface();
240 return surface
.forget();
244 } // namespace mozilla