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/. */
10 #include "nsIDocument.h"
11 #include "nsIDOMDocument.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"
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
)
40 /* member initializers and constructor 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
)
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);
83 // Figure out how much data we've been passed.
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
);
97 NS_ADDREF(*aContainer
= image
.get());
102 NS_IMETHODIMP
imgTools::EncodeImage(imgIContainer
*aContainer
,
103 const nsACString
& aMimeType
,
104 const nsAString
& aOutputOptions
,
105 nsIInputStream
**aStream
)
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
));
161 gfxContext
ctx(dest
);
164 gfxFloat sw
= (double) aScaledWidth
/ frameWidth
;
165 gfxFloat sh
= (double) aScaledHeight
/ frameHeight
;
168 // Paint a scaled image
169 ctx
.SetOperator(gfxContext::OPERATOR_SOURCE
);
171 nsRefPtr
<gfxPattern
> pat
= new gfxPattern(frame
);
172 pat
->SetExtend(gfxPattern::EXTEND_PAD
);
178 return EncodeImageData(dest
, aMimeType
, aOutputOptions
, aStream
);
181 NS_IMETHODIMP
imgTools::EncodeCroppedImage(imgIContainer
*aContainer
,
182 const nsACString
& aMimeType
,
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
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.
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
);
227 ctx
.Translate(gfxPoint(-aOffsetX
, -aOffsetY
));
229 // Paint a scaled image
230 ctx
.SetOperator(gfxContext::OPERATOR_SOURCE
);
231 ctx
.SetSource(frame
);
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
)
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());
251 return NS_IMAGELIB_ERROR_NO_ENCODER
;
253 bitmapData
= aSurface
->Data();
255 return NS_ERROR_FAILURE
;
257 strideSize
= aSurface
->Stride();
259 int32_t width
= aSurface
->Width(), height
= aSurface
->Height();
260 bitmapDataLength
= height
* strideSize
;
263 nsresult rv
= encoder
->InitFromData(bitmapData
,
268 imgIEncoder::INPUT_FORMAT_HOSTARGB
,
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
);
293 NS_IMETHODIMP
imgTools::CreateScriptedObserver(imgIScriptedNotificationObserver
* aInner
,
294 imgINotificationObserver
** aObserver
)
296 NS_ADDREF(*aObserver
= new ScriptedNotificationObserver(aInner
));
301 imgTools::GetImgLoaderForDocument(nsIDOMDocument
* aDoc
, imgILoader
** aLoader
)
303 nsCOMPtr
<nsIDocument
> doc
= do_QueryInterface(aDoc
);
304 NS_IF_ADDREF(*aLoader
= nsContentUtils::GetImgLoaderForDocument(doc
));
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
);