image/src/imgTools.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
michael@0 2 *
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "imgTools.h"
michael@0 8
michael@0 9 #include "gfxUtils.h"
michael@0 10 #include "mozilla/gfx/2D.h"
michael@0 11 #include "mozilla/RefPtr.h"
michael@0 12 #include "nsCOMPtr.h"
michael@0 13 #include "nsIDocument.h"
michael@0 14 #include "nsIDOMDocument.h"
michael@0 15 #include "nsError.h"
michael@0 16 #include "imgLoader.h"
michael@0 17 #include "imgICache.h"
michael@0 18 #include "imgIContainer.h"
michael@0 19 #include "imgIEncoder.h"
michael@0 20 #include "nsStreamUtils.h"
michael@0 21 #include "nsContentUtils.h"
michael@0 22 #include "ImageFactory.h"
michael@0 23 #include "Image.h"
michael@0 24 #include "ScriptedNotificationObserver.h"
michael@0 25 #include "imgIScriptedNotificationObserver.h"
michael@0 26 #include "gfxPlatform.h"
michael@0 27
michael@0 28 using namespace mozilla;
michael@0 29 using namespace mozilla::image;
michael@0 30 using namespace mozilla::gfx;
michael@0 31
michael@0 32 /* ========== imgITools implementation ========== */
michael@0 33
michael@0 34
michael@0 35
michael@0 36 NS_IMPL_ISUPPORTS(imgTools, imgITools)
michael@0 37
michael@0 38 imgTools::imgTools()
michael@0 39 {
michael@0 40 /* member initializers and constructor code */
michael@0 41 }
michael@0 42
michael@0 43 imgTools::~imgTools()
michael@0 44 {
michael@0 45 /* destructor code */
michael@0 46 }
michael@0 47
michael@0 48 NS_IMETHODIMP imgTools::DecodeImageData(nsIInputStream* aInStr,
michael@0 49 const nsACString& aMimeType,
michael@0 50 imgIContainer **aContainer)
michael@0 51 {
michael@0 52 NS_ABORT_IF_FALSE(*aContainer == nullptr,
michael@0 53 "Cannot provide an existing image container to DecodeImageData");
michael@0 54
michael@0 55 return DecodeImage(aInStr, aMimeType, aContainer);
michael@0 56 }
michael@0 57
michael@0 58 NS_IMETHODIMP imgTools::DecodeImage(nsIInputStream* aInStr,
michael@0 59 const nsACString& aMimeType,
michael@0 60 imgIContainer **aContainer)
michael@0 61 {
michael@0 62 nsresult rv;
michael@0 63 nsRefPtr<Image> image;
michael@0 64
michael@0 65 NS_ENSURE_ARG_POINTER(aInStr);
michael@0 66
michael@0 67 // Create a new image container to hold the decoded data.
michael@0 68 nsAutoCString mimeType(aMimeType);
michael@0 69 image = ImageFactory::CreateAnonymousImage(mimeType);
michael@0 70
michael@0 71 if (image->HasError())
michael@0 72 return NS_ERROR_FAILURE;
michael@0 73
michael@0 74 // Prepare the input stream.
michael@0 75 nsCOMPtr<nsIInputStream> inStream = aInStr;
michael@0 76 if (!NS_InputStreamIsBuffered(aInStr)) {
michael@0 77 nsCOMPtr<nsIInputStream> bufStream;
michael@0 78 rv = NS_NewBufferedInputStream(getter_AddRefs(bufStream), aInStr, 1024);
michael@0 79 if (NS_SUCCEEDED(rv))
michael@0 80 inStream = bufStream;
michael@0 81 }
michael@0 82
michael@0 83 // Figure out how much data we've been passed.
michael@0 84 uint64_t length;
michael@0 85 rv = inStream->Available(&length);
michael@0 86 NS_ENSURE_SUCCESS(rv, rv);
michael@0 87 NS_ENSURE_TRUE(length <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
michael@0 88
michael@0 89 // Send the source data to the Image.
michael@0 90 rv = image->OnImageDataAvailable(nullptr, nullptr, inStream, 0, uint32_t(length));
michael@0 91 NS_ENSURE_SUCCESS(rv, rv);
michael@0 92 // Let the Image know we've sent all the data.
michael@0 93 rv = image->OnImageDataComplete(nullptr, nullptr, NS_OK, true);
michael@0 94 NS_ENSURE_SUCCESS(rv, rv);
michael@0 95
michael@0 96 // All done.
michael@0 97 NS_ADDREF(*aContainer = image.get());
michael@0 98 return NS_OK;
michael@0 99 }
michael@0 100
michael@0 101 /**
michael@0 102 * This takes a DataSourceSurface rather than a SourceSurface because some
michael@0 103 * of the callers have a DataSourceSurface and we don't want to call
michael@0 104 * GetDataSurface on such surfaces since that may incure a conversion to
michael@0 105 * SurfaceType::DATA which we don't need.
michael@0 106 */
michael@0 107 static nsresult EncodeImageData(DataSourceSurface* aDataSurface,
michael@0 108 const nsACString& aMimeType,
michael@0 109 const nsAString& aOutputOptions,
michael@0 110 nsIInputStream **aStream)
michael@0 111 {
michael@0 112 MOZ_ASSERT(aDataSurface->GetFormat() == SurfaceFormat::B8G8R8A8,
michael@0 113 "We're assuming B8G8R8A8");
michael@0 114
michael@0 115 // Get an image encoder for the media type
michael@0 116 nsAutoCString encoderCID(
michael@0 117 NS_LITERAL_CSTRING("@mozilla.org/image/encoder;2?type=") + aMimeType);
michael@0 118
michael@0 119 nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(encoderCID.get());
michael@0 120 if (!encoder)
michael@0 121 return NS_IMAGELIB_ERROR_NO_ENCODER;
michael@0 122
michael@0 123 DataSourceSurface::MappedSurface map;
michael@0 124 if (!aDataSurface->Map(DataSourceSurface::MapType::READ, &map)) {
michael@0 125 return NS_ERROR_FAILURE;
michael@0 126 }
michael@0 127
michael@0 128 IntSize size = aDataSurface->GetSize();
michael@0 129 uint32_t dataLength = map.mStride * size.height;
michael@0 130
michael@0 131 // Encode the bitmap
michael@0 132 nsresult rv = encoder->InitFromData(map.mData,
michael@0 133 dataLength,
michael@0 134 size.width,
michael@0 135 size.height,
michael@0 136 map.mStride,
michael@0 137 imgIEncoder::INPUT_FORMAT_HOSTARGB,
michael@0 138 aOutputOptions);
michael@0 139 aDataSurface->Unmap();
michael@0 140 NS_ENSURE_SUCCESS(rv, rv);
michael@0 141
michael@0 142 return CallQueryInterface(encoder, aStream);
michael@0 143 }
michael@0 144
michael@0 145 NS_IMETHODIMP imgTools::EncodeImage(imgIContainer *aContainer,
michael@0 146 const nsACString& aMimeType,
michael@0 147 const nsAString& aOutputOptions,
michael@0 148 nsIInputStream **aStream)
michael@0 149 {
michael@0 150 // Use frame 0 from the image container.
michael@0 151 RefPtr<SourceSurface> frame =
michael@0 152 aContainer->GetFrame(imgIContainer::FRAME_FIRST,
michael@0 153 imgIContainer::FLAG_SYNC_DECODE);
michael@0 154 NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
michael@0 155
michael@0 156 RefPtr<DataSourceSurface> dataSurface;
michael@0 157
michael@0 158 if (frame->GetFormat() == SurfaceFormat::B8G8R8A8) {
michael@0 159 dataSurface = frame->GetDataSurface();
michael@0 160 } else {
michael@0 161 // Convert format to SurfaceFormat::B8G8R8A8
michael@0 162 dataSurface = gfxUtils::
michael@0 163 CopySurfaceToDataSourceSurfaceWithFormat(frame,
michael@0 164 SurfaceFormat::B8G8R8A8);
michael@0 165 }
michael@0 166
michael@0 167 NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE);
michael@0 168
michael@0 169 return EncodeImageData(dataSurface, aMimeType, aOutputOptions, aStream);
michael@0 170 }
michael@0 171
michael@0 172 NS_IMETHODIMP imgTools::EncodeScaledImage(imgIContainer *aContainer,
michael@0 173 const nsACString& aMimeType,
michael@0 174 int32_t aScaledWidth,
michael@0 175 int32_t aScaledHeight,
michael@0 176 const nsAString& aOutputOptions,
michael@0 177 nsIInputStream **aStream)
michael@0 178 {
michael@0 179 NS_ENSURE_ARG(aScaledWidth >= 0 && aScaledHeight >= 0);
michael@0 180
michael@0 181 // If no scaled size is specified, we'll just encode the image at its
michael@0 182 // original size (no scaling).
michael@0 183 if (aScaledWidth == 0 && aScaledHeight == 0) {
michael@0 184 return EncodeImage(aContainer, aMimeType, aOutputOptions, aStream);
michael@0 185 }
michael@0 186
michael@0 187 // Use frame 0 from the image container.
michael@0 188 RefPtr<SourceSurface> frame =
michael@0 189 aContainer->GetFrame(imgIContainer::FRAME_FIRST,
michael@0 190 imgIContainer::FLAG_SYNC_DECODE);
michael@0 191 NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
michael@0 192
michael@0 193 int32_t frameWidth = frame->GetSize().width;
michael@0 194 int32_t frameHeight = frame->GetSize().height;
michael@0 195
michael@0 196 // If the given width or height is zero we'll replace it with the image's
michael@0 197 // original dimensions.
michael@0 198 if (aScaledWidth == 0) {
michael@0 199 aScaledWidth = frameWidth;
michael@0 200 } else if (aScaledHeight == 0) {
michael@0 201 aScaledHeight = frameHeight;
michael@0 202 }
michael@0 203
michael@0 204 RefPtr<DataSourceSurface> dataSurface =
michael@0 205 Factory::CreateDataSourceSurface(IntSize(aScaledWidth, aScaledHeight),
michael@0 206 SurfaceFormat::B8G8R8A8);
michael@0 207 DataSourceSurface::MappedSurface map;
michael@0 208 if (!dataSurface->Map(DataSourceSurface::MapType::WRITE, &map)) {
michael@0 209 return NS_ERROR_FAILURE;
michael@0 210 }
michael@0 211
michael@0 212 RefPtr<DrawTarget> dt =
michael@0 213 Factory::CreateDrawTargetForData(BackendType::CAIRO,
michael@0 214 map.mData,
michael@0 215 dataSurface->GetSize(),
michael@0 216 map.mStride,
michael@0 217 SurfaceFormat::B8G8R8A8);
michael@0 218 dt->DrawSurface(frame,
michael@0 219 Rect(0, 0, aScaledWidth, aScaledHeight),
michael@0 220 Rect(0, 0, frameWidth, frameHeight),
michael@0 221 DrawSurfaceOptions(),
michael@0 222 DrawOptions(1.0f, CompositionOp::OP_SOURCE));
michael@0 223
michael@0 224 dataSurface->Unmap();
michael@0 225
michael@0 226 return EncodeImageData(dataSurface, aMimeType, aOutputOptions, aStream);
michael@0 227 }
michael@0 228
michael@0 229 NS_IMETHODIMP imgTools::EncodeCroppedImage(imgIContainer *aContainer,
michael@0 230 const nsACString& aMimeType,
michael@0 231 int32_t aOffsetX,
michael@0 232 int32_t aOffsetY,
michael@0 233 int32_t aWidth,
michael@0 234 int32_t aHeight,
michael@0 235 const nsAString& aOutputOptions,
michael@0 236 nsIInputStream **aStream)
michael@0 237 {
michael@0 238 NS_ENSURE_ARG(aOffsetX >= 0 && aOffsetY >= 0 && aWidth >= 0 && aHeight >= 0);
michael@0 239
michael@0 240 // Offsets must be zero when no width and height are given or else we're out
michael@0 241 // of bounds.
michael@0 242 NS_ENSURE_ARG(aWidth + aHeight > 0 || aOffsetX + aOffsetY == 0);
michael@0 243
michael@0 244 // If no size is specified then we'll preserve the image's original dimensions
michael@0 245 // and don't need to crop.
michael@0 246 if (aWidth == 0 && aHeight == 0) {
michael@0 247 return EncodeImage(aContainer, aMimeType, aOutputOptions, aStream);
michael@0 248 }
michael@0 249
michael@0 250 // Use frame 0 from the image container.
michael@0 251 RefPtr<SourceSurface> frame =
michael@0 252 aContainer->GetFrame(imgIContainer::FRAME_FIRST,
michael@0 253 imgIContainer::FLAG_SYNC_DECODE);
michael@0 254 NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
michael@0 255
michael@0 256 int32_t frameWidth = frame->GetSize().width;
michael@0 257 int32_t frameHeight = frame->GetSize().height;
michael@0 258
michael@0 259 // If the given width or height is zero we'll replace it with the image's
michael@0 260 // original dimensions.
michael@0 261 if (aWidth == 0) {
michael@0 262 aWidth = frameWidth;
michael@0 263 } else if (aHeight == 0) {
michael@0 264 aHeight = frameHeight;
michael@0 265 }
michael@0 266
michael@0 267 // Check that the given crop rectangle is within image bounds.
michael@0 268 NS_ENSURE_ARG(frameWidth >= aOffsetX + aWidth &&
michael@0 269 frameHeight >= aOffsetY + aHeight);
michael@0 270
michael@0 271 RefPtr<DataSourceSurface> dataSurface =
michael@0 272 Factory::CreateDataSourceSurface(IntSize(aWidth, aHeight),
michael@0 273 SurfaceFormat::B8G8R8A8);
michael@0 274 DataSourceSurface::MappedSurface map;
michael@0 275 if (!dataSurface->Map(DataSourceSurface::MapType::WRITE, &map)) {
michael@0 276 return NS_ERROR_FAILURE;
michael@0 277 }
michael@0 278
michael@0 279 RefPtr<DrawTarget> dt =
michael@0 280 Factory::CreateDrawTargetForData(BackendType::CAIRO,
michael@0 281 map.mData,
michael@0 282 dataSurface->GetSize(),
michael@0 283 map.mStride,
michael@0 284 SurfaceFormat::B8G8R8A8);
michael@0 285 dt->CopySurface(frame,
michael@0 286 IntRect(aOffsetX, aOffsetY, aWidth, aHeight),
michael@0 287 IntPoint(0, 0));
michael@0 288
michael@0 289 dataSurface->Unmap();
michael@0 290
michael@0 291 return EncodeImageData(dataSurface, aMimeType, aOutputOptions, aStream);
michael@0 292 }
michael@0 293
michael@0 294 NS_IMETHODIMP imgTools::CreateScriptedObserver(imgIScriptedNotificationObserver* aInner,
michael@0 295 imgINotificationObserver** aObserver)
michael@0 296 {
michael@0 297 NS_ADDREF(*aObserver = new ScriptedNotificationObserver(aInner));
michael@0 298 return NS_OK;
michael@0 299 }
michael@0 300
michael@0 301 NS_IMETHODIMP
michael@0 302 imgTools::GetImgLoaderForDocument(nsIDOMDocument* aDoc, imgILoader** aLoader)
michael@0 303 {
michael@0 304 nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDoc);
michael@0 305 NS_IF_ADDREF(*aLoader = nsContentUtils::GetImgLoaderForDocument(doc));
michael@0 306 return NS_OK;
michael@0 307 }
michael@0 308
michael@0 309 NS_IMETHODIMP
michael@0 310 imgTools::GetImgCacheForDocument(nsIDOMDocument* aDoc, imgICache** aCache)
michael@0 311 {
michael@0 312 nsCOMPtr<imgILoader> loader;
michael@0 313 nsresult rv = GetImgLoaderForDocument(aDoc, getter_AddRefs(loader));
michael@0 314 NS_ENSURE_SUCCESS(rv, rv);
michael@0 315 return CallQueryInterface(loader, aCache);
michael@0 316 }

mercurial