/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
if (aInputStream) { // Look at the first few bytes and see if we can tell what the data is // from that since servers tend to lie. :(
uint32_t unused;
aInputStream->ReadSegments(sniff_mimetype_callback, &mimeType, aCount,
&unused);
}
RefPtr<ProgressTracker> tracker = new ProgressTracker(); if (mObserver) {
tracker->AddObserver(this);
}
NS_IMETHOD
OnStopRequest(nsIRequest* aRequest, nsresult aStatus) override { // Encouter a fetch error, or no data could be fetched. if (!mImage || NS_FAILED(aStatus)) {
mCallback->OnImageReady(nullptr, mImage ? aStatus : NS_ERROR_FAILURE); return NS_OK;
}
NS_IMETHOD
Run() override { // This runnable is dispatched on the Image thread when reading data, but // at the end, it goes back to the main-thread in order to complete the // operation. if (NS_IsMainThread()) { // Let the Image know we've sent all the data.
mImage->OnImageDataComplete(nullptr, mStatus, true);
if (NS_WARN_IF(NS_FAILED(rv))) { return OperationCompleted(rv);
}
// Nothing else to read, but maybe we just need to wait. if (length == 0) {
nsCOMPtr<nsIAsyncInputStream> asyncInputStream =
do_QueryInterface(mInputStream); if (asyncInputStream) {
rv = asyncInputStream->AsyncWait(this, 0, 0, mEventTarget); if (NS_WARN_IF(NS_FAILED(rv))) { return OperationCompleted(rv);
} return NS_OK;
}
// We really have nothing else to read. if (length == 0) { return OperationCompleted(NS_OK);
}
}
// Send the source data to the Image.
rv = mImage->OnImageDataAvailable(nullptr, mInputStream, 0,
uint32_t(length)); if (NS_WARN_IF(NS_FAILED(rv))) { return OperationCompleted(rv);
}
rv = mEventTarget->Dispatch(this, NS_DISPATCH_NORMAL); if (NS_WARN_IF(NS_FAILED(rv))) { return OperationCompleted(rv);
}
// Create a new image container to hold the decoded data.
nsAutoCString mimeType(aMimeType);
RefPtr<image::Image> image =
ImageFactory::CreateAnonymousImage(mimeType, aSize);
RefPtr<ProgressTracker> tracker = image->GetProgressTracker();
if (image->HasError()) { return NS_ERROR_FAILURE;
}
// Let the Image know we've sent all the data.
rv = image->OnImageDataComplete(nullptr, NS_OK, true);
tracker->SyncNotifyProgress(FLAG_LOAD_COMPLETE);
NS_ENSURE_SUCCESS(rv, rv);
// All done.
image.forget(aContainer); return NS_OK;
}
// Create a new image container to hold the decoded data.
nsAutoCString mimeType(aMimeType);
RefPtr<image::Image> image = ImageFactory::CreateAnonymousImage(mimeType, 0);
// Already an error? if (image->HasError()) { return NS_ERROR_FAILURE;
}
/** * This takes a DataSourceSurface rather than a SourceSurface because some * of the callers have a DataSourceSurface and we don't want to call * GetDataSurface on such surfaces since that may incur a conversion to * SurfaceType::DATA which we don't need.
*/ static nsresult EncodeImageData(DataSourceSurface* aDataSurface,
DataSourceSurface::ScopedMap& aMap, const nsACString& aMimeType, const nsAString& aOutputOptions,
nsIInputStream** aStream) {
MOZ_ASSERT(aDataSurface->GetFormat() == SurfaceFormat::B8G8R8A8 ||
aDataSurface->GetFormat() == SurfaceFormat::B8G8R8X8, "We're assuming B8G8R8A8/X8");
// Get an image encoder for the media type
nsAutoCString encoderCID("@mozilla.org/image/encoder;2?type="_ns + aMimeType);
nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(encoderCID.get()); if (!encoder) { return NS_IMAGELIB_ERROR_NO_ENCODER;
}
// If no scaled size is specified, we'll just encode the image at its // original size (no scaling). if (aScaledWidth == 0 && aScaledHeight == 0) { return EncodeImage(aContainer, aMimeType, aOutputOptions, aStream);
}
// If the given width or height is zero we'll replace it with the image's // original dimensions.
IntSize scaledSize(aScaledWidth == 0 ? imageWidth : aScaledWidth,
aScaledHeight == 0 ? imageHeight : aScaledHeight);
// Use frame 0 from the image container.
RefPtr<SourceSurface> frame = aContainer->GetFrameAtSize(
scaledSize, imgIContainer::FRAME_FIRST,
imgIContainer::FLAG_HIGH_QUALITY_SCALING |
imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_ASYNC_NOTIFY);
NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
// If the given surface is the right size/format, we can encode it directly. if (scaledSize == frame->GetSize() &&
(frame->GetFormat() == SurfaceFormat::B8G8R8A8 ||
frame->GetFormat() == SurfaceFormat::B8G8R8X8)) {
RefPtr<DataSourceSurface> dataSurface = frame->GetDataSurface(); if (dataSurface) { return EncodeImageData(dataSurface, aMimeType, aOutputOptions, aStream);
}
}
// Otherwise we need to scale it using a draw target. // Ensure the surface is initialized to clear in case we need to blend to it.
RefPtr<DataSourceSurface> dataSurface = Factory::CreateDataSourceSurface(
scaledSize, SurfaceFormat::B8G8R8A8, true); if (NS_WARN_IF(!dataSurface)) { return NS_ERROR_FAILURE;
}
DataSourceSurface::ScopedMap map(dataSurface, DataSourceSurface::READ_WRITE); if (!map.IsMapped()) { return NS_ERROR_FAILURE;
}
// Prefer using OP_OVER to scale the surface instead of OP_SOURCE, as both // D2D and Skia have specific fast-paths for these, and may give divergent // and slower results when using OP_SOURCE.
IntSize frameSize = frame->GetSize();
dt->DrawSurface(frame, Rect(0, 0, scaledSize.width, scaledSize.height),
Rect(0, 0, frameSize.width, frameSize.height),
DrawSurfaceOptions(),
DrawOptions(1.0f, CompositionOp::OP_OVER));
// Offsets must be zero when no width and height are given or else we're out // of bounds.
NS_ENSURE_ARG(aWidth + aHeight > 0 || aOffsetX + aOffsetY == 0);
// If no size is specified then we'll preserve the image's original dimensions // and don't need to crop. if (aWidth == 0 && aHeight == 0) { return EncodeImage(aContainer, aMimeType, aOutputOptions, aStream);
}
// Use frame 0 from the image container.
RefPtr<SourceSurface> frame = aContainer->GetFrame(
imgIContainer::FRAME_FIRST,
imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_ASYNC_NOTIFY);
NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
// If the given width or height is zero we'll replace it with the image's // original dimensions. if (aWidth == 0) {
aWidth = frameWidth;
} elseif (aHeight == 0) {
aHeight = frameHeight;
}
// Check that the given crop rectangle is within image bounds.
NS_ENSURE_ARG(frameWidth >= aOffsetX + aWidth &&
frameHeight >= aOffsetY + aHeight);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.