Backed out changeset ad0d9f62c29c (bug 206659) for B2G desktop mochitest orange.
[gecko.git] / image / src / imgTools.cpp
blob0dd5640ed8eed238452fa24690f03b51463427ea
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 "imgTools.h"
9 #include "nsCOMPtr.h"
10 #include "nsIDocument.h"
11 #include "nsIDOMDocument.h"
12 #include "nsError.h"
13 #include "imgLoader.h"
14 #include "imgICache.h"
15 #include "imgIContainer.h"
16 #include "imgIEncoder.h"
17 #include "gfxContext.h"
18 #include "nsComponentManagerUtils.h"
19 #include "nsStreamUtils.h"
20 #include "nsNetUtil.h"
21 #include "nsContentUtils.h"
22 #include "ImageFactory.h"
23 #include "Image.h"
24 #include "ScriptedNotificationObserver.h"
25 #include "imgIScriptedNotificationObserver.h"
26 #include "gfxPlatform.h"
28 using namespace mozilla;
29 using namespace mozilla::image;
30 using namespace mozilla::gfx;
32 /* ========== imgITools implementation ========== */
36 NS_IMPL_ISUPPORTS1(imgTools, imgITools)
38 imgTools::imgTools()
40 /* member initializers and constructor code */
43 imgTools::~imgTools()
45 /* destructor code */
48 NS_IMETHODIMP imgTools::DecodeImageData(nsIInputStream* aInStr,
49 const nsACString& aMimeType,
50 imgIContainer **aContainer)
52 NS_ABORT_IF_FALSE(*aContainer == nullptr,
53 "Cannot provide an existing image container to DecodeImageData");
55 return DecodeImage(aInStr, aMimeType, aContainer);
58 NS_IMETHODIMP imgTools::DecodeImage(nsIInputStream* aInStr,
59 const nsACString& aMimeType,
60 imgIContainer **aContainer)
62 nsresult rv;
63 nsRefPtr<Image> image;
65 NS_ENSURE_ARG_POINTER(aInStr);
67 // Create a new image container to hold the decoded data.
68 nsAutoCString mimeType(aMimeType);
69 image = ImageFactory::CreateAnonymousImage(mimeType);
71 if (image->HasError())
72 return NS_ERROR_FAILURE;
74 // Prepare the input stream.
75 nsCOMPtr<nsIInputStream> inStream = aInStr;
76 if (!NS_InputStreamIsBuffered(aInStr)) {
77 nsCOMPtr<nsIInputStream> bufStream;
78 rv = NS_NewBufferedInputStream(getter_AddRefs(bufStream), aInStr, 1024);
79 if (NS_SUCCEEDED(rv))
80 inStream = bufStream;
83 // Figure out how much data we've been passed.
84 uint64_t length;
85 rv = inStream->Available(&length);
86 NS_ENSURE_SUCCESS(rv, rv);
87 NS_ENSURE_TRUE(length <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
89 // Send the source data to the Image.
90 rv = image->OnImageDataAvailable(nullptr, nullptr, inStream, 0, uint32_t(length));
91 NS_ENSURE_SUCCESS(rv, rv);
92 // Let the Image know we've sent all the data.
93 rv = image->OnImageDataComplete(nullptr, nullptr, NS_OK, true);
94 NS_ENSURE_SUCCESS(rv, rv);
96 // All done.
97 NS_ADDREF(*aContainer = image.get());
98 return NS_OK;
102 NS_IMETHODIMP imgTools::EncodeImage(imgIContainer *aContainer,
103 const nsACString& aMimeType,
104 const nsAString& aOutputOptions,
105 nsIInputStream **aStream)
107 nsresult rv;
109 // Use frame 0 from the image container.
110 nsRefPtr<gfxImageSurface> frame;
111 rv = GetFirstImageFrame(aContainer, getter_AddRefs(frame));
112 NS_ENSURE_SUCCESS(rv, rv);
114 return EncodeImageData(frame, aMimeType, aOutputOptions, aStream);
117 NS_IMETHODIMP imgTools::EncodeScaledImage(imgIContainer *aContainer,
118 const nsACString& aMimeType,
119 int32_t aScaledWidth,
120 int32_t aScaledHeight,
121 const nsAString& aOutputOptions,
122 nsIInputStream **aStream)
124 NS_ENSURE_ARG(aScaledWidth >= 0 && aScaledHeight >= 0);
126 // If no scaled size is specified, we'll just encode the image at its
127 // original size (no scaling).
128 if (aScaledWidth == 0 && aScaledHeight == 0) {
129 return EncodeImage(aContainer, aMimeType, aOutputOptions, aStream);
132 // Use frame 0 from the image container.
133 nsRefPtr<gfxImageSurface> frame;
134 nsresult rv = GetFirstImageFrame(aContainer, getter_AddRefs(frame));
135 NS_ENSURE_SUCCESS(rv, rv);
137 int32_t frameWidth = frame->Width(), frameHeight = frame->Height();
139 // If the given width or height is zero we'll replace it with the image's
140 // original dimensions.
141 if (aScaledWidth == 0) {
142 aScaledWidth = frameWidth;
143 } else if (aScaledHeight == 0) {
144 aScaledHeight = frameHeight;
147 // Create a temporary image surface
148 nsRefPtr<gfxImageSurface> dest = new gfxImageSurface(gfxIntSize(aScaledWidth, aScaledHeight),
149 gfxImageFormatARGB32);
150 if (gfxPlatform::GetPlatform()->SupportsAzureContent()) {
151 RefPtr<DrawTarget> dt =
152 gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(dest, IntSize(aScaledWidth, aScaledHeight));
153 RefPtr<SourceSurface> source = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, frame);
155 dt->DrawSurface(source,
156 Rect(0, 0, aScaledWidth, aScaledHeight),
157 Rect(0, 0, frameWidth, frameHeight),
158 DrawSurfaceOptions(),
159 DrawOptions(1.0f, OP_SOURCE));
160 } else {
161 gfxContext ctx(dest);
163 // Set scaling
164 gfxFloat sw = (double) aScaledWidth / frameWidth;
165 gfxFloat sh = (double) aScaledHeight / frameHeight;
166 ctx.Scale(sw, sh);
168 // Paint a scaled image
169 ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
171 nsRefPtr<gfxPattern> pat = new gfxPattern(frame);
172 pat->SetExtend(gfxPattern::EXTEND_PAD);
173 ctx.SetPattern(pat);
174 ctx.Paint();
178 return EncodeImageData(dest, aMimeType, aOutputOptions, aStream);
181 NS_IMETHODIMP imgTools::EncodeCroppedImage(imgIContainer *aContainer,
182 const nsACString& aMimeType,
183 int32_t aOffsetX,
184 int32_t aOffsetY,
185 int32_t aWidth,
186 int32_t aHeight,
187 const nsAString& aOutputOptions,
188 nsIInputStream **aStream)
190 NS_ENSURE_ARG(aOffsetX >= 0 && aOffsetY >= 0 && aWidth >= 0 && aHeight >= 0);
192 // Offsets must be zero when no width and height are given or else we're out
193 // of bounds.
194 NS_ENSURE_ARG(aWidth + aHeight > 0 || aOffsetX + aOffsetY == 0);
196 // If no size is specified then we'll preserve the image's original dimensions
197 // and don't need to crop.
198 if (aWidth == 0 && aHeight == 0) {
199 return EncodeImage(aContainer, aMimeType, aOutputOptions, aStream);
202 // Use frame 0 from the image container.
203 nsRefPtr<gfxImageSurface> frame;
204 nsresult rv = GetFirstImageFrame(aContainer, getter_AddRefs(frame));
205 NS_ENSURE_SUCCESS(rv, rv);
207 int32_t frameWidth = frame->Width(), frameHeight = frame->Height();
209 // If the given width or height is zero we'll replace it with the image's
210 // original dimensions.
211 if (aWidth == 0) {
212 aWidth = frameWidth;
213 } else if (aHeight == 0) {
214 aHeight = frameHeight;
217 // Check that the given crop rectangle is within image bounds.
218 NS_ENSURE_ARG(frameWidth >= aOffsetX + aWidth &&
219 frameHeight >= aOffsetY + aHeight);
221 // Create a temporary image surface
222 nsRefPtr<gfxImageSurface> dest = new gfxImageSurface(gfxIntSize(aWidth, aHeight),
223 gfxImageFormatARGB32);
224 gfxContext ctx(dest);
226 // Set translate
227 ctx.Translate(gfxPoint(-aOffsetX, -aOffsetY));
229 // Paint a scaled image
230 ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
231 ctx.SetSource(frame);
232 ctx.Paint();
234 return EncodeImageData(dest, aMimeType, aOutputOptions, aStream);
237 NS_IMETHODIMP imgTools::EncodeImageData(gfxImageSurface *aSurface,
238 const nsACString& aMimeType,
239 const nsAString& aOutputOptions,
240 nsIInputStream **aStream)
242 uint8_t *bitmapData;
243 uint32_t bitmapDataLength, strideSize;
245 // Get an image encoder for the media type
246 nsAutoCString encoderCID(
247 NS_LITERAL_CSTRING("@mozilla.org/image/encoder;2?type=") + aMimeType);
249 nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(encoderCID.get());
250 if (!encoder)
251 return NS_IMAGELIB_ERROR_NO_ENCODER;
253 bitmapData = aSurface->Data();
254 if (!bitmapData)
255 return NS_ERROR_FAILURE;
257 strideSize = aSurface->Stride();
259 int32_t width = aSurface->Width(), height = aSurface->Height();
260 bitmapDataLength = height * strideSize;
262 // Encode the bitmap
263 nsresult rv = encoder->InitFromData(bitmapData,
264 bitmapDataLength,
265 width,
266 height,
267 strideSize,
268 imgIEncoder::INPUT_FORMAT_HOSTARGB,
269 aOutputOptions);
271 NS_ENSURE_SUCCESS(rv, rv);
273 return CallQueryInterface(encoder, aStream);
276 NS_IMETHODIMP imgTools::GetFirstImageFrame(imgIContainer *aContainer,
277 gfxImageSurface **aSurface)
279 nsRefPtr<gfxASurface> surface;
280 aContainer->GetFrame(imgIContainer::FRAME_FIRST,
281 imgIContainer::FLAG_SYNC_DECODE,
282 getter_AddRefs(surface));
283 NS_ENSURE_TRUE(surface, NS_ERROR_NOT_AVAILABLE);
285 nsRefPtr<gfxImageSurface> frame(surface->CopyToARGB32ImageSurface());
286 NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
287 NS_ENSURE_TRUE(frame->Width() && frame->Height(), NS_ERROR_FAILURE);
289 frame.forget(aSurface);
290 return NS_OK;
293 NS_IMETHODIMP imgTools::CreateScriptedObserver(imgIScriptedNotificationObserver* aInner,
294 imgINotificationObserver** aObserver)
296 NS_ADDREF(*aObserver = new ScriptedNotificationObserver(aInner));
297 return NS_OK;
300 NS_IMETHODIMP
301 imgTools::GetImgLoaderForDocument(nsIDOMDocument* aDoc, imgILoader** aLoader)
303 nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDoc);
304 NS_IF_ADDREF(*aLoader = nsContentUtils::GetImgLoaderForDocument(doc));
305 return NS_OK;
308 NS_IMETHODIMP
309 imgTools::GetImgCacheForDocument(nsIDOMDocument* aDoc, imgICache** aCache)
311 nsCOMPtr<imgILoader> loader;
312 nsresult rv = GetImgLoaderForDocument(aDoc, getter_AddRefs(loader));
313 NS_ENSURE_SUCCESS(rv, rv);
314 return CallQueryInterface(loader, aCache);