Bug 389273 - large favicons (>32 KB) won't show up in url bar autocomplete, history / bookmarks menu, bm organizer. r=sspitzer, stuart. a1.9=schrep
@ -58,6 +58,7 @@
|
||||
#include "imgLoader.h"
|
||||
#include "imgRequest.h"
|
||||
#include "imgRequestProxy.h"
|
||||
#include "imgTools.h"
|
||||
|
||||
#ifdef IMG_BUILD_DECODER_gif
|
||||
// gif
|
||||
@ -102,6 +103,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(imgCache)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(imgContainer)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(imgLoader)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(imgRequestProxy)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(imgTools)
|
||||
|
||||
#ifdef IMG_BUILD_DECODER_gif
|
||||
// gif
|
||||
@ -217,6 +219,10 @@ static const nsModuleComponentInfo components[] =
|
||||
NS_IMGREQUESTPROXY_CID,
|
||||
"@mozilla.org/image/request;1",
|
||||
imgRequestProxyConstructor, },
|
||||
{ "image tools",
|
||||
NS_IMGTOOLS_CID,
|
||||
"@mozilla.org/image/tools;1",
|
||||
imgToolsConstructor, },
|
||||
|
||||
#ifdef IMG_BUILD_DECODER_gif
|
||||
// gif
|
||||
|
@ -49,4 +49,5 @@
|
||||
#define NS_IMAGELIB_ERROR_NO_DECODER NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_IMGLIB, 6)
|
||||
#define NS_IMAGELIB_ERROR_NOT_FINISHED NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_IMGLIB, 7)
|
||||
#define NS_IMAGELIB_ERROR_LOAD_ABORTED NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_IMGLIB, 8)
|
||||
#define NS_IMAGELIB_ERROR_NO_ENCODER NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_IMGLIB, 9)
|
||||
|
||||
|
@ -52,11 +52,12 @@ XPIDLSRCS = \
|
||||
imgIContainer.idl \
|
||||
imgIContainerObserver.idl \
|
||||
imgIDecoder.idl \
|
||||
imgIDecoderObserver.idl \
|
||||
imgIDecoderObserver.idl \
|
||||
imgIEncoder.idl \
|
||||
imgILoad.idl \
|
||||
imgILoader.idl \
|
||||
imgIRequest.idl \
|
||||
imgIRequest.idl \
|
||||
imgITools.idl \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
97
modules/libpr0n/public/imgITools.idl
Normal file
@ -0,0 +1,97 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2007
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Justin Dolske <dolske@mozilla.com> (original author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIInputStream;
|
||||
interface imgIContainer;
|
||||
|
||||
[scriptable, uuid(c395d8f1-c616-4a1b-adfd-747b4b1b2cbe)]
|
||||
interface imgITools : nsISupports
|
||||
{
|
||||
/**
|
||||
* decodeImageData
|
||||
* Caller provides an input stream and mimetype. We read from the stream
|
||||
* and decompress it (according to the specified mime type) and return
|
||||
* the resulting imgIContainer. (If the caller already has a container,
|
||||
* it can be provided as input to be reused).
|
||||
*
|
||||
* @param aStream
|
||||
* An input stream for an encoded image file.
|
||||
* @param aMimeType
|
||||
* Type of image in the stream.
|
||||
* @param aContainer
|
||||
* An imgIContainer holding the decoded image. Specify |null| when
|
||||
* calling to have one created, otherwise specify a container to
|
||||
* be reused.
|
||||
*/
|
||||
void decodeImageData(in nsIInputStream aStream,
|
||||
in ACString aMimeType,
|
||||
inout imgIContainer aContainer);
|
||||
|
||||
/**
|
||||
* encodeImage
|
||||
* Caller provides an image container, and the mime type it should be
|
||||
* encoded to. We return an input stream for the encoded image data.
|
||||
*
|
||||
* @param aContainer
|
||||
* An image container.
|
||||
* @param aMimeType
|
||||
* Type of encoded image desired (eg "image/png").
|
||||
*/
|
||||
nsIInputStream encodeImage(in imgIContainer aContainer,
|
||||
in ACString aMimeType);
|
||||
|
||||
/**
|
||||
* encodeScaledImage
|
||||
* Caller provides an image container, and the mime type it should be
|
||||
* encoded to. We return an input stream for the encoded image data.
|
||||
* The encoded image is scaled to the specified dimensions.
|
||||
*
|
||||
* @param aContainer
|
||||
* An image container.
|
||||
* @param aMimeType
|
||||
* Type of encoded image desired (eg "image/png").
|
||||
* @param aWidth, aHeight
|
||||
* The size (in pixels) desired for the resulting image.
|
||||
*/
|
||||
nsIInputStream encodeScaledImage(in imgIContainer aContainer,
|
||||
in ACString aMimeType,
|
||||
in long aWidth,
|
||||
in long aHeight);
|
||||
};
|
@ -66,7 +66,8 @@ CPPSRCS = \
|
||||
imgContainer.cpp \
|
||||
imgLoader.cpp \
|
||||
imgRequest.cpp \
|
||||
imgRequestProxy.cpp
|
||||
imgRequestProxy.cpp \
|
||||
imgTools.cpp
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
|
356
modules/libpr0n/src/imgTools.cpp
Normal file
@ -0,0 +1,356 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2007
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Justin Dolske <dolske@mozilla.com> (original author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "imgTools.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "ImageErrors.h"
|
||||
#include "imgIContainer.h"
|
||||
#include "imgILoad.h"
|
||||
#include "imgIDecoder.h"
|
||||
#include "imgIEncoder.h"
|
||||
#include "imgIDecoderObserver.h"
|
||||
#include "imgIContainerObserver.h"
|
||||
#include "nsIImage.h"
|
||||
#include "gfxIImageFrame.h"
|
||||
#include "gfxImageSurface.h"
|
||||
#include "gfxContext.h"
|
||||
#include "nsStringStream.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
|
||||
|
||||
/* ========== Utility classes ========== */
|
||||
|
||||
|
||||
class HelperLoader : public imgILoad,
|
||||
public imgIDecoderObserver,
|
||||
public nsSupportsWeakReference
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_IMGILOAD
|
||||
NS_DECL_IMGIDECODEROBSERVER
|
||||
NS_DECL_IMGICONTAINEROBSERVER
|
||||
HelperLoader(void);
|
||||
|
||||
private:
|
||||
nsCOMPtr<imgIContainer> mContainer;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS4 (HelperLoader, imgILoad, imgIDecoderObserver, imgIContainerObserver, nsISupportsWeakReference)
|
||||
|
||||
HelperLoader::HelperLoader (void)
|
||||
{
|
||||
}
|
||||
|
||||
/* Implement imgILoad::image getter */
|
||||
NS_IMETHODIMP
|
||||
HelperLoader::GetImage(imgIContainer **aImage)
|
||||
{
|
||||
*aImage = mContainer;
|
||||
NS_IF_ADDREF (*aImage);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* Implement imgILoad::image setter */
|
||||
NS_IMETHODIMP
|
||||
HelperLoader::SetImage(imgIContainer *aImage)
|
||||
{
|
||||
mContainer = aImage;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* Implement imgILoad::isMultiPartChannel getter */
|
||||
NS_IMETHODIMP
|
||||
HelperLoader::GetIsMultiPartChannel(PRBool *aIsMultiPartChannel)
|
||||
{
|
||||
*aIsMultiPartChannel = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* Implement imgIDecoderObserver::onStartRequest() */
|
||||
NS_IMETHODIMP
|
||||
HelperLoader::OnStartRequest(imgIRequest *aRequest)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* Implement imgIDecoderObserver::onStartDecode() */
|
||||
NS_IMETHODIMP
|
||||
HelperLoader::OnStartDecode(imgIRequest *aRequest)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* Implement imgIDecoderObserver::onStartContainer() */
|
||||
NS_IMETHODIMP
|
||||
HelperLoader::OnStartContainer(imgIRequest *aRequest, imgIContainer
|
||||
*aContainer)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* Implement imgIDecoderObserver::onStartFrame() */
|
||||
NS_IMETHODIMP
|
||||
HelperLoader::OnStartFrame(imgIRequest *aRequest, gfxIImageFrame *aFrame)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* Implement imgIDecoderObserver::onDataAvailable() */
|
||||
NS_IMETHODIMP
|
||||
HelperLoader::OnDataAvailable(imgIRequest *aRequest, gfxIImageFrame
|
||||
*aFrame, const nsIntRect * aRect)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* Implement imgIDecoderObserver::onStopFrame() */
|
||||
NS_IMETHODIMP
|
||||
HelperLoader::OnStopFrame(imgIRequest *aRequest, gfxIImageFrame *aFrame)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* Implement imgIDecoderObserver::onStopContainer() */
|
||||
NS_IMETHODIMP
|
||||
HelperLoader::OnStopContainer(imgIRequest *aRequest, imgIContainer
|
||||
*aContainer)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* Implement imgIDecoderObserver::onStopDecode() */
|
||||
NS_IMETHODIMP
|
||||
HelperLoader::OnStopDecode(imgIRequest *aRequest, nsresult status, const
|
||||
PRUnichar *statusArg)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* Implement imgIDecoderObserver::onStopRequest() */
|
||||
NS_IMETHODIMP
|
||||
HelperLoader::OnStopRequest(imgIRequest *aRequest, PRBool aIsLastPart)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* implement imgIContainerObserver::frameChanged() */
|
||||
NS_IMETHODIMP
|
||||
HelperLoader::FrameChanged(imgIContainer *aContainer,
|
||||
gfxIImageFrame *aFrame, nsIntRect * aDirtyRect)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ========== imgITools implementation ========== */
|
||||
|
||||
|
||||
|
||||
NS_IMPL_ISUPPORTS1(imgTools, imgITools)
|
||||
|
||||
imgTools::imgTools()
|
||||
{
|
||||
/* member initializers and constructor code */
|
||||
}
|
||||
|
||||
imgTools::~imgTools()
|
||||
{
|
||||
/* destructor code */
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP imgTools::DecodeImageData(nsIInputStream* aInStr,
|
||||
const nsACString& aMimeType,
|
||||
imgIContainer **aContainer)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
// Get an image decoder for our media type
|
||||
nsCAutoString decoderCID(
|
||||
NS_LITERAL_CSTRING("@mozilla.org/image/decoder;2?type=") + aMimeType);
|
||||
|
||||
nsCOMPtr<imgIDecoder> decoder = do_CreateInstance(decoderCID.get());
|
||||
if (!decoder)
|
||||
return NS_IMAGELIB_ERROR_NO_DECODER;
|
||||
|
||||
// Init the decoder, we use a small utility class here.
|
||||
nsCOMPtr<imgILoad> loader = new HelperLoader();
|
||||
if (!loader)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// If caller provided an existing container, use it.
|
||||
if (*aContainer)
|
||||
loader->SetImage(*aContainer);
|
||||
|
||||
rv = decoder->Init(loader);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRUint32 length;
|
||||
rv = aInStr->Available(&length);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRUint32 written;
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = decoder->WriteFrom(aInStr, length, &written);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ASSERTION(written == length, "decoder didn't eat all of its vegetables");
|
||||
rv = decoder->Flush();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = decoder->Close();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// If caller didn't provide an existing container, return the new one.
|
||||
if (!*aContainer)
|
||||
loader->GetImage(aContainer);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP imgTools::EncodeImage(imgIContainer *aContainer,
|
||||
const nsACString& aMimeType,
|
||||
nsIInputStream **aStream)
|
||||
{
|
||||
return EncodeScaledImage(aContainer, aMimeType, 0, 0, aStream);
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP imgTools::EncodeScaledImage(imgIContainer *aContainer,
|
||||
const nsACString& aMimeType,
|
||||
PRInt32 aScaledWidth,
|
||||
PRInt32 aScaledHeight,
|
||||
nsIInputStream **aStream)
|
||||
{
|
||||
nsresult rv;
|
||||
PRBool doScaling = PR_TRUE;
|
||||
PRUint8 *bitmapData;
|
||||
PRUint32 bitmapDataLength, strideSize;
|
||||
|
||||
// If no scaled size is specified, we'll just encode the image at its
|
||||
// original size (no scaling).
|
||||
if (aScaledWidth == 0 && aScaledHeight == 0) {
|
||||
doScaling = PR_FALSE;
|
||||
} else {
|
||||
NS_ENSURE_ARG(aScaledWidth > 0);
|
||||
NS_ENSURE_ARG(aScaledHeight > 0);
|
||||
}
|
||||
|
||||
// Get an image encoder for the media type
|
||||
nsCAutoString encoderCID(
|
||||
NS_LITERAL_CSTRING("@mozilla.org/image/encoder;2?type=") + aMimeType);
|
||||
|
||||
nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(encoderCID.get());
|
||||
if (!encoder)
|
||||
return NS_IMAGELIB_ERROR_NO_ENCODER;
|
||||
|
||||
// Use frame 0 from the image container.
|
||||
nsCOMPtr<gfxIImageFrame> frame;
|
||||
rv = aContainer->GetFrameAt(0, getter_AddRefs(frame));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRInt32 w,h;
|
||||
frame->GetWidth(&w);
|
||||
frame->GetHeight(&h);
|
||||
if (!w || !h)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsIImage> img(do_GetInterface(frame));
|
||||
nsRefPtr<gfxImageSurface> dest;
|
||||
|
||||
if (!doScaling) {
|
||||
// If we're not scaling the image, use the actual width/height.
|
||||
aScaledWidth = w;
|
||||
aScaledHeight = h;
|
||||
|
||||
img->LockImagePixels(PR_FALSE);
|
||||
bitmapData = img->GetBits();
|
||||
if (!bitmapData) {
|
||||
img->UnlockImagePixels(PR_FALSE);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
frame->GetImageBytesPerRow(&strideSize);
|
||||
bitmapDataLength = aScaledHeight * strideSize;
|
||||
|
||||
} else {
|
||||
// Prepare to draw a scaled version of the image to a temporary surface...
|
||||
|
||||
// Get the source image surface
|
||||
nsRefPtr<gfxASurface> gfxsurf;
|
||||
rv = img->GetSurface(getter_AddRefs(gfxsurf));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Create a temporary image surface
|
||||
dest = new gfxImageSurface(gfxIntSize(aScaledWidth, aScaledHeight),
|
||||
gfxASurface::ImageFormatARGB32);
|
||||
if (!dest)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
gfxContext ctx(dest);
|
||||
|
||||
// Set scaling
|
||||
gfxFloat sw = (double) aScaledWidth / w;
|
||||
gfxFloat sh = (double) aScaledHeight / h;
|
||||
ctx.Scale(sw, sh);
|
||||
|
||||
// Paint a scaled image
|
||||
ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
|
||||
ctx.SetSource(gfxsurf);
|
||||
ctx.Paint();
|
||||
|
||||
bitmapData = dest->Data();
|
||||
strideSize = dest->Stride();
|
||||
bitmapDataLength = aScaledHeight * strideSize;
|
||||
}
|
||||
|
||||
// Encode the bitmap
|
||||
rv = encoder->InitFromData(bitmapData, bitmapDataLength,
|
||||
aScaledWidth, aScaledHeight, strideSize,
|
||||
imgIEncoder::INPUT_FORMAT_HOSTARGB, EmptyString());
|
||||
if (!doScaling)
|
||||
img->UnlockImagePixels(PR_FALSE);
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return CallQueryInterface(encoder, aStream);
|
||||
}
|
57
modules/libpr0n/src/imgTools.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2007
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Justin Dolske <dolske@mozilla.com> (original author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "imgITools.h"
|
||||
|
||||
#define NS_IMGTOOLS_CID \
|
||||
{ /* fd9a9e8a-a77b-496a-b7bb-263df9715149 */ \
|
||||
0xfd9a9e8a, \
|
||||
0xa77b, \
|
||||
0x496a, \
|
||||
{0xb7, 0xbb, 0x26, 0x3d, 0xf9, 0x71, 0x51, 0x49} \
|
||||
}
|
||||
|
||||
class imgTools : public imgITools
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_IMGITOOLS
|
||||
|
||||
imgTools();
|
||||
virtual ~imgTools();
|
||||
};
|
BIN
modules/libpr0n/test/unit/image1.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
modules/libpr0n/test/unit/image1png16x16.jpg
Normal file
After Width: | Height: | Size: 733 B |
BIN
modules/libpr0n/test/unit/image1png64x64.jpg
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
modules/libpr0n/test/unit/image2.jpg
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
modules/libpr0n/test/unit/image2jpg16x16.png
Normal file
After Width: | Height: | Size: 948 B |
BIN
modules/libpr0n/test/unit/image2jpg32x32.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
modules/libpr0n/test/unit/image3.ico
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
modules/libpr0n/test/unit/image3ico16x16.png
Normal file
After Width: | Height: | Size: 330 B |
BIN
modules/libpr0n/test/unit/image3ico32x32.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
294
modules/libpr0n/test/unit/test_imgtools.js
Normal file
@ -0,0 +1,294 @@
|
||||
/*
|
||||
* Tests for imgITools
|
||||
*/
|
||||
|
||||
const TESTDIR = "modules/libpr0n/test/unit/";
|
||||
const Ci = Components.interfaces;
|
||||
const Cc = Components.classes;
|
||||
|
||||
|
||||
/*
|
||||
* dumpToFile()
|
||||
*
|
||||
* For test development, dumps the specified array to a file.
|
||||
* Call |dumpToFile(outData);| in a test to file to a file.
|
||||
*/
|
||||
function dumpToFile(aData) {
|
||||
const path = "/tmp";
|
||||
|
||||
var outputFile = Cc["@mozilla.org/file/local;1"].
|
||||
createInstance(Ci.nsILocalFile);
|
||||
outputFile.initWithPath(path);
|
||||
outputFile.append("testdump.png");
|
||||
|
||||
var outputStream = Cc["@mozilla.org/network/file-output-stream;1"].
|
||||
createInstance(Ci.nsIFileOutputStream);
|
||||
// WR_ONLY|CREAT|TRUNC
|
||||
outputStream.init(outputFile, 0x02 | 0x08 | 0x20, 0644, null);
|
||||
|
||||
var bos = Cc["@mozilla.org/binaryoutputstream;1"].
|
||||
createInstance(Ci.nsIBinaryOutputStream);
|
||||
bos.setOutputStream(outputStream);
|
||||
|
||||
bos.writeByteArray(aData, aData.length);
|
||||
|
||||
outputStream.close();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* getFileInputStream()
|
||||
*
|
||||
* Returns an input stream for the specified file.
|
||||
*/
|
||||
function getFileInputStream(aFile) {
|
||||
var inputStream = Cc["@mozilla.org/network/file-input-stream;1"].
|
||||
createInstance(Ci.nsIFileInputStream);
|
||||
// init the stream as RD_ONLY, -1 == default permissions.
|
||||
inputStream.init(aFile, 0x01, -1, null);
|
||||
|
||||
// Blah. The image decoders use ReadSegments, which isn't implemented on
|
||||
// file input streams. Use a buffered stream to make it work.
|
||||
var bis = Cc["@mozilla.org/network/buffered-input-stream;1"].
|
||||
createInstance(Ci.nsIBufferedInputStream);
|
||||
bis.init(inputStream, 1024);
|
||||
|
||||
return bis;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* streamToArray()
|
||||
*
|
||||
* Consumes an input stream, and returns its bytes as an array.
|
||||
*/
|
||||
function streamToArray(aStream) {
|
||||
var size = aStream.available();
|
||||
|
||||
// use a binary input stream to grab the bytes.
|
||||
var bis = Cc["@mozilla.org/binaryinputstream;1"].
|
||||
createInstance(Ci.nsIBinaryInputStream);
|
||||
bis.setInputStream(aStream);
|
||||
|
||||
var bytes = bis.readByteArray(size);
|
||||
if (size != bytes.length)
|
||||
throw "Didn't read expected number of bytes";
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* compareArrays
|
||||
*
|
||||
* Compares two arrays, and throws if there's a difference.
|
||||
*/
|
||||
function compareArrays(aArray1, aArray2) {
|
||||
do_check_eq(aArray1.length, aArray2.length);
|
||||
|
||||
for (var i = 0; i < aArray1.length; i++)
|
||||
if (aArray1[i] != aArray2[i])
|
||||
throw "arrays differ at index " + i;
|
||||
}
|
||||
|
||||
|
||||
function run_test() {
|
||||
try {
|
||||
|
||||
|
||||
/* ========== 0 ========== */
|
||||
var testnum = 0;
|
||||
var testdesc = "imgITools setup";
|
||||
|
||||
var imgTools = Cc["@mozilla.org/image/tools;1"].
|
||||
getService(Ci.imgITools);
|
||||
|
||||
if (!imgTools)
|
||||
throw "Couldn't get imgITools service"
|
||||
|
||||
|
||||
/* ========== 1 ========== */
|
||||
testnum++;
|
||||
testdesc = "test decoding a PNG";
|
||||
|
||||
// 64x64 png, 10698 bytes.
|
||||
var imgName = "image1.png";
|
||||
var inMimeType = "image/png";
|
||||
var imgFile = do_get_file(TESTDIR + imgName);
|
||||
|
||||
var istream = getFileInputStream(imgFile);
|
||||
do_check_eq(istream.available(), 10698);
|
||||
|
||||
var outParam = { value: null };
|
||||
imgTools.decodeImageData(istream, inMimeType, outParam);
|
||||
var container = outParam.value;
|
||||
|
||||
// It's not easy to look at the pixel values from JS, so just
|
||||
// check the container's size.
|
||||
do_check_eq(container.width, 64);
|
||||
do_check_eq(container.height, 64);
|
||||
|
||||
|
||||
/* ========== 2 ========== */
|
||||
testnum++;
|
||||
testdesc = "test encoding a scaled JPEG";
|
||||
|
||||
// we'll reuse the container from the previous test
|
||||
istream = imgTools.encodeScaledImage(container, "image/jpeg", 16, 16);
|
||||
|
||||
var encodedBytes = streamToArray(istream);
|
||||
// Get bytes for exected result
|
||||
var refName = "image1png16x16.jpg";
|
||||
var refFile = do_get_file(TESTDIR + refName);
|
||||
istream = getFileInputStream(refFile);
|
||||
do_check_eq(istream.available(), 733);
|
||||
var referenceBytes = streamToArray(istream);
|
||||
|
||||
// compare the encoder's output to the reference file.
|
||||
compareArrays(encodedBytes, referenceBytes);
|
||||
|
||||
|
||||
/* ========== 3 ========== */
|
||||
testnum++;
|
||||
testdesc = "test encoding an unscaled JPEG";
|
||||
|
||||
// we'll reuse the container from the previous test
|
||||
istream = imgTools.encodeImage(container, "image/jpeg");
|
||||
encodedBytes = streamToArray(istream);
|
||||
|
||||
// Get bytes for exected result
|
||||
refName = "image1png64x64.jpg";
|
||||
refFile = do_get_file(TESTDIR + refName);
|
||||
istream = getFileInputStream(refFile);
|
||||
do_check_eq(istream.available(), 1593);
|
||||
referenceBytes = streamToArray(istream);
|
||||
|
||||
// compare the encoder's output to the reference file.
|
||||
compareArrays(encodedBytes, referenceBytes);
|
||||
|
||||
|
||||
/* ========== 4 ========== */
|
||||
testnum++;
|
||||
testdesc = "test decoding a JPEG";
|
||||
|
||||
// 32x32 jpeg, 3494 bytes.
|
||||
imgName = "image2.jpg";
|
||||
inMimeType = "image/jpeg";
|
||||
imgFile = do_get_file(TESTDIR + imgName);
|
||||
|
||||
istream = getFileInputStream(imgFile);
|
||||
do_check_eq(istream.available(), 3494);
|
||||
|
||||
outParam = {};
|
||||
imgTools.decodeImageData(istream, inMimeType, outParam);
|
||||
container = outParam.value;
|
||||
|
||||
// It's not easy to look at the pixel values from JS, so just
|
||||
// check the container's size.
|
||||
do_check_eq(container.width, 32);
|
||||
do_check_eq(container.height, 32);
|
||||
|
||||
|
||||
/* ========== 5 ========== */
|
||||
testnum++;
|
||||
testdesc = "test encoding a scaled PNG";
|
||||
|
||||
// we'll reuse the container from the previous test
|
||||
istream = imgTools.encodeScaledImage(container, "image/png", 16, 16);
|
||||
|
||||
encodedBytes = streamToArray(istream);
|
||||
// Get bytes for exected result
|
||||
refName = "image2jpg16x16.png";
|
||||
refFile = do_get_file(TESTDIR + refName);
|
||||
istream = getFileInputStream(refFile);
|
||||
do_check_eq(istream.available(), 948);
|
||||
referenceBytes = streamToArray(istream);
|
||||
|
||||
// compare the encoder's output to the reference file.
|
||||
compareArrays(encodedBytes, referenceBytes);
|
||||
|
||||
|
||||
/* ========== 6 ========== */
|
||||
testnum++;
|
||||
testdesc = "test encoding an unscaled PNG";
|
||||
|
||||
// we'll reuse the container from the previous test
|
||||
istream = imgTools.encodeImage(container, "image/png");
|
||||
encodedBytes = streamToArray(istream);
|
||||
|
||||
// Get bytes for exected result
|
||||
refName = "image2jpg32x32.png";
|
||||
refFile = do_get_file(TESTDIR + refName);
|
||||
istream = getFileInputStream(refFile);
|
||||
do_check_eq(istream.available(), 3105);
|
||||
referenceBytes = streamToArray(istream);
|
||||
|
||||
// compare the encoder's output to the reference file.
|
||||
compareArrays(encodedBytes, referenceBytes);
|
||||
|
||||
|
||||
/* ========== 7 ========== */
|
||||
testnum++;
|
||||
testdesc = "test decoding a ICO";
|
||||
|
||||
// 16x16 ico, 1406 bytes.
|
||||
imgName = "image3.ico";
|
||||
inMimeType = "image/x-icon";
|
||||
imgFile = do_get_file(TESTDIR + imgName);
|
||||
|
||||
istream = getFileInputStream(imgFile);
|
||||
do_check_eq(istream.available(), 1406);
|
||||
|
||||
outParam = { value: null };
|
||||
imgTools.decodeImageData(istream, inMimeType, outParam);
|
||||
container = outParam.value;
|
||||
|
||||
// It's not easy to look at the pixel values from JS, so just
|
||||
// check the container's size.
|
||||
do_check_eq(container.width, 16);
|
||||
do_check_eq(container.height, 16);
|
||||
|
||||
|
||||
/* ========== 8 ========== */
|
||||
testnum++;
|
||||
testdesc = "test encoding a scaled PNG"; // note that we're scaling UP
|
||||
|
||||
// we'll reuse the container from the previous test
|
||||
istream = imgTools.encodeScaledImage(container, "image/png", 32, 32);
|
||||
encodedBytes = streamToArray(istream);
|
||||
|
||||
// Get bytes for exected result
|
||||
refName = "image3ico32x32.png";
|
||||
refFile = do_get_file(TESTDIR + refName);
|
||||
istream = getFileInputStream(refFile);
|
||||
do_check_eq(istream.available(), 2281);
|
||||
referenceBytes = streamToArray(istream);
|
||||
|
||||
// compare the encoder's output to the reference file.
|
||||
compareArrays(encodedBytes, referenceBytes);
|
||||
|
||||
|
||||
/* ========== 9 ========== */
|
||||
testnum++;
|
||||
testdesc = "test encoding an unscaled PNG";
|
||||
|
||||
// we'll reuse the container from the previous test
|
||||
istream = imgTools.encodeImage(container, "image/png");
|
||||
encodedBytes = streamToArray(istream);
|
||||
|
||||
// Get bytes for exected result
|
||||
refName = "image3ico16x16.png";
|
||||
refFile = do_get_file(TESTDIR + refName);
|
||||
istream = getFileInputStream(refFile);
|
||||
do_check_eq(istream.available(), 330);
|
||||
referenceBytes = streamToArray(istream);
|
||||
|
||||
// compare the encoder's output to the reference file.
|
||||
compareArrays(encodedBytes, referenceBytes);
|
||||
|
||||
/* ========== end ========== */
|
||||
|
||||
} catch (e) {
|
||||
throw "FAILED in test #" + testnum + " -- " + testdesc + ": " + e;
|
||||
}
|
||||
};
|
@ -59,6 +59,8 @@ REQUIRES = xpcom \
|
||||
morkreader \
|
||||
pref \
|
||||
necko \
|
||||
imglib2 \
|
||||
gfx \
|
||||
intl \
|
||||
layout \
|
||||
locale \
|
||||
|
@ -59,14 +59,12 @@
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsStreamUtils.h"
|
||||
#include "nsStringStream.h"
|
||||
#include "mozStorageHelper.h"
|
||||
|
||||
// This is the maximum favicon size that we will bother storing. Most icons
|
||||
// are about 4K. Some people add 32x32 versions at different bit depths,
|
||||
// making them much bigger. It would be nice if could extract just the 16x16
|
||||
// version that we need. Instead, we'll just store everything below this
|
||||
// sanity threshold.
|
||||
#define MAX_FAVICON_SIZE 32768
|
||||
// For favicon optimization
|
||||
#include "imgITools.h"
|
||||
#include "imgIContainer.h"
|
||||
|
||||
#define FAVICON_BUFFER_INCREMENT 8192
|
||||
|
||||
@ -553,6 +551,24 @@ nsFaviconService::SetFaviconData(nsIURI* aFavicon, const PRUint8* aData,
|
||||
PRTime aExpiration)
|
||||
{
|
||||
nsresult rv;
|
||||
PRUint32 dataLen = aDataLen;
|
||||
const PRUint8* data = aData;
|
||||
const nsACString* mimeType = &aMimeType;
|
||||
nsCString newData, newMimeType;
|
||||
|
||||
// If the page provided a large image for the favicon (eg, a highres image
|
||||
// or a multiresolution .ico file), we don't want to store more data than
|
||||
// needed. An uncompressed 16x16 RGBA image is 1024 bytes, and almost all
|
||||
// sensible 16x16 icons are under 1024 bytes.
|
||||
if (aDataLen > 1024) {
|
||||
rv = OptimizeFaviconImage(aData, aDataLen, aMimeType, newData, newMimeType);
|
||||
if (NS_SUCCEEDED(rv) && newData.Length() < aDataLen) {
|
||||
data = reinterpret_cast<PRUint8*>(const_cast<char*>(newData.get())),
|
||||
dataLen = newData.Length();
|
||||
mimeType = &newMimeType;
|
||||
}
|
||||
}
|
||||
|
||||
mozIStorageStatement* statement;
|
||||
{
|
||||
// this block forces the scoper to reset our statement: necessary for the
|
||||
@ -583,9 +599,9 @@ nsFaviconService::SetFaviconData(nsIURI* aFavicon, const PRUint8* aData,
|
||||
mozStorageStatementScoper scoper(statement);
|
||||
|
||||
// the insert and update statements share all but the 0th parameter
|
||||
rv = statement->BindBlobParameter(1, aData, aDataLen);
|
||||
rv = statement->BindBlobParameter(1, data, dataLen);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = statement->BindUTF8StringParameter(2, aMimeType);
|
||||
rv = statement->BindUTF8StringParameter(2, *mimeType);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = statement->BindInt64Parameter(3, aExpiration);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
@ -800,6 +816,48 @@ nsFaviconService::GetFaviconSpecForIconString(const nsCString& aSpec, nsACString
|
||||
}
|
||||
|
||||
|
||||
// nsFaviconService::OptimizeFaviconImage
|
||||
//
|
||||
// Given a blob of data (a image file already read into a buffer), optimize
|
||||
// its size by recompressing it as a 16x16 PNG.
|
||||
nsresult
|
||||
nsFaviconService::OptimizeFaviconImage(const PRUint8* aData, PRUint32 aDataLen,
|
||||
const nsACString& aMimeType,
|
||||
nsACString& aNewData,
|
||||
nsACString& aNewMimeType)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
|
||||
nsCOMPtr<imgITools> imgtool = do_CreateInstance("@mozilla.org/image/tools;1");
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
rv = NS_NewByteInputStream(getter_AddRefs(stream),
|
||||
reinterpret_cast<const char*>(aData), aDataLen,
|
||||
NS_ASSIGNMENT_DEPEND);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// decode image
|
||||
nsCOMPtr<imgIContainer> container;
|
||||
rv = imgtool->DecodeImageData(stream, aMimeType, getter_AddRefs(container));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
aNewMimeType.AssignLiteral("image/png");
|
||||
|
||||
// scale and recompress
|
||||
nsCOMPtr<nsIInputStream> iconStream;
|
||||
rv = imgtool->EncodeScaledImage(container, aNewMimeType, 16, 16,
|
||||
getter_AddRefs(iconStream));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Read the stream into a new buffer.
|
||||
rv = NS_ConsumeStream(iconStream, PR_UINT32_MAX, aNewData);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMPL_ISUPPORTS4(FaviconLoadListener,
|
||||
nsIRequestObserver,
|
||||
nsIStreamListener,
|
||||
@ -926,9 +984,6 @@ FaviconLoadListener::OnDataAvailable(nsIRequest *aRequest, nsISupports *aContext
|
||||
nsIInputStream *aInputStream,
|
||||
PRUint32 aOffset, PRUint32 aCount)
|
||||
{
|
||||
if (aOffset + aCount > MAX_FAVICON_SIZE)
|
||||
return NS_ERROR_FAILURE; // too big
|
||||
|
||||
nsCString buffer;
|
||||
nsresult rv = NS_ConsumeStream(aInputStream, aCount, buffer);
|
||||
if (rv != NS_BASE_STREAM_WOULD_BLOCK && NS_FAILED(rv))
|
||||
|
@ -87,6 +87,9 @@ public:
|
||||
nsresult GetFaviconLinkForIconString(const nsCString& aIcon, nsIURI** aOutput);
|
||||
void GetFaviconSpecForIconString(const nsCString& aIcon, nsACString& aOutput);
|
||||
|
||||
static nsresult OptimizeFaviconImage(const PRUint8* aData, PRUint32 aDataLen,
|
||||
const nsACString& aMimeType,
|
||||
nsACString& aNewData, nsACString& aNewMimeType);
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIFAVICONSERVICE
|
||||
|
||||
|
After Width: | Height: | Size: 330 B |
After Width: | Height: | Size: 948 B |
After Width: | Height: | Size: 245 B |
After Width: | Height: | Size: 656 B |
After Width: | Height: | Size: 866 B |
After Width: | Height: | Size: 131 B |
After Width: | Height: | Size: 124 B |
BIN
toolkit/components/places/tests/unit/favicon-big16.ico
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
toolkit/components/places/tests/unit/favicon-big32.jpg
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
toolkit/components/places/tests/unit/favicon-big4.jpg
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
toolkit/components/places/tests/unit/favicon-big48.ico
Normal file
After Width: | Height: | Size: 55 KiB |
BIN
toolkit/components/places/tests/unit/favicon-big64.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
toolkit/components/places/tests/unit/favicon-normal16.png
Normal file
After Width: | Height: | Size: 286 B |
BIN
toolkit/components/places/tests/unit/favicon-normal32.png
Normal file
After Width: | Height: | Size: 344 B |
BIN
toolkit/components/places/tests/unit/favicon-scale160x3.jpg
Normal file
After Width: | Height: | Size: 5.0 KiB |
BIN
toolkit/components/places/tests/unit/favicon-scale3x160.jpg
Normal file
After Width: | Height: | Size: 4.9 KiB |
324
toolkit/components/places/tests/unit/test_favicons.js
Normal file
@ -0,0 +1,324 @@
|
||||
/*
|
||||
* Tests for nsIFaviconService
|
||||
*/
|
||||
|
||||
const TESTDIR = "toolkit/components/places/tests/unit/";
|
||||
|
||||
/*
|
||||
* dumpToFile()
|
||||
*
|
||||
* For test development, dumps the specified array to a file.
|
||||
* Call |dumpToFile(outData);| in a test to file to a file.
|
||||
*/
|
||||
function dumpToFile(aData) {
|
||||
const path = "/tmp";
|
||||
|
||||
var outputFile = Cc["@mozilla.org/file/local;1"].
|
||||
createInstance(Ci.nsILocalFile);
|
||||
outputFile.initWithPath(path);
|
||||
outputFile.append("testdump.png");
|
||||
|
||||
var outputStream = Cc["@mozilla.org/network/file-output-stream;1"].
|
||||
createInstance(Ci.nsIFileOutputStream);
|
||||
// WR_ONLY|CREAT|TRUNC
|
||||
outputStream.init(outputFile, 0x02 | 0x08 | 0x20, 0644, null);
|
||||
|
||||
var bos = Cc["@mozilla.org/binaryoutputstream;1"].
|
||||
createInstance(Ci.nsIBinaryOutputStream);
|
||||
bos.setOutputStream(outputStream);
|
||||
|
||||
bos.writeByteArray(aData, aData.length);
|
||||
|
||||
outputStream.close();
|
||||
}
|
||||
|
||||
/*
|
||||
* readFileData()
|
||||
*
|
||||
* Reads the data from the specified nsIFile, and returns an array of bytes.
|
||||
*/
|
||||
function readFileData(aFile) {
|
||||
var inputStream = Cc["@mozilla.org/network/file-input-stream;1"].
|
||||
createInstance(Ci.nsIFileInputStream);
|
||||
// init the stream as RD_ONLY, -1 == default permissions.
|
||||
inputStream.init(aFile, 0x01, -1, null);
|
||||
var size = inputStream.available();
|
||||
|
||||
// use a binary input stream to grab the bytes.
|
||||
var bis = Cc["@mozilla.org/binaryinputstream;1"].
|
||||
createInstance(Ci.nsIBinaryInputStream);
|
||||
bis.setInputStream(inputStream);
|
||||
|
||||
var bytes = bis.readByteArray(size);
|
||||
|
||||
if (size != bytes.length)
|
||||
throw "Didn't read expected number of bytes";
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* setAndGetFaviconData()
|
||||
*
|
||||
* Calls setFaviconData() with the specified image data,
|
||||
* and then retrieves it with getFaviconData(). Returns
|
||||
* and array of bytes and mimetype.
|
||||
*/
|
||||
function setAndGetFaviconData(aFilename, aData, aMimeType) {
|
||||
var iconURI = uri("http://places.test/" + aFilename);
|
||||
|
||||
iconsvc.setFaviconData(iconURI,
|
||||
aData, aData.length, aMimeType,
|
||||
Number.MAX_VALUE);
|
||||
|
||||
var mimeTypeOutparam = {};
|
||||
|
||||
var outData = iconsvc.getFaviconData(iconURI,
|
||||
mimeTypeOutparam, {});
|
||||
|
||||
return [outData, mimeTypeOutparam.value];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* compareArrays
|
||||
*
|
||||
* Compares two arrays, and throws if there's a difference.
|
||||
*/
|
||||
function compareArrays(aArray1, aArray2) {
|
||||
do_check_eq(aArray1.length, aArray2.length);
|
||||
|
||||
for (var i = 0; i < aArray1.length; i++)
|
||||
if (aArray1[i] != aArray2[i])
|
||||
throw "arrays differ at index " + i;
|
||||
}
|
||||
|
||||
|
||||
var iconsvc;
|
||||
|
||||
function run_test() {
|
||||
try {
|
||||
|
||||
|
||||
/* ========== 0 ========== */
|
||||
var testnum = 0;
|
||||
var testdesc = "nsIFaviconService setup";
|
||||
|
||||
iconsvc = Cc["@mozilla.org/browser/favicon-service;1"].
|
||||
getService(Ci.nsIFaviconService);
|
||||
|
||||
if (!iconsvc)
|
||||
throw "Couldn't get nsIFaviconService service"
|
||||
|
||||
|
||||
/* ========== 1 ========== */
|
||||
testnum++;
|
||||
testdesc = "test storing a normal 16x16 icon";
|
||||
|
||||
// 16x16 png, 286 bytes.
|
||||
var iconName = "favicon-normal16.png";
|
||||
var inMimeType = "image/png";
|
||||
var iconFile = do_get_file(TESTDIR + iconName);
|
||||
|
||||
var inData = readFileData(iconFile);
|
||||
do_check_eq(inData.length, 286);
|
||||
|
||||
var [outData, outMimeType] = setAndGetFaviconData(iconName, inData, inMimeType);
|
||||
|
||||
// Ensure input and output are identical
|
||||
do_check_eq(inMimeType, outMimeType);
|
||||
compareArrays(inData, outData);
|
||||
|
||||
|
||||
/* ========== 2 ========== */
|
||||
testnum++;
|
||||
testdesc = "test storing a normal 32x32 icon";
|
||||
|
||||
// 32x32 png, 344 bytes.
|
||||
iconName = "favicon-normal32.png";
|
||||
inMimeType = "image/png";
|
||||
iconFile = do_get_file(TESTDIR + iconName);
|
||||
|
||||
inData = readFileData(iconFile);
|
||||
do_check_eq(inData.length, 344);
|
||||
|
||||
[outData, outMimeType] = setAndGetFaviconData(iconName, inData, inMimeType);
|
||||
|
||||
// Ensure input and output are identical
|
||||
do_check_eq(inMimeType, outMimeType);
|
||||
compareArrays(inData, outData);
|
||||
|
||||
|
||||
/* ========== 3 ========== */
|
||||
testnum++;
|
||||
testdesc = "test storing an oversize 16x16 icon ";
|
||||
|
||||
// in: 16x16 ico, 1406 bytes.
|
||||
// out: 16x16 png
|
||||
iconName = "favicon-big16.ico";
|
||||
inMimeType = "image/x-icon";
|
||||
iconFile = do_get_file(TESTDIR + iconName);
|
||||
|
||||
inData = readFileData(iconFile);
|
||||
do_check_eq(inData.length, 1406);
|
||||
|
||||
[outData, outMimeType] = setAndGetFaviconData(iconName, inData, inMimeType);
|
||||
|
||||
// Read in the expected output.
|
||||
var expectedFile = do_get_file(TESTDIR + "expected-" + iconName + ".png");
|
||||
var expectedData = readFileData(expectedFile);
|
||||
|
||||
// Compare thet expected data to the actual data.
|
||||
do_check_eq("image/png", outMimeType);
|
||||
compareArrays(expectedData, outData);
|
||||
|
||||
/* ========== 4 ========== */
|
||||
testnum++;
|
||||
testdesc = "test storing an oversize 4x4 icon ";
|
||||
|
||||
// in: 4x4 jpg, 4751 bytes.
|
||||
// out: 16x16 png
|
||||
iconName = "favicon-big4.jpg";
|
||||
inMimeType = "image/jpeg";
|
||||
iconFile = do_get_file(TESTDIR + iconName);
|
||||
|
||||
inData = readFileData(iconFile);
|
||||
do_check_eq(inData.length, 4751);
|
||||
|
||||
[outData, outMimeType] = setAndGetFaviconData(iconName, inData, inMimeType);
|
||||
|
||||
// Read in the expected output.
|
||||
var expectedFile = do_get_file(TESTDIR + "expected-" + iconName + ".png");
|
||||
var expectedData = readFileData(expectedFile);
|
||||
|
||||
// Compare thet expected data to the actual data.
|
||||
do_check_eq("image/png", outMimeType);
|
||||
compareArrays(expectedData, outData);
|
||||
|
||||
|
||||
/* ========== 5 ========== */
|
||||
testnum++;
|
||||
testdesc = "test storing an oversize 32x32 icon ";
|
||||
|
||||
// in: 32x32 jpg, 3494 bytes.
|
||||
// out: 16x16 png
|
||||
iconName = "favicon-big32.jpg";
|
||||
inMimeType = "image/jpeg";
|
||||
iconFile = do_get_file(TESTDIR + iconName);
|
||||
|
||||
inData = readFileData(iconFile);
|
||||
do_check_eq(inData.length, 3494);
|
||||
|
||||
[outData, outMimeType] = setAndGetFaviconData(iconName, inData, inMimeType);
|
||||
|
||||
// Read in the expected output.
|
||||
var expectedFile = do_get_file(TESTDIR + "expected-" + iconName + ".png");
|
||||
var expectedData = readFileData(expectedFile);
|
||||
|
||||
// Compare thet expected data to the actual data.
|
||||
do_check_eq("image/png", outMimeType);
|
||||
compareArrays(expectedData, outData);
|
||||
|
||||
/* ========== 6 ========== */
|
||||
testnum++;
|
||||
testdesc = "test storing an oversize 48x48 icon ";
|
||||
|
||||
// in: 48x48 ico, 56646 bytes.
|
||||
// (howstuffworks.com icon, contains 13 icons with sizes from 16x16 to
|
||||
// 48x48 in varying depths)
|
||||
// out: 16x16 png
|
||||
iconName = "favicon-big48.ico";
|
||||
inMimeType = "image/x-icon";
|
||||
iconFile = do_get_file(TESTDIR + iconName);
|
||||
|
||||
inData = readFileData(iconFile);
|
||||
do_check_eq(inData.length, 56646);
|
||||
|
||||
[outData, outMimeType] = setAndGetFaviconData(iconName, inData, inMimeType);
|
||||
|
||||
// Read in the expected output.
|
||||
var expectedFile = do_get_file(TESTDIR + "expected-" + iconName + ".png");
|
||||
var expectedData = readFileData(expectedFile);
|
||||
|
||||
// Compare thet expected data to the actual data.
|
||||
do_check_eq("image/png", outMimeType);
|
||||
compareArrays(expectedData, outData);
|
||||
|
||||
/* ========== 7 ========== */
|
||||
testnum++;
|
||||
testdesc = "test storing an oversize 64x64 icon ";
|
||||
|
||||
// in: 64x64 png, 10698 bytes.
|
||||
// out: 16x16 png
|
||||
iconName = "favicon-big64.png";
|
||||
inMimeType = "image/png";
|
||||
iconFile = do_get_file(TESTDIR + iconName);
|
||||
|
||||
inData = readFileData(iconFile);
|
||||
do_check_eq(inData.length, 10698);
|
||||
|
||||
[outData, outMimeType] = setAndGetFaviconData(iconName, inData, inMimeType);
|
||||
|
||||
// Read in the expected output.
|
||||
var expectedFile = do_get_file(TESTDIR + "expected-" + iconName + ".png");
|
||||
var expectedData = readFileData(expectedFile);
|
||||
|
||||
// Compare thet expected data to the actual data.
|
||||
do_check_eq("image/png", outMimeType);
|
||||
compareArrays(expectedData, outData);
|
||||
|
||||
/* ========== 8 ========== */
|
||||
testnum++;
|
||||
testdesc = "test scaling an oversize 160x3 icon ";
|
||||
|
||||
// in: 160x3 jpg, 5095 bytes.
|
||||
// out: 16x16 png
|
||||
iconName = "favicon-scale160x3.jpg";
|
||||
inMimeType = "image/jpeg";
|
||||
iconFile = do_get_file(TESTDIR + iconName);
|
||||
|
||||
inData = readFileData(iconFile);
|
||||
do_check_eq(inData.length, 5095);
|
||||
|
||||
[outData, outMimeType] = setAndGetFaviconData(iconName, inData, inMimeType);
|
||||
|
||||
// Read in the expected output.
|
||||
var expectedFile = do_get_file(TESTDIR + "expected-" + iconName + ".png");
|
||||
var expectedData = readFileData(expectedFile);
|
||||
|
||||
// Compare thet expected data to the actual data.
|
||||
do_check_eq("image/png", outMimeType);
|
||||
compareArrays(expectedData, outData);
|
||||
|
||||
/* ========== 9 ========== */
|
||||
testnum++;
|
||||
testdesc = "test scaling an oversize 3x160 icon ";
|
||||
|
||||
// in: 3x160 jpg, 5059 bytes.
|
||||
// out: 16x16 png
|
||||
iconName = "favicon-scale3x160.jpg";
|
||||
inMimeType = "image/jpeg";
|
||||
iconFile = do_get_file(TESTDIR + iconName);
|
||||
|
||||
inData = readFileData(iconFile);
|
||||
do_check_eq(inData.length, 5059);
|
||||
|
||||
[outData, outMimeType] = setAndGetFaviconData(iconName, inData, inMimeType);
|
||||
|
||||
// Read in the expected output.
|
||||
var expectedFile = do_get_file(TESTDIR + "expected-" + iconName + ".png");
|
||||
var expectedData = readFileData(expectedFile);
|
||||
|
||||
// Compare thet expected data to the actual data.
|
||||
do_check_eq("image/png", outMimeType);
|
||||
compareArrays(expectedData, outData);
|
||||
|
||||
|
||||
|
||||
/* ========== end ========== */
|
||||
|
||||
} catch (e) {
|
||||
throw "FAILED in test #" + testnum + " -- " + testdesc + ": " + e;
|
||||
}
|
||||
};
|