Bug 1444460 [wpt PR 9948] - gyroscope: Rename LocalCoordinateSystem to GyroscopeLocal...
[gecko.git] / image / ImageOps.cpp
blob716b5b56fc8ffba4ed1fcdc4a621963edb61974e
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/. */
7 #include "ImageOps.h"
9 #include "ClippedImage.h"
10 #include "Decoder.h"
11 #include "DecoderFactory.h"
12 #include "DynamicImage.h"
13 #include "FrozenImage.h"
14 #include "IDecodingTask.h"
15 #include "Image.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;
25 namespace mozilla {
26 namespace image {
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 {
83 public:
84 explicit ImageBufferImpl(already_AddRefed<SourceBuffer> aSourceBuffer)
85 : mSourceBuffer(aSourceBuffer)
86 { }
88 protected:
89 ~ImageBufferImpl() override { }
91 already_AddRefed<SourceBuffer> GetSourceBuffer() const override
93 RefPtr<SourceBuffer> sourceBuffer = mSourceBuffer;
94 return sourceBuffer.forget();
97 private:
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);
107 nsresult rv;
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))) {
115 return nullptr;
119 // Figure out how much data we've been passed.
120 uint64_t length;
121 rv = inputStream->Available(&length);
122 if (NS_FAILED(rv) || length > UINT32_MAX) {
123 return nullptr;
126 // Write the data into a SourceBuffer.
127 RefPtr<SourceBuffer> sourceBuffer = new SourceBuffer();
128 sourceBuffer->ExpectLength(length);
129 rv = sourceBuffer->AppendFromInputStream(inputStream, length);
130 if (NS_FAILED(rv)) {
131 return nullptr;
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.");
138 return nullptr;
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)
161 if (!aBuffer) {
162 return NS_ERROR_FAILURE;
165 RefPtr<SourceBuffer> sourceBuffer = aBuffer->GetSourceBuffer();
166 if (NS_WARN_IF(!sourceBuffer)) {
167 return NS_ERROR_FAILURE;
170 // Create a decoder.
171 DecoderType decoderType =
172 DecoderFactory::GetDecoderType(PromiseFlatCString(aMimeType).get());
173 RefPtr<Decoder> decoder =
174 DecoderFactory::CreateAnonymousMetadataDecoder(decoderType,
175 WrapNotNull(sourceBuffer));
176 if (!decoder) {
177 return NS_ERROR_FAILURE;
180 // Run the decoder synchronously.
181 RefPtr<IDecodingTask> task = new AnonymousDecodingTask(WrapNotNull(decoder));
182 task->Run();
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());
192 return NS_OK;
195 /* static */ already_AddRefed<gfx::SourceSurface>
196 ImageOps::DecodeToSurface(already_AddRefed<nsIInputStream> aInputStream,
197 const nsACString& aMimeType,
198 uint32_t aFlags,
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,
209 uint32_t aFlags,
210 const Maybe<IntSize>& aSize /* = Nothing() */)
212 if (!aBuffer) {
213 return nullptr;
216 RefPtr<SourceBuffer> sourceBuffer = aBuffer->GetSourceBuffer();
217 if (NS_WARN_IF(!sourceBuffer)) {
218 return nullptr;
221 // Create a decoder.
222 DecoderType decoderType =
223 DecoderFactory::GetDecoderType(PromiseFlatCString(aMimeType).get());
224 RefPtr<Decoder> decoder =
225 DecoderFactory::CreateAnonymousDecoder(decoderType,
226 WrapNotNull(sourceBuffer),
227 aSize, ToSurfaceFlags(aFlags));
228 if (!decoder) {
229 return nullptr;
232 // Run the decoder synchronously.
233 RefPtr<IDecodingTask> task = new AnonymousDecodingTask(WrapNotNull(decoder));
234 task->Run();
235 if (!decoder->GetDecodeDone() || decoder->HasError()) {
236 return nullptr;
239 // Pull out the surface.
240 RawAccessFrameRef frame = decoder->GetCurrentFrameRef();
241 if (!frame) {
242 return nullptr;
245 RefPtr<SourceSurface> surface = frame->GetSourceSurface();
246 if (!surface) {
247 return nullptr;
250 return surface.forget();
253 } // namespace image
254 } // namespace mozilla