Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
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/. */
6 :
7 : #include "ImageOps.h"
8 :
9 : #include "ClippedImage.h"
10 : #include "DecodePool.h"
11 : #include "Decoder.h"
12 : #include "DecoderFactory.h"
13 : #include "DynamicImage.h"
14 : #include "FrozenImage.h"
15 : #include "IDecodingTask.h"
16 : #include "Image.h"
17 : #include "ImageMetadata.h"
18 : #include "imgIContainer.h"
19 : #include "mozilla/gfx/2D.h"
20 : #include "nsStreamUtils.h"
21 : #include "OrientedImage.h"
22 : #include "SourceBuffer.h"
23 :
24 : using namespace mozilla::gfx;
25 :
26 : namespace mozilla {
27 : namespace image {
28 :
29 : /* static */ already_AddRefed<Image>
30 0 : ImageOps::Freeze(Image* aImage)
31 : {
32 0 : RefPtr<Image> frozenImage = new FrozenImage(aImage);
33 0 : return frozenImage.forget();
34 : }
35 :
36 : /* static */ already_AddRefed<imgIContainer>
37 0 : ImageOps::Freeze(imgIContainer* aImage)
38 : {
39 : nsCOMPtr<imgIContainer> frozenImage =
40 0 : new FrozenImage(static_cast<Image*>(aImage));
41 0 : return frozenImage.forget();
42 : }
43 :
44 : /* static */ already_AddRefed<Image>
45 0 : ImageOps::Clip(Image* aImage, nsIntRect aClip,
46 : const Maybe<nsSize>& aSVGViewportSize)
47 : {
48 0 : RefPtr<Image> clippedImage = new ClippedImage(aImage, aClip, aSVGViewportSize);
49 0 : return clippedImage.forget();
50 : }
51 :
52 : /* static */ already_AddRefed<imgIContainer>
53 56 : ImageOps::Clip(imgIContainer* aImage, nsIntRect aClip,
54 : const Maybe<nsSize>& aSVGViewportSize)
55 : {
56 : nsCOMPtr<imgIContainer> clippedImage =
57 168 : new ClippedImage(static_cast<Image*>(aImage), aClip, aSVGViewportSize);
58 112 : return clippedImage.forget();
59 : }
60 :
61 : /* static */ already_AddRefed<Image>
62 0 : ImageOps::Orient(Image* aImage, Orientation aOrientation)
63 : {
64 0 : RefPtr<Image> orientedImage = new OrientedImage(aImage, aOrientation);
65 0 : return orientedImage.forget();
66 : }
67 :
68 : /* static */ already_AddRefed<imgIContainer>
69 0 : ImageOps::Orient(imgIContainer* aImage, Orientation aOrientation)
70 : {
71 : nsCOMPtr<imgIContainer> orientedImage =
72 0 : new OrientedImage(static_cast<Image*>(aImage), aOrientation);
73 0 : return orientedImage.forget();
74 : }
75 :
76 : /* static */ already_AddRefed<imgIContainer>
77 0 : ImageOps::CreateFromDrawable(gfxDrawable* aDrawable)
78 : {
79 0 : nsCOMPtr<imgIContainer> drawableImage = new DynamicImage(aDrawable);
80 0 : return drawableImage.forget();
81 : }
82 :
83 : class ImageOps::ImageBufferImpl final : public ImageOps::ImageBuffer {
84 : public:
85 0 : explicit ImageBufferImpl(already_AddRefed<SourceBuffer> aSourceBuffer)
86 0 : : mSourceBuffer(aSourceBuffer)
87 0 : { }
88 :
89 : protected:
90 0 : ~ImageBufferImpl() override { }
91 :
92 0 : already_AddRefed<SourceBuffer> GetSourceBuffer() const override
93 : {
94 0 : RefPtr<SourceBuffer> sourceBuffer = mSourceBuffer;
95 0 : return sourceBuffer.forget();
96 : }
97 :
98 : private:
99 : RefPtr<SourceBuffer> mSourceBuffer;
100 : };
101 :
102 : /* static */ already_AddRefed<ImageOps::ImageBuffer>
103 0 : ImageOps::CreateImageBuffer(nsIInputStream* aInputStream)
104 : {
105 0 : MOZ_ASSERT(aInputStream);
106 :
107 : nsresult rv;
108 :
109 : // Prepare the input stream.
110 0 : nsCOMPtr<nsIInputStream> inputStream = aInputStream;
111 0 : if (!NS_InputStreamIsBuffered(aInputStream)) {
112 0 : nsCOMPtr<nsIInputStream> bufStream;
113 0 : rv = NS_NewBufferedInputStream(getter_AddRefs(bufStream),
114 0 : aInputStream, 1024);
115 0 : if (NS_SUCCEEDED(rv)) {
116 0 : inputStream = bufStream;
117 : }
118 : }
119 :
120 : // Figure out how much data we've been passed.
121 : uint64_t length;
122 0 : rv = inputStream->Available(&length);
123 0 : if (NS_FAILED(rv) || length > UINT32_MAX) {
124 0 : return nullptr;
125 : }
126 :
127 : // Write the data into a SourceBuffer.
128 0 : RefPtr<SourceBuffer> sourceBuffer = new SourceBuffer();
129 0 : sourceBuffer->ExpectLength(length);
130 0 : rv = sourceBuffer->AppendFromInputStream(inputStream, length);
131 0 : if (NS_FAILED(rv)) {
132 0 : return nullptr;
133 : }
134 : // Make sure our sourceBuffer is marked as complete.
135 0 : if (sourceBuffer->IsComplete()) {
136 : NS_WARNING("The SourceBuffer was unexpectedly marked as complete. This may "
137 : "indicate either an OOM condition, or that imagelib was not "
138 0 : "initialized properly.");
139 0 : return nullptr;
140 : }
141 0 : sourceBuffer->Complete(NS_OK);
142 :
143 0 : RefPtr<ImageBuffer> imageBuffer = new ImageBufferImpl(sourceBuffer.forget());
144 0 : return imageBuffer.forget();
145 : }
146 :
147 : /* static */ nsresult
148 0 : ImageOps::DecodeMetadata(nsIInputStream* aInputStream,
149 : const nsACString& aMimeType,
150 : ImageMetadata& aMetadata)
151 : {
152 0 : RefPtr<ImageBuffer> buffer = CreateImageBuffer(aInputStream);
153 0 : return DecodeMetadata(buffer, aMimeType, aMetadata);
154 : }
155 :
156 : /* static */ nsresult
157 0 : ImageOps::DecodeMetadata(ImageBuffer* aBuffer,
158 : const nsACString& aMimeType,
159 : ImageMetadata& aMetadata)
160 : {
161 0 : if (!aBuffer) {
162 0 : return NS_ERROR_FAILURE;
163 : }
164 :
165 0 : RefPtr<SourceBuffer> sourceBuffer = aBuffer->GetSourceBuffer();
166 0 : if (NS_WARN_IF(!sourceBuffer)) {
167 0 : return NS_ERROR_FAILURE;
168 : }
169 :
170 : // Create a decoder.
171 : DecoderType decoderType =
172 0 : DecoderFactory::GetDecoderType(PromiseFlatCString(aMimeType).get());
173 : RefPtr<Decoder> decoder =
174 0 : DecoderFactory::CreateAnonymousMetadataDecoder(decoderType,
175 0 : WrapNotNull(sourceBuffer));
176 0 : if (!decoder) {
177 0 : return NS_ERROR_FAILURE;
178 : }
179 :
180 : // Run the decoder synchronously.
181 0 : RefPtr<IDecodingTask> task = new AnonymousDecodingTask(WrapNotNull(decoder));
182 0 : task->Run();
183 0 : if (!decoder->GetDecodeDone() || decoder->HasError()) {
184 0 : return NS_ERROR_FAILURE;
185 : }
186 :
187 0 : aMetadata = decoder->GetImageMetadata();
188 0 : if (aMetadata.GetNativeSizes().IsEmpty() && aMetadata.HasSize()) {
189 0 : aMetadata.AddNativeSize(aMetadata.GetSize());
190 : }
191 :
192 0 : return NS_OK;
193 : }
194 :
195 : /* static */ already_AddRefed<gfx::SourceSurface>
196 0 : ImageOps::DecodeToSurface(nsIInputStream* aInputStream,
197 : const nsACString& aMimeType,
198 : uint32_t aFlags,
199 : const Maybe<IntSize>& aSize /* = Nothing() */)
200 : {
201 0 : RefPtr<ImageBuffer> buffer = CreateImageBuffer(aInputStream);
202 0 : return DecodeToSurface(buffer, aMimeType, aFlags, aSize);
203 : }
204 :
205 : /* static */ already_AddRefed<gfx::SourceSurface>
206 0 : ImageOps::DecodeToSurface(ImageBuffer* aBuffer,
207 : const nsACString& aMimeType,
208 : uint32_t aFlags,
209 : const Maybe<IntSize>& aSize /* = Nothing() */)
210 : {
211 0 : if (!aBuffer) {
212 0 : return nullptr;
213 : }
214 :
215 0 : RefPtr<SourceBuffer> sourceBuffer = aBuffer->GetSourceBuffer();
216 0 : if (NS_WARN_IF(!sourceBuffer)) {
217 0 : return nullptr;
218 : }
219 :
220 : // Create a decoder.
221 : DecoderType decoderType =
222 0 : DecoderFactory::GetDecoderType(PromiseFlatCString(aMimeType).get());
223 : RefPtr<Decoder> decoder =
224 0 : DecoderFactory::CreateAnonymousDecoder(decoderType,
225 0 : WrapNotNull(sourceBuffer),
226 0 : aSize, ToSurfaceFlags(aFlags));
227 0 : if (!decoder) {
228 0 : return nullptr;
229 : }
230 :
231 : // Run the decoder synchronously.
232 0 : RefPtr<IDecodingTask> task = new AnonymousDecodingTask(WrapNotNull(decoder));
233 0 : task->Run();
234 0 : if (!decoder->GetDecodeDone() || decoder->HasError()) {
235 0 : return nullptr;
236 : }
237 :
238 : // Pull out the surface.
239 0 : RawAccessFrameRef frame = decoder->GetCurrentFrameRef();
240 0 : if (!frame) {
241 0 : return nullptr;
242 : }
243 :
244 0 : RefPtr<SourceSurface> surface = frame->GetSourceSurface();
245 0 : if (!surface) {
246 0 : return nullptr;
247 : }
248 :
249 0 : return surface.forget();
250 : }
251 :
252 : } // namespace image
253 : } // namespace mozilla
|