Backout bug 449422.
[wine-gecko.git] / modules / libpr0n / src / imgTools.cpp
blob4a562fdad93536e33b03b9fce96058caf0e593a5
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is mozilla.org code.
18 * The Initial Developer of the Original Code is Mozilla Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 2007
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Justin Dolske <dolske@mozilla.com> (original author)
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #include "imgTools.h"
40 #include "nsCOMPtr.h"
41 #include "nsString.h"
42 #include "ImageErrors.h"
43 #include "imgIContainer.h"
44 #include "imgILoad.h"
45 #include "imgIDecoder.h"
46 #include "imgIEncoder.h"
47 #include "imgIDecoderObserver.h"
48 #include "imgIContainerObserver.h"
49 #include "nsIImage.h"
50 #include "gfxIImageFrame.h"
51 #include "gfxImageSurface.h"
52 #include "gfxContext.h"
53 #include "nsStringStream.h"
54 #include "nsComponentManagerUtils.h"
55 #include "nsWeakReference.h"
56 #include "nsIInterfaceRequestorUtils.h"
59 /* ========== Utility classes ========== */
62 class HelperLoader : public imgILoad,
63 public imgIDecoderObserver,
64 public nsSupportsWeakReference
66 public:
67 NS_DECL_ISUPPORTS
68 NS_DECL_IMGILOAD
69 NS_DECL_IMGIDECODEROBSERVER
70 NS_DECL_IMGICONTAINEROBSERVER
71 HelperLoader(void);
73 private:
74 nsCOMPtr<imgIContainer> mContainer;
77 NS_IMPL_ISUPPORTS4 (HelperLoader, imgILoad, imgIDecoderObserver, imgIContainerObserver, nsISupportsWeakReference)
79 HelperLoader::HelperLoader (void)
83 /* Implement imgILoad::image getter */
84 NS_IMETHODIMP
85 HelperLoader::GetImage(imgIContainer **aImage)
87 *aImage = mContainer;
88 NS_IF_ADDREF (*aImage);
89 return NS_OK;
92 /* Implement imgILoad::image setter */
93 NS_IMETHODIMP
94 HelperLoader::SetImage(imgIContainer *aImage)
96 mContainer = aImage;
97 return NS_OK;
100 /* Implement imgILoad::isMultiPartChannel getter */
101 NS_IMETHODIMP
102 HelperLoader::GetIsMultiPartChannel(PRBool *aIsMultiPartChannel)
104 *aIsMultiPartChannel = PR_FALSE;
105 return NS_OK;
108 /* Implement imgIDecoderObserver::onStartRequest() */
109 NS_IMETHODIMP
110 HelperLoader::OnStartRequest(imgIRequest *aRequest)
112 return NS_OK;
115 /* Implement imgIDecoderObserver::onStartDecode() */
116 NS_IMETHODIMP
117 HelperLoader::OnStartDecode(imgIRequest *aRequest)
119 return NS_OK;
122 /* Implement imgIDecoderObserver::onStartContainer() */
123 NS_IMETHODIMP
124 HelperLoader::OnStartContainer(imgIRequest *aRequest, imgIContainer
125 *aContainer)
127 return NS_OK;
130 /* Implement imgIDecoderObserver::onStartFrame() */
131 NS_IMETHODIMP
132 HelperLoader::OnStartFrame(imgIRequest *aRequest, gfxIImageFrame *aFrame)
134 return NS_OK;
137 /* Implement imgIDecoderObserver::onDataAvailable() */
138 NS_IMETHODIMP
139 HelperLoader::OnDataAvailable(imgIRequest *aRequest, gfxIImageFrame
140 *aFrame, const nsIntRect * aRect)
142 return NS_OK;
145 /* Implement imgIDecoderObserver::onStopFrame() */
146 NS_IMETHODIMP
147 HelperLoader::OnStopFrame(imgIRequest *aRequest, gfxIImageFrame *aFrame)
149 return NS_OK;
152 /* Implement imgIDecoderObserver::onStopContainer() */
153 NS_IMETHODIMP
154 HelperLoader::OnStopContainer(imgIRequest *aRequest, imgIContainer
155 *aContainer)
157 return NS_OK;
160 /* Implement imgIDecoderObserver::onStopDecode() */
161 NS_IMETHODIMP
162 HelperLoader::OnStopDecode(imgIRequest *aRequest, nsresult status, const
163 PRUnichar *statusArg)
165 return NS_OK;
168 /* Implement imgIDecoderObserver::onStopRequest() */
169 NS_IMETHODIMP
170 HelperLoader::OnStopRequest(imgIRequest *aRequest, PRBool aIsLastPart)
172 return NS_OK;
175 /* implement imgIContainerObserver::frameChanged() */
176 NS_IMETHODIMP
177 HelperLoader::FrameChanged(imgIContainer *aContainer,
178 gfxIImageFrame *aFrame, nsIntRect * aDirtyRect)
180 return NS_OK;
185 /* ========== imgITools implementation ========== */
189 NS_IMPL_ISUPPORTS1(imgTools, imgITools)
191 imgTools::imgTools()
193 /* member initializers and constructor code */
196 imgTools::~imgTools()
198 /* destructor code */
202 NS_IMETHODIMP imgTools::DecodeImageData(nsIInputStream* aInStr,
203 const nsACString& aMimeType,
204 imgIContainer **aContainer)
206 nsresult rv;
208 // Get an image decoder for our media type
209 nsCAutoString decoderCID(
210 NS_LITERAL_CSTRING("@mozilla.org/image/decoder;2?type=") + aMimeType);
212 nsCOMPtr<imgIDecoder> decoder = do_CreateInstance(decoderCID.get());
213 if (!decoder)
214 return NS_IMAGELIB_ERROR_NO_DECODER;
216 // Init the decoder, we use a small utility class here.
217 nsCOMPtr<imgILoad> loader = new HelperLoader();
218 if (!loader)
219 return NS_ERROR_OUT_OF_MEMORY;
221 // If caller provided an existing container, use it.
222 if (*aContainer)
223 loader->SetImage(*aContainer);
225 rv = decoder->Init(loader);
226 NS_ENSURE_SUCCESS(rv, rv);
228 PRUint32 length;
229 rv = aInStr->Available(&length);
230 NS_ENSURE_SUCCESS(rv, rv);
232 PRUint32 written;
233 NS_ENSURE_SUCCESS(rv, rv);
234 rv = decoder->WriteFrom(aInStr, length, &written);
235 NS_ENSURE_SUCCESS(rv, rv);
236 if (written != length)
237 NS_WARNING("decoder didn't eat all of its vegetables");
238 rv = decoder->Flush();
239 NS_ENSURE_SUCCESS(rv, rv);
240 rv = decoder->Close();
241 NS_ENSURE_SUCCESS(rv, rv);
243 // If caller didn't provide an existing container, return the new one.
244 if (!*aContainer)
245 loader->GetImage(aContainer);
247 return NS_OK;
251 NS_IMETHODIMP imgTools::EncodeImage(imgIContainer *aContainer,
252 const nsACString& aMimeType,
253 nsIInputStream **aStream)
255 return EncodeScaledImage(aContainer, aMimeType, 0, 0, aStream);
259 NS_IMETHODIMP imgTools::EncodeScaledImage(imgIContainer *aContainer,
260 const nsACString& aMimeType,
261 PRInt32 aScaledWidth,
262 PRInt32 aScaledHeight,
263 nsIInputStream **aStream)
265 nsresult rv;
266 PRBool doScaling = PR_TRUE;
267 PRUint8 *bitmapData;
268 PRUint32 bitmapDataLength, strideSize;
270 // If no scaled size is specified, we'll just encode the image at its
271 // original size (no scaling).
272 if (aScaledWidth == 0 && aScaledHeight == 0) {
273 doScaling = PR_FALSE;
274 } else {
275 NS_ENSURE_ARG(aScaledWidth > 0);
276 NS_ENSURE_ARG(aScaledHeight > 0);
279 // Get an image encoder for the media type
280 nsCAutoString encoderCID(
281 NS_LITERAL_CSTRING("@mozilla.org/image/encoder;2?type=") + aMimeType);
283 nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(encoderCID.get());
284 if (!encoder)
285 return NS_IMAGELIB_ERROR_NO_ENCODER;
287 // Use frame 0 from the image container.
288 nsCOMPtr<gfxIImageFrame> frame;
289 rv = aContainer->GetFrameAt(0, getter_AddRefs(frame));
290 NS_ENSURE_SUCCESS(rv, rv);
291 if (!frame)
292 return NS_ERROR_NOT_AVAILABLE;
294 PRInt32 w,h;
295 frame->GetWidth(&w);
296 frame->GetHeight(&h);
297 if (!w || !h)
298 return NS_ERROR_FAILURE;
300 nsCOMPtr<nsIImage> img(do_GetInterface(frame));
301 nsRefPtr<gfxImageSurface> dest;
303 if (!doScaling) {
304 // If we're not scaling the image, use the actual width/height.
305 aScaledWidth = w;
306 aScaledHeight = h;
308 img->LockImagePixels(PR_FALSE);
309 bitmapData = img->GetBits();
310 if (!bitmapData) {
311 img->UnlockImagePixels(PR_FALSE);
312 return NS_ERROR_FAILURE;
315 frame->GetImageBytesPerRow(&strideSize);
316 bitmapDataLength = aScaledHeight * strideSize;
318 } else {
319 // Prepare to draw a scaled version of the image to a temporary surface...
321 // Get the source image surface
322 nsRefPtr<gfxPattern> gfxpat;
323 img->GetPattern(getter_AddRefs(gfxpat));
325 // Create a temporary image surface
326 dest = new gfxImageSurface(gfxIntSize(aScaledWidth, aScaledHeight),
327 gfxASurface::ImageFormatARGB32);
328 if (!dest)
329 return NS_ERROR_OUT_OF_MEMORY;
331 gfxContext ctx(dest);
333 // Set scaling
334 gfxFloat sw = (double) aScaledWidth / w;
335 gfxFloat sh = (double) aScaledHeight / h;
336 ctx.Scale(sw, sh);
338 // Paint a scaled image
339 ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
340 ctx.SetPattern(gfxpat);
341 ctx.Paint();
343 bitmapData = dest->Data();
344 strideSize = dest->Stride();
345 bitmapDataLength = aScaledHeight * strideSize;
348 // Encode the bitmap
349 rv = encoder->InitFromData(bitmapData, bitmapDataLength,
350 aScaledWidth, aScaledHeight, strideSize,
351 imgIEncoder::INPUT_FORMAT_HOSTARGB, EmptyString());
352 if (!doScaling)
353 img->UnlockImagePixels(PR_FALSE);
355 NS_ENSURE_SUCCESS(rv, rv);
357 return CallQueryInterface(encoder, aStream);