From 97a57a776986345178126b948c3d292827eb9906 Mon Sep 17 00:00:00 2001 From: "dolske@mozilla.com" Date: Sat, 12 Jan 2008 20:15:20 -0800 Subject: [PATCH] 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 --- modules/libpr0n/build/nsImageModule.cpp | 6 + modules/libpr0n/public/ImageErrors.h | 1 + modules/libpr0n/public/Makefile.in | 5 +- modules/libpr0n/public/imgITools.idl | 97 +++++ modules/libpr0n/src/Makefile.in | 3 +- modules/libpr0n/src/imgTools.cpp | 356 ++++++++++++++++++ modules/libpr0n/src/imgTools.h | 57 +++ modules/libpr0n/test/unit/image1.png | Bin 0 -> 10698 bytes modules/libpr0n/test/unit/image1png16x16.jpg | Bin 0 -> 733 bytes modules/libpr0n/test/unit/image1png64x64.jpg | Bin 0 -> 1593 bytes modules/libpr0n/test/unit/image2.jpg | Bin 0 -> 3494 bytes modules/libpr0n/test/unit/image2jpg16x16.png | Bin 0 -> 948 bytes modules/libpr0n/test/unit/image2jpg32x32.png | Bin 0 -> 3105 bytes modules/libpr0n/test/unit/image3.ico | Bin 0 -> 1406 bytes modules/libpr0n/test/unit/image3ico16x16.png | Bin 0 -> 330 bytes modules/libpr0n/test/unit/image3ico32x32.png | Bin 0 -> 2281 bytes modules/libpr0n/test/unit/test_imgtools.js | 294 +++++++++++++++ toolkit/components/places/src/Makefile.in | 2 + .../places/src/nsFaviconService.cpp | 77 +++- .../components/places/src/nsFaviconService.h | 3 + .../tests/unit/expected-favicon-big16.ico.png | Bin 0 -> 330 bytes .../tests/unit/expected-favicon-big32.jpg.png | Bin 0 -> 948 bytes .../tests/unit/expected-favicon-big4.jpg.png | Bin 0 -> 245 bytes .../tests/unit/expected-favicon-big48.ico.png | Bin 0 -> 656 bytes .../tests/unit/expected-favicon-big64.png.png | Bin 0 -> 866 bytes .../unit/expected-favicon-scale160x3.jpg.png | Bin 0 -> 131 bytes .../unit/expected-favicon-scale3x160.jpg.png | Bin 0 -> 124 bytes .../places/tests/unit/favicon-big16.ico | Bin 0 -> 1406 bytes .../places/tests/unit/favicon-big32.jpg | Bin 0 -> 3494 bytes .../places/tests/unit/favicon-big4.jpg | Bin 0 -> 4751 bytes .../places/tests/unit/favicon-big48.ico | Bin 0 -> 56646 bytes .../places/tests/unit/favicon-big64.png | Bin 0 -> 10698 bytes .../places/tests/unit/favicon-normal16.png | Bin 0 -> 286 bytes .../places/tests/unit/favicon-normal32.png | Bin 0 -> 344 bytes .../places/tests/unit/favicon-scale160x3.jpg | Bin 0 -> 5095 bytes .../places/tests/unit/favicon-scale3x160.jpg | Bin 0 -> 5059 bytes .../places/tests/unit/test_favicons.js | 324 ++++++++++++++++ 37 files changed, 1211 insertions(+), 14 deletions(-) create mode 100644 modules/libpr0n/public/imgITools.idl create mode 100644 modules/libpr0n/src/imgTools.cpp create mode 100644 modules/libpr0n/src/imgTools.h create mode 100644 modules/libpr0n/test/unit/image1.png create mode 100644 modules/libpr0n/test/unit/image1png16x16.jpg create mode 100644 modules/libpr0n/test/unit/image1png64x64.jpg create mode 100644 modules/libpr0n/test/unit/image2.jpg create mode 100644 modules/libpr0n/test/unit/image2jpg16x16.png create mode 100644 modules/libpr0n/test/unit/image2jpg32x32.png create mode 100644 modules/libpr0n/test/unit/image3.ico create mode 100644 modules/libpr0n/test/unit/image3ico16x16.png create mode 100644 modules/libpr0n/test/unit/image3ico32x32.png create mode 100644 modules/libpr0n/test/unit/test_imgtools.js create mode 100644 toolkit/components/places/tests/unit/expected-favicon-big16.ico.png create mode 100644 toolkit/components/places/tests/unit/expected-favicon-big32.jpg.png create mode 100644 toolkit/components/places/tests/unit/expected-favicon-big4.jpg.png create mode 100644 toolkit/components/places/tests/unit/expected-favicon-big48.ico.png create mode 100644 toolkit/components/places/tests/unit/expected-favicon-big64.png.png create mode 100644 toolkit/components/places/tests/unit/expected-favicon-scale160x3.jpg.png create mode 100644 toolkit/components/places/tests/unit/expected-favicon-scale3x160.jpg.png create mode 100644 toolkit/components/places/tests/unit/favicon-big16.ico create mode 100644 toolkit/components/places/tests/unit/favicon-big32.jpg create mode 100644 toolkit/components/places/tests/unit/favicon-big4.jpg create mode 100644 toolkit/components/places/tests/unit/favicon-big48.ico create mode 100644 toolkit/components/places/tests/unit/favicon-big64.png create mode 100644 toolkit/components/places/tests/unit/favicon-normal16.png create mode 100644 toolkit/components/places/tests/unit/favicon-normal32.png create mode 100644 toolkit/components/places/tests/unit/favicon-scale160x3.jpg create mode 100644 toolkit/components/places/tests/unit/favicon-scale3x160.jpg create mode 100644 toolkit/components/places/tests/unit/test_favicons.js diff --git a/modules/libpr0n/build/nsImageModule.cpp b/modules/libpr0n/build/nsImageModule.cpp index 0ed1e6b3cc1..d3cbbe38c5e 100644 --- a/modules/libpr0n/build/nsImageModule.cpp +++ b/modules/libpr0n/build/nsImageModule.cpp @@ -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 diff --git a/modules/libpr0n/public/ImageErrors.h b/modules/libpr0n/public/ImageErrors.h index 15a26b58112..ffbcab25535 100644 --- a/modules/libpr0n/public/ImageErrors.h +++ b/modules/libpr0n/public/ImageErrors.h @@ -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) diff --git a/modules/libpr0n/public/Makefile.in b/modules/libpr0n/public/Makefile.in index ef1af92dec5..a6be22852e1 100644 --- a/modules/libpr0n/public/Makefile.in +++ b/modules/libpr0n/public/Makefile.in @@ -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 diff --git a/modules/libpr0n/public/imgITools.idl b/modules/libpr0n/public/imgITools.idl new file mode 100644 index 00000000000..af91ac05dfe --- /dev/null +++ b/modules/libpr0n/public/imgITools.idl @@ -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 (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); +}; diff --git a/modules/libpr0n/src/Makefile.in b/modules/libpr0n/src/Makefile.in index 2f85dbff435..44cc97754db 100644 --- a/modules/libpr0n/src/Makefile.in +++ b/modules/libpr0n/src/Makefile.in @@ -66,7 +66,8 @@ CPPSRCS = \ imgContainer.cpp \ imgLoader.cpp \ imgRequest.cpp \ - imgRequestProxy.cpp + imgRequestProxy.cpp \ + imgTools.cpp include $(topsrcdir)/config/rules.mk diff --git a/modules/libpr0n/src/imgTools.cpp b/modules/libpr0n/src/imgTools.cpp new file mode 100644 index 00000000000..dd822a11d2b --- /dev/null +++ b/modules/libpr0n/src/imgTools.cpp @@ -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 (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 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 decoder = do_CreateInstance(decoderCID.get()); + if (!decoder) + return NS_IMAGELIB_ERROR_NO_DECODER; + + // Init the decoder, we use a small utility class here. + nsCOMPtr 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 encoder = do_CreateInstance(encoderCID.get()); + if (!encoder) + return NS_IMAGELIB_ERROR_NO_ENCODER; + + // Use frame 0 from the image container. + nsCOMPtr 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 img(do_GetInterface(frame)); + nsRefPtr 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 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); +} diff --git a/modules/libpr0n/src/imgTools.h b/modules/libpr0n/src/imgTools.h new file mode 100644 index 00000000000..24c7a674cd7 --- /dev/null +++ b/modules/libpr0n/src/imgTools.h @@ -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 (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(); +}; diff --git a/modules/libpr0n/test/unit/image1.png b/modules/libpr0n/test/unit/image1.png new file mode 100644 index 0000000000000000000000000000000000000000..2756cf0cb3ccf1a2f2371bceb8621550b34346b4 GIT binary patch literal 10698 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 NN3}&RDWm(-e*h_$%vS&a literal 0 HcmV?d00001 diff --git a/modules/libpr0n/test/unit/image2.jpg b/modules/libpr0n/test/unit/image2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b2131bf0c1c41b0b00821d7c42e74fe1f0aab779 GIT binary patch literal 3494 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 literal 0 HcmV?d00001 diff --git a/modules/libpr0n/test/unit/image3ico16x16.png b/modules/libpr0n/test/unit/image3ico16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..e9e520cb6cf6546bd1ec021ee99741681579889a GIT binary patch literal 330 zcmV-Q0k!^#P)mpC;QyPF?2!T+31>LG#o<8dudB62 zN{Nt&2wH3O-gzs$-|s{OA+bp;`&py`lYR%S>kTub?7|{(l_17hBvMMa`_BL~I|1yS zw-~Ui#HJwUOiGDG;zitA!^~KA0Q&BHfSBNA9tXhP$Luj4&4L4VWOCds`&g%g=k7Bg zB;1{x^P`gp1e|MICc*Uycx`8x8y?0^{XYQVJ{tPgKj_}-l c1ofZw1@I&!G(_A|qyPW_07*qoM6N<$f*u2q)Bpeg literal 0 HcmV?d00001 diff --git a/modules/libpr0n/test/unit/image3ico32x32.png b/modules/libpr0n/test/unit/image3ico32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..421b9ce30d13399ab7520119b5edb9f737eb2319 GIT binary patch literal 2281 zcmVJZd{V-ZZz&{HX7YTvt~1KQ?n+1`0t0gu(he_`jX8) z$w^Lf&%Mv@{-5VO=Q+Utv-x~Ji_hm%+S}XJ!oot;o{*sCMn$O(vsrc6?dsO8Th-3a zPW9~Bv+DHpw7Rgcpe!yfT7FId<=C-f{~K%1YMcgSXJcYGY%k#g zL5Yit^V)2-pe)NYo6Ss?B<_xg;2D4)0sI=^rvR@Ba8?Fi)usQn1P%&tR0z&UGA~5AEaZ(7rz9NRdw^;ed)vNh#bTqG;Oq??q_$m9WlH6$U=D5`0U5Ur69L0KWwI9>CZ2oiGUS zf&j0|;5#xnF2G9wuL1l5U`T)GV?B%)0G_qm`EpwuCw;!)fxUaZHk(bs?Ch*|{``4X zR8%l4C54&M(R8f@hh;D*gCPkxkh_#wcLCGblDejvaXr7+YbfNuc|>dwEs z0pt&6GhegYIgpzhD$U3UrlzL)zXRY*PUe=CE9n*B8#4H*41O)Z&j7xvkIw+|rtzV! zh!@~KgMmjPBRRHe73VD${(Z%Y<#k`^a05cHLYC=FPuIQ^f_9gS-HC}Dk-+yw*!i~- z_zA#qeSC5YfNKEv1KeydFyCb2=J$MpFA2e?WSPzB=^AEdXSLDMQP$VjQ_aa?NleUg>Ak8$EIFvxA+G2U zH;3Rs9U?a}k_D?)u__~jeI+G4Q(jKL)5#%O<^>^mMv{0y2sWF|VStMlFVf@j@Ru7l z&~fLTEH)VU#0@cjAK+nttpJ|`c=?7T`&ge})}OTk+y$@j z^fl)I9s<}F8Ohf8c(y4DJF2VsP;EI23ldqNSXoEqi);==FM;o14pZ zLeL{g%K%H2@Kb&MH-J+Bk4HqX!)Ro$(a7nD2>x!x3cg{n@Zw!}aUdy)hvE}?ATpNT z#AH5NzKykeUEHuMpZ8YX8>()s4z{$kgty_y$Ovm|Ynhdm#kjaQ<_f`1Nm>rUQYHLa zpZ^2ky8zD`jjS@8xyfv1ozcigEf#teh5NT{V^>ubpDrrr@pvbnjJ31Ynas*v`Fw2u z!#vp69qjDt^m;s=a3LBV9%flt8MCso=yW={W8FHo$Hed)z;|wu_5VcpfEqIzSzYV@`vZZ% zcS~`7eLXumI(Yo}arQm_I2-MDx&fZJMb<9?1R^3>Z8Y-!HEXzg%NG7>&z@l8?%m#o zh6c60y_wB9y`{p1_A+Pa&q!NhmqZG*P5G~wZXx`;Kam4 z$ba}SE3>n?6X6Er$_*-f4)6oLBl=CWfmOo9O?TfN+FMf-Jb3V+zpJb32REgP-ELQ# zo10ai&*vQ&7zplbX<J literal 0 HcmV?d00001 diff --git a/modules/libpr0n/test/unit/test_imgtools.js b/modules/libpr0n/test/unit/test_imgtools.js new file mode 100644 index 00000000000..24a34ffa51c --- /dev/null +++ b/modules/libpr0n/test/unit/test_imgtools.js @@ -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; +} +}; diff --git a/toolkit/components/places/src/Makefile.in b/toolkit/components/places/src/Makefile.in index 84f07115674..62e11379127 100644 --- a/toolkit/components/places/src/Makefile.in +++ b/toolkit/components/places/src/Makefile.in @@ -59,6 +59,8 @@ REQUIRES = xpcom \ morkreader \ pref \ necko \ + imglib2 \ + gfx \ intl \ layout \ locale \ diff --git a/toolkit/components/places/src/nsFaviconService.cpp b/toolkit/components/places/src/nsFaviconService.cpp index f5edfac38ab..91ee438c4b0 100644 --- a/toolkit/components/places/src/nsFaviconService.cpp +++ b/toolkit/components/places/src/nsFaviconService.cpp @@ -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(const_cast(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 imgtool = do_CreateInstance("@mozilla.org/image/tools;1"); + + nsCOMPtr stream; + rv = NS_NewByteInputStream(getter_AddRefs(stream), + reinterpret_cast(aData), aDataLen, + NS_ASSIGNMENT_DEPEND); + NS_ENSURE_SUCCESS(rv, rv); + + // decode image + nsCOMPtr container; + rv = imgtool->DecodeImageData(stream, aMimeType, getter_AddRefs(container)); + NS_ENSURE_SUCCESS(rv, rv); + + aNewMimeType.AssignLiteral("image/png"); + + // scale and recompress + nsCOMPtr 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)) diff --git a/toolkit/components/places/src/nsFaviconService.h b/toolkit/components/places/src/nsFaviconService.h index 5a15590d5c4..fd8970fb75a 100644 --- a/toolkit/components/places/src/nsFaviconService.h +++ b/toolkit/components/places/src/nsFaviconService.h @@ -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 diff --git a/toolkit/components/places/tests/unit/expected-favicon-big16.ico.png b/toolkit/components/places/tests/unit/expected-favicon-big16.ico.png new file mode 100644 index 0000000000000000000000000000000000000000..e9e520cb6cf6546bd1ec021ee99741681579889a GIT binary patch literal 330 zcmV-Q0k!^#P)mpC;QyPF?2!T+31>LG#o<8dudB62 zN{Nt&2wH3O-gzs$-|s{OA+bp;`&py`lYR%S>kTub?7|{(l_17hBvMMa`_BL~I|1yS zw-~Ui#HJwUOiGDG;zitA!^~KA0Q&BHfSBNA9tXhP$Luj4&4L4VWOCds`&g%g=k7Bg zB;1{x^P`gp1e|MICc*Uycx`8x8y?0^{XYQVJ{tPgKj_}-l c1ofZw1@I&!G(_A|qyPW_07*qoM6N<$f*u2q)Bpeg literal 0 HcmV?d00001 diff --git a/toolkit/components/places/tests/unit/expected-favicon-big32.jpg.png b/toolkit/components/places/tests/unit/expected-favicon-big32.jpg.png new file mode 100644 index 0000000000000000000000000000000000000000..c3a4aee616675d212178f70a97d8ce73fc1813e2 GIT binary patch literal 948 zcmV;l155mgP)V4UD_Ey98Hw^3d_z0SAGilu96u$N#q%XukhFy!r@;Ac`UYA}|4121ocoXC$|( zmhAFs@_()8{-eiC&%|c3PdfsLAWkBRQ*{45jN(!i!58%;Yg)+fe#rTTK4OcE_(y-i z$&(q34D~;~c{U(UFxXPX_2L57Mw}+>yBnmHYDp>8aoIdTX7gQ?W%Wd!%An+eFYOh+ zJm@TfsS!X#VCo6YXF|{?$jJLDiqg!(XfynY&%Hv@4HE~-YB^GE=94SsZ1eTOQ0l{@ z`kfdnk`bpy5ttg`_GgKlw&OMN9f5@(wXRrB}PI=goL6^_M`@S6LBJwy;(mKa9)FFP&zNU@5N^M z9@f9VhX(Zu#(R7)UEP9Em$DB_f*Tf<6zyhP)GJ>mHQ0}!_%j41T_7|i3-6Gxd11j; zX21R(r%&u>pg_WKgDY*CaD?B_rqB`PMvqEDQ@}hLcUWNxf0Ih(Ms#tT`6YQLAN%?7 z;+&N@*n3fs9l*bpOBt#6rqPgwaL-tSK`y07A)#04h~uZ66zb779) z%-mTn#O+!|%TLRBXz*aPKa@Xe3lSK5Lb2Zlnm>~8m+B2H3Og(cCk&xW2w&~NMwczD zneWc2?aOFSa-}cVnu-4H+}7>p@o*mk;xu=vbzFPfjyjnG?Lks3hn(nANa=`O#-E9+ z=}7RRGuD|_r4>WJEvCQjU21jbK%7KC1SThFxR^zr^E}EIzQT3sEQ}lMG07ci`_Pe& zFni2#*8HP(pjY!2nyZJI7#n(qX~v;AK2BS{nr}Saxn@6?qWP~8j2@*6^NSv@XkQ00000NkvXXu0mjfuo7Z% literal 0 HcmV?d00001 diff --git a/toolkit/components/places/tests/unit/expected-favicon-big48.ico.png b/toolkit/components/places/tests/unit/expected-favicon-big48.ico.png new file mode 100644 index 0000000000000000000000000000000000000000..b23e0569c48529f90c4e8c17e364bd4ce000a938 GIT binary patch literal 656 zcmV;B0&o3^P)PN1kNo5i!5A|(r{O}VBx|QrZc-KypZCE7GX)D?xoORB^J3yir}P>TRR&e zHo_j9xE8`%2(hr(!eWXmrm*;~NYpI;;1x6T-ZyXFds8U+l9YVW^Hy$(ZtO?8*6!)X z)}F3y^>l6LM3&O7yl#Y7Z{U7&(OLtbpEW@zz*%*vw%>j2x=>ha zi+&5_ zW}R?(ueTzNa3S9QILRkZNxUT#0w z?M-X&y>pQD`ikf*Vtg_F0Fc4-DQcwNv%8A%IJ!&oa6xG%Q05b zBDqcg$euF14Uckj4$$h4=^gfPRvetK4r-u?FJqG1g!n2Z=mbb#@ai7!noD#Vy$_P@ zOIGcklisHA0?BoP^o4LYB-m~dYzKth5H(Uv9;VryU&MJpxhbeo^dbEZniaV>IL`y@ z`n0#N($5+-RH&gsYt7_gf(!&Tnhun=JNKDN{;!Gci`n~mV2m*aFzH=t0K*F=y-&^L qaWY+lx%qozsyn}p?Tab-qW=TcD!-(KF{;!c|`6Zn^Zqz zTeYh$F5~^`czJW>y?l3RS;6OLH+4?(?x{Jt<`?)Z{3APt=SX|K6+>KE$A3cm)YU~I z<}_<{C)>W7ro3m0=KetrXqVYHcZrI=X-aptQCpbC;z<+Fr%UP`0T(Kj-!BHU7~3D@ z>%D${ZC**`(ILwE#@W*OJ=;UG_yWUuC??Cgp&}tM8KfaX0{Cr+% z`~+{y35r@yu)3-h3el}rW=ia|x{U13 zOdvin8!@;My_-X2nfw*f6YF>ws7FNHA|i4?CqGYZu%p#Fi1_S8e2L80DmeHvQL zaw3}z#OAHU&KnUC&mC*b5LrKxEcBQS4A_l~<|c7&Lkj0h9L!cZnW;7NORteDV>%vF z^zVp>?ygV7iDVxUx!P~HFpy|tFv-Snx|OqeOPMUU5N=5L(`1m%BBKAlLz+co%|@%~ sU}J(g{I=6FwpKBm;o%a6hfZ-vVlHTg9?(0WUZ}E8NHBZC%B>tbmzQ`*^Pwe{Ve*| XTAmy5Gq%108pq)2>gTe~DWM4fFY_m` literal 0 HcmV?d00001 diff --git a/toolkit/components/places/tests/unit/favicon-big16.ico b/toolkit/components/places/tests/unit/favicon-big16.ico new file mode 100644 index 0000000000000000000000000000000000000000..d44438903b751f4732f5365783eb0229b0501f9a GIT binary patch literal 1406 zcmZvcze^lJ6vy9y;f`fV)+?@Ze|W?Y>#3{^YAe`S+YM=~Z34NW`?g{0%{Gm#-zuW37pASug&9hEW%I5<8GkmQYMp$Ony#e@#BjuEiFmE-c}V zrd^0bcjyk?p*!@r%%gjB&%~p9bOs6N0X?7xgn+KhmAQuGZ0RljmPD3CR#cKborS@| zU}3N@BqSIt3>F3pgM}es!eC*rFjyEY3<(_u3xkEh!eC*riUx;;!$uC(Q~?ymczRl( zp~pvt#bNF+awK)Iq%v^Rap7Qbu%xoU;oxv^I5->}sZ?+{7#s`^hFCfWhl9bv5b#p^ zR6=~ZlX)s{tPWIod!kaQ@%AuzOg#o3CXcu0rYDKV+vAsduroh z@GyAl5Vwu0q^Cz=q>tN34FY}vwg5-KFKun)paubs5IK0TwB0NUumo5F5COyV3cwOr z7zhdo0TzBV@~|fXmJsWaSmN6dcL5Csg+XCZ7!(GDA-zs81Q-+sg(1K|8XEC1C=3dN z!a!;oIt&Vf!k_>s{()r5LM6zN!!dVoXv!U9oUF=cIXF0wqoX4^K0cO{lM^{VKbNz! zGr7FHl<9OTS65eZb8{oNx3_YCe=mzaDxXeI`5%v|Zu}3#fqZEe^Tw%4_Mf9?On&&F zi}beZwkZd!>yBC3w&vx-=SH%5uQV+Iv+k~DdEGL9UJhoPqdUoZxoMl$(3xtsdZBU89L3N8 literal 0 HcmV?d00001 diff --git a/toolkit/components/places/tests/unit/favicon-big32.jpg b/toolkit/components/places/tests/unit/favicon-big32.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b2131bf0c1c41b0b00821d7c42e74fe1f0aab779 GIT binary patch literal 3494 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 literal 0 HcmV?d00001 diff --git a/toolkit/components/places/tests/unit/favicon-big64.png b/toolkit/components/places/tests/unit/favicon-big64.png new file mode 100644 index 0000000000000000000000000000000000000000..2756cf0cb3ccf1a2f2371bceb8621550b34346b4 GIT binary patch literal 10698 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 literal 0 HcmV?d00001 diff --git a/toolkit/components/places/tests/unit/favicon-normal32.png b/toolkit/components/places/tests/unit/favicon-normal32.png new file mode 100644 index 0000000000000000000000000000000000000000..5535363c94df7314765551f65311ec6f98729d8e GIT binary patch literal 344 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 literal 0 HcmV?d00001 diff --git a/toolkit/components/places/tests/unit/favicon-scale3x160.jpg b/toolkit/components/places/tests/unit/favicon-scale3x160.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e8514966a024065d01d3fca5bb84dca79aee060c GIT binary patch literal 5059 zcmeHLS+E>c8SYu`Hn~A=5-_AL=48PHYHBn$R{@twg^)-nLnTBIe6h~-oI7)$=C{86 zo$o&Vz3>0vhd+AexgY=Jr$77o@e|LV`qi(0^TKa`_xnHm@uipl^2%TT_V<7M^Hs{L z7Bp;HWoG}D*8=jYH=B*-4CPg;-;7UVp*gi>*Yvu*M`q;e`mIa1&2G5jj=LUuYHr)^ zYhOICn?2h)fBW*Oi(aDCIJ5sOvD?oovof(NujhmLMh(qtEChRk7k1u#EEt~{zc&BM zd(%wCLJxBji(VR~naFh^WUPv|2-752VWA46G9i0($%M1?{pBGP>m$&R>&5;h?n)bwyq zBWu{{i0cXw%RHB2)yNpOWnaT0vQCjL*AX`gp=HI2l^fZU z<*5}E8%GW%1!|JnLa>vLIDl#)l?--!XhmDZX@tYB^6a*!W0e$W?MOxNY(wXm3X`Fo zmEpuhk%a$#BH5723vKJvL(izrwkNTy^5V>Gkr0DzPOEhU-J!l_rpVyAO3A_ol}dDX z&=H5E0Rnu`k?x`x$PAYvg(e?HMG(7UTWOZaOgWe`);L}mNwcmNdD^4Gaa~a35($U1 z6x{=s5xz^UfX{*&z!-=m;E!H7eEDBd0vqf#CJ6H-o`Kw}vof}OO(z@K0fN`}*f0|FtyTF&XvWH9I%iBL?;a~d=TvI}wmN5l+;sua0G z=bCTa`2m zQG|UaqhL(Mq39ToZ`lh#L}sD!z>U%_s0WZQNsxFFru@8D=}_vF%H-oKDsx@44CN=h zXEXr7{RN>}UItNTkqA< zssivE- zazCKKn9Q29gIA(;TQDbV^aORD1-ViXFKe{k0Nt((%pJT0S#`w2DAB|oNYJ85u*LLr z0Em0pf;~bXNQ~Cg(>0|;JPWm5;Oq%@>97e{`wi0yE1zaedOX;LVggB3+)jNa)ETnl zmy%(oW3&fUP%fq<3L*mTtp@otux;j8sFes!S4Y^CNjB6wp*vDRvq;gcY&g#84k`|v z=qS;4Sqq*ZlnU;NSF0O#C$3oE2f-UF95L8!|7dx4xa8G_R%sSwKYTC?pYA2WVaKiy z{$&6>Nz>Z)yC1E%c8qyVVRaAFjMi>P$oxLw)v#nI)(B=?ORIJnkzr`!97;@E5+*oN zSmVkuaB}2jh7^s_2}PlW8#8UsxA?ufe8D@*FZ^D8md}=t+4t(N294L>tNH&6{_o$b zU)%G<$$P)@^6CfA`N*H2+;j5ICtm&2TaN$o*q$?849