mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 110894 - Use favicons on webpage shortcuts in Windows. r=bbondy
This commit is contained in:
parent
86fe2dfee8
commit
18ade5e188
@ -24,6 +24,8 @@
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/LazyIdleThread.h"
|
||||
|
||||
#include "WinUtils.h"
|
||||
|
||||
// The amount of time, in milliseconds, that our IO thread will stay alive after the last event it processes.
|
||||
#define DEFAULT_THREAD_TIMEOUT_MS 30000
|
||||
|
||||
@ -41,10 +43,6 @@ bool JumpListBuilder::sBuildingList = false;
|
||||
const char kPrefTaskbarEnabled[] = "browser.taskbar.lists.enabled";
|
||||
|
||||
NS_IMPL_ISUPPORTS2(JumpListBuilder, nsIJumpListBuilder, nsIObserver)
|
||||
NS_IMPL_ISUPPORTS1(AsyncFaviconDataReady, nsIFaviconDataCallback)
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(AsyncWriteIconToDisk, nsIRunnable)
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(AsyncDeleteIconFromDisk, nsIRunnable)
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(AsyncDeleteAllFaviconsFromDisk, nsIRunnable)
|
||||
|
||||
JumpListBuilder::JumpListBuilder() :
|
||||
mMaxItems(0),
|
||||
@ -182,7 +180,7 @@ nsresult JumpListBuilder::RemoveIconCacheForItems(nsIMutableArray *items)
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIRunnable> event
|
||||
= new AsyncDeleteIconFromDisk(NS_ConvertUTF8toUTF16(spec));
|
||||
= new mozilla::widget::AsyncDeleteIconFromDisk(NS_ConvertUTF8toUTF16(spec));
|
||||
mIOThread->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
|
||||
// The shortcut was generated from an IShellLinkW so IShellLinkW can
|
||||
@ -207,7 +205,8 @@ nsresult JumpListBuilder::RemoveIconCacheForAllItems()
|
||||
nsresult rv = NS_GetSpecialDirectory("ProfLDS",
|
||||
getter_AddRefs(jumpListCacheDir));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = jumpListCacheDir->AppendNative(nsDependentCString(JumpListItem::kJumpListCacheDir));
|
||||
rv = jumpListCacheDir->AppendNative(nsDependentCString(
|
||||
mozilla::widget::FaviconHelper::kJumpListCacheDir));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsISimpleEnumerator> entries;
|
||||
rv = jumpListCacheDir->GetDirectoryEntries(getter_AddRefs(entries));
|
||||
@ -509,234 +508,14 @@ NS_IMETHODIMP JumpListBuilder::Observe(nsISupports* aSubject,
|
||||
bool enabled = Preferences::GetBool(kPrefTaskbarEnabled, true);
|
||||
if (!enabled) {
|
||||
|
||||
nsCOMPtr<nsIRunnable> event = new AsyncDeleteAllFaviconsFromDisk();
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
new mozilla::widget::AsyncDeleteAllFaviconsFromDisk();
|
||||
mIOThread->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
AsyncFaviconDataReady::AsyncFaviconDataReady(nsIURI *aNewURI,
|
||||
nsCOMPtr<nsIThread> &aIOThread)
|
||||
: mNewURI(aNewURI),
|
||||
mIOThread(aIOThread)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AsyncFaviconDataReady::OnComplete(nsIURI *aFaviconURI,
|
||||
PRUint32 aDataLen,
|
||||
const PRUint8 *aData,
|
||||
const nsACString &aMimeType)
|
||||
{
|
||||
if (!aDataLen || !aData) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> icoFile;
|
||||
nsresult rv = JumpListShortcut::GetOutputIconPath(mNewURI, icoFile);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsAutoString path;
|
||||
rv = icoFile->GetPath(path);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Allocate a new buffer that we own and can use out of line in
|
||||
// another thread. Copy the favicon raw data into it.
|
||||
const fallible_t fallible = fallible_t();
|
||||
PRUint8 *data = new (fallible) PRUint8[aDataLen];
|
||||
if (!data) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
memcpy(data, aData, aDataLen);
|
||||
|
||||
//AsyncWriteIconToDisk takes ownership of the heap allocated buffer.
|
||||
nsCOMPtr<nsIRunnable> event = new AsyncWriteIconToDisk(path, aMimeType,
|
||||
data,
|
||||
aDataLen);
|
||||
mIOThread->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Warning: AsyncWriteIconToDisk assumes ownership of the aData buffer passed in
|
||||
AsyncWriteIconToDisk::AsyncWriteIconToDisk(const nsAString &aIconPath,
|
||||
const nsACString &aMimeTypeOfInputData,
|
||||
PRUint8 *aBuffer,
|
||||
PRUint32 aBufferLength)
|
||||
: mIconPath(aIconPath),
|
||||
mMimeTypeOfInputData(aMimeTypeOfInputData),
|
||||
mBuffer(aBuffer),
|
||||
mBufferLength(aBufferLength)
|
||||
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP AsyncWriteIconToDisk::Run()
|
||||
{
|
||||
NS_PRECONDITION(!NS_IsMainThread(), "Should not be called on the main thread.");
|
||||
|
||||
// Convert the obtained favicon data to an input stream
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream),
|
||||
reinterpret_cast<const char*>(mBuffer.get()),
|
||||
mBufferLength,
|
||||
NS_ASSIGNMENT_DEPEND);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Decode the image from the format it was returned to us in (probably PNG)
|
||||
nsCOMPtr<imgIContainer> container;
|
||||
nsCOMPtr<imgITools> imgtool = do_CreateInstance("@mozilla.org/image/tools;1");
|
||||
rv = imgtool->DecodeImageData(stream, mMimeTypeOfInputData,
|
||||
getter_AddRefs(container));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Get the recommended icon width and height, or if failure to obtain
|
||||
// these settings, fall back to 16x16 ICOs. These values can be different
|
||||
// if the user has a different DPI setting other than 100%.
|
||||
// Windows would scale the 16x16 icon themselves, but it's better
|
||||
// we let our ICO encoder do it.
|
||||
PRInt32 systemIconWidth = GetSystemMetrics(SM_CXSMICON);
|
||||
PRInt32 systemIconHeight = GetSystemMetrics(SM_CYSMICON);
|
||||
if (systemIconWidth == 0 || systemIconHeight == 0) {
|
||||
systemIconWidth = 16;
|
||||
systemIconHeight = 16;
|
||||
}
|
||||
// Scale the image to the needed size and in ICO format
|
||||
mMimeTypeOfInputData.AssignLiteral("image/vnd.microsoft.icon");
|
||||
nsCOMPtr<nsIInputStream> iconStream;
|
||||
rv = imgtool->EncodeScaledImage(container, mMimeTypeOfInputData,
|
||||
systemIconWidth,
|
||||
systemIconHeight,
|
||||
EmptyString(),
|
||||
getter_AddRefs(iconStream));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIFile> icoFile
|
||||
= do_CreateInstance("@mozilla.org/file/local;1");
|
||||
NS_ENSURE_TRUE(icoFile, NS_ERROR_FAILURE);
|
||||
rv = icoFile->InitWithPath(mIconPath);
|
||||
|
||||
// Setup the output stream for the ICO file on disk
|
||||
nsCOMPtr<nsIOutputStream> outputStream;
|
||||
rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), icoFile);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Obtain the ICO buffer size from the re-encoded ICO stream
|
||||
PRUint32 bufSize;
|
||||
rv = iconStream->Available(&bufSize);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Setup a buffered output stream from the stream object
|
||||
// so that we can simply use WriteFrom with the stream object
|
||||
nsCOMPtr<nsIOutputStream> bufferedOutputStream;
|
||||
rv = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream),
|
||||
outputStream, bufSize);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Write out the icon stream to disk and make sure we wrote everything
|
||||
PRUint32 wrote;
|
||||
rv = bufferedOutputStream->WriteFrom(iconStream, bufSize, &wrote);
|
||||
NS_ASSERTION(bufSize == wrote, "Icon wrote size should be equal to requested write size");
|
||||
|
||||
// Cleanup
|
||||
bufferedOutputStream->Close();
|
||||
outputStream->Close();
|
||||
return rv;
|
||||
}
|
||||
|
||||
AsyncWriteIconToDisk::~AsyncWriteIconToDisk()
|
||||
{
|
||||
}
|
||||
|
||||
AsyncDeleteIconFromDisk::AsyncDeleteIconFromDisk(const nsAString &aIconPath)
|
||||
: mIconPath(aIconPath)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP AsyncDeleteIconFromDisk::Run()
|
||||
{
|
||||
// Construct the parent path of the passed in path
|
||||
nsCOMPtr<nsIFile> icoFile = do_CreateInstance("@mozilla.org/file/local;1");
|
||||
NS_ENSURE_TRUE(icoFile, NS_ERROR_FAILURE);
|
||||
nsresult rv = icoFile->InitWithPath(mIconPath);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Check if the cached ICO file exists
|
||||
bool exists;
|
||||
rv = icoFile->Exists(&exists);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Check that we aren't deleting some arbitrary file that is not an icon
|
||||
if (StringTail(mIconPath, 4).LowerCaseEqualsASCII(".ico")) {
|
||||
// Check if the cached ICO file exists
|
||||
bool exists;
|
||||
if (NS_FAILED(icoFile->Exists(&exists)) || !exists)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// We found an ICO file that exists, so we should remove it
|
||||
icoFile->Remove(false);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
AsyncDeleteIconFromDisk::~AsyncDeleteIconFromDisk()
|
||||
{
|
||||
}
|
||||
|
||||
AsyncDeleteAllFaviconsFromDisk::AsyncDeleteAllFaviconsFromDisk()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP AsyncDeleteAllFaviconsFromDisk::Run()
|
||||
{
|
||||
// Construct the path of our jump list cache
|
||||
nsCOMPtr<nsIFile> jumpListCacheDir;
|
||||
nsresult rv = NS_GetSpecialDirectory("ProfLDS",
|
||||
getter_AddRefs(jumpListCacheDir));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = jumpListCacheDir->AppendNative(nsDependentCString(JumpListItem::kJumpListCacheDir));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsISimpleEnumerator> entries;
|
||||
rv = jumpListCacheDir->GetDirectoryEntries(getter_AddRefs(entries));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Loop through each directory entry and remove all ICO files found
|
||||
do {
|
||||
bool hasMore = false;
|
||||
if (NS_FAILED(entries->HasMoreElements(&hasMore)) || !hasMore)
|
||||
break;
|
||||
|
||||
nsCOMPtr<nsISupports> supp;
|
||||
if (NS_FAILED(entries->GetNext(getter_AddRefs(supp))))
|
||||
break;
|
||||
|
||||
nsCOMPtr<nsIFile> currFile(do_QueryInterface(supp));
|
||||
nsAutoString path;
|
||||
if (NS_FAILED(currFile->GetPath(path)))
|
||||
continue;
|
||||
|
||||
PRInt32 len = path.Length();
|
||||
if (StringTail(path, 4).LowerCaseEqualsASCII(".ico")) {
|
||||
// Check if the cached ICO file exists
|
||||
bool exists;
|
||||
if (NS_FAILED(currFile->Exists(&exists)) || !exists)
|
||||
continue;
|
||||
|
||||
// We found an ICO file that exists, so we should remove it
|
||||
currFile->Remove(false);
|
||||
}
|
||||
} while(true);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
AsyncDeleteAllFaviconsFromDisk::~AsyncDeleteAllFaviconsFromDisk()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -55,65 +55,6 @@ private:
|
||||
friend class WinTaskbar;
|
||||
};
|
||||
|
||||
|
||||
class AsyncFaviconDataReady MOZ_FINAL : public nsIFaviconDataCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIFAVICONDATACALLBACK
|
||||
|
||||
AsyncFaviconDataReady(nsIURI *aNewURI, nsCOMPtr<nsIThread> &aIOThread);
|
||||
private:
|
||||
nsCOMPtr<nsIURI> mNewURI;
|
||||
nsCOMPtr<nsIThread> mIOThread;
|
||||
};
|
||||
|
||||
/**
|
||||
* Asynchronously tries add the list to the build
|
||||
*/
|
||||
class AsyncWriteIconToDisk : public nsIRunnable
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
// Warning: AsyncWriteIconToDisk assumes ownership of the aData buffer passed in
|
||||
AsyncWriteIconToDisk(const nsAString &aIconPath,
|
||||
const nsACString &aMimeTypeOfInputData,
|
||||
PRUint8 *aData,
|
||||
PRUint32 aDataLen);
|
||||
virtual ~AsyncWriteIconToDisk();
|
||||
|
||||
private:
|
||||
nsAutoString mIconPath;
|
||||
nsCAutoString mMimeTypeOfInputData;
|
||||
nsAutoArrayPtr<PRUint8> mBuffer;
|
||||
PRUint32 mBufferLength;
|
||||
};
|
||||
|
||||
class AsyncDeleteIconFromDisk : public nsIRunnable
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
AsyncDeleteIconFromDisk(const nsAString &aIconPath);
|
||||
virtual ~AsyncDeleteIconFromDisk();
|
||||
|
||||
private:
|
||||
nsAutoString mIconPath;
|
||||
};
|
||||
|
||||
class AsyncDeleteAllFaviconsFromDisk : public nsIRunnable
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
AsyncDeleteAllFaviconsFromDisk();
|
||||
virtual ~AsyncDeleteAllFaviconsFromDisk();
|
||||
};
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -23,8 +23,6 @@
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
const char JumpListItem::kJumpListCacheDir[] = "jumpListCache";
|
||||
|
||||
// ISUPPORTS Impl's
|
||||
NS_IMPL_ISUPPORTS1(JumpListItem,
|
||||
nsIJumpListItem)
|
||||
@ -122,7 +120,7 @@ NS_IMETHODIMP JumpListLink::GetUriHash(nsACString& aUriHash)
|
||||
if (!mURI)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
return JumpListItem::HashURI(mCryptoHash, mURI, aUriHash);
|
||||
return mozilla::widget::FaviconHelper::HashURI(mCryptoHash, mURI, aUriHash);
|
||||
}
|
||||
|
||||
/* boolean compareHash(in nsIURI uri); */
|
||||
@ -139,9 +137,9 @@ NS_IMETHODIMP JumpListLink::CompareHash(nsIURI *aUri, bool *aResult)
|
||||
|
||||
nsCAutoString hash1, hash2;
|
||||
|
||||
rv = JumpListItem::HashURI(mCryptoHash, mURI, hash1);
|
||||
rv = mozilla::widget::FaviconHelper::HashURI(mCryptoHash, mURI, hash1);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = JumpListItem::HashURI(mCryptoHash, aUri, hash2);
|
||||
rv = mozilla::widget::FaviconHelper::HashURI(mCryptoHash, aUri, hash2);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
*aResult = hash1.Equals(hash2);
|
||||
@ -321,135 +319,6 @@ nsresult JumpListSeparator::GetSeparator(nsRefPtr<IShellLinkW>& aShellLink)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Obtains the jump list 'ICO cache timeout in seconds' pref
|
||||
static PRInt32 GetICOCacheSecondsTimeout() {
|
||||
|
||||
// Only obtain the setting at most once from the pref service.
|
||||
// In the rare case that 2 threads call this at the same
|
||||
// time it is no harm and we will simply obtain the pref twice.
|
||||
// None of the taskbar list prefs are currently updated via a
|
||||
// pref observer so I think this should suffice.
|
||||
const PRInt32 kSecondsPerDay = 86400;
|
||||
static bool alreadyObtained = false;
|
||||
static PRInt32 icoReCacheSecondsTimeout = kSecondsPerDay;
|
||||
if (alreadyObtained) {
|
||||
return icoReCacheSecondsTimeout;
|
||||
}
|
||||
|
||||
// Obtain the pref
|
||||
const char PREF_ICOTIMEOUT[] = "browser.taskbar.lists.icoTimeoutInSeconds";
|
||||
icoReCacheSecondsTimeout = Preferences::GetInt(PREF_ICOTIMEOUT,
|
||||
kSecondsPerDay);
|
||||
alreadyObtained = true;
|
||||
return icoReCacheSecondsTimeout;
|
||||
}
|
||||
|
||||
// (static) If the data is available, will return the path on disk where
|
||||
// the favicon for page aFaviconPageURI is stored. If the favicon does not
|
||||
// exist, or its cache is expired, this method will kick off an async request
|
||||
// for the icon so that next time the method is called it will be available.
|
||||
nsresult JumpListShortcut::ObtainCachedIconFile(nsCOMPtr<nsIURI> aFaviconPageURI,
|
||||
nsString &aICOFilePath,
|
||||
nsCOMPtr<nsIThread> &aIOThread)
|
||||
{
|
||||
// Obtain the ICO file path
|
||||
nsCOMPtr<nsIFile> icoFile;
|
||||
nsresult rv = GetOutputIconPath(aFaviconPageURI, icoFile);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Check if the cached ICO file already exists
|
||||
bool exists;
|
||||
rv = icoFile->Exists(&exists);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (exists) {
|
||||
|
||||
// Obtain the file's last modification date in seconds
|
||||
PRInt64 fileModTime = LL_ZERO;
|
||||
rv = icoFile->GetLastModifiedTime(&fileModTime);
|
||||
fileModTime /= PR_MSEC_PER_SEC;
|
||||
PRInt32 icoReCacheSecondsTimeout = GetICOCacheSecondsTimeout();
|
||||
PRInt64 nowTime = PR_Now() / PRInt64(PR_USEC_PER_SEC);
|
||||
|
||||
// If the last mod call failed or the icon is old then re-cache it
|
||||
// This check is in case the favicon of a page changes
|
||||
// the next time we try to build the jump list, the data will be available.
|
||||
if (NS_FAILED(rv) ||
|
||||
(nowTime - fileModTime) > icoReCacheSecondsTimeout) {
|
||||
CacheIconFileFromFaviconURIAsync(aFaviconPageURI, icoFile, aIOThread);
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
} else {
|
||||
|
||||
// The file does not exist yet, obtain it async from the favicon service so that
|
||||
// the next time we try to build the jump list it'll be available.
|
||||
CacheIconFileFromFaviconURIAsync(aFaviconPageURI, icoFile, aIOThread);
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
// The icoFile is filled with a path that exists, get its path
|
||||
rv = icoFile->GetPath(aICOFilePath);
|
||||
return rv;
|
||||
}
|
||||
|
||||
// (static) Obtains the ICO file for the favicon at page aFaviconPageURI
|
||||
// If successful, the file path on disk is in the format:
|
||||
// <ProfLDS>\jumpListCache\<hash(aFaviconPageURI)>.ico
|
||||
nsresult JumpListShortcut::GetOutputIconPath(nsCOMPtr<nsIURI> aFaviconPageURI,
|
||||
nsCOMPtr<nsIFile> &aICOFile)
|
||||
{
|
||||
// Hash the input URI and replace any / with _
|
||||
nsCAutoString inputURIHash;
|
||||
nsCOMPtr<nsICryptoHash> cryptoHash;
|
||||
nsresult rv = JumpListItem::HashURI(cryptoHash, aFaviconPageURI,
|
||||
inputURIHash);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
char* cur = inputURIHash.BeginWriting();
|
||||
char* end = inputURIHash.EndWriting();
|
||||
for (; cur < end; ++cur) {
|
||||
if ('/' == *cur) {
|
||||
*cur = '_';
|
||||
}
|
||||
}
|
||||
|
||||
// Obtain the local profile directory and construct the output icon file path
|
||||
rv = NS_GetSpecialDirectory("ProfLDS", getter_AddRefs(aICOFile));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = aICOFile->AppendNative(nsDependentCString(JumpListItem::kJumpListCacheDir));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Try to create the directory if it's not there yet
|
||||
rv = aICOFile->Create(nsIFile::DIRECTORY_TYPE, 0777);
|
||||
if (NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Append the icon extension
|
||||
inputURIHash.Append(".ico");
|
||||
rv = aICOFile->AppendNative(inputURIHash);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
// (static) Asynchronously creates a cached ICO file on disk for the favicon of
|
||||
// page aFaviconPageURI and stores it to disk at the path of aICOFile.
|
||||
nsresult
|
||||
JumpListShortcut::CacheIconFileFromFaviconURIAsync(nsCOMPtr<nsIURI> aFaviconPageURI,
|
||||
nsCOMPtr<nsIFile> aICOFile,
|
||||
nsCOMPtr<nsIThread> &aIOThread)
|
||||
{
|
||||
// Obtain the favicon service and get the favicon for the specified page
|
||||
nsCOMPtr<mozIAsyncFavicons> favIconSvc(
|
||||
do_GetService("@mozilla.org/browser/favicon-service;1"));
|
||||
NS_ENSURE_TRUE(favIconSvc, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsIFaviconDataCallback> callback =
|
||||
new AsyncFaviconDataReady(aFaviconPageURI, aIOThread);
|
||||
|
||||
favIconSvc->GetFaviconDataForPage(aFaviconPageURI, callback);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// (static) Creates a ShellLink that encapsulate a shortcut to local apps.
|
||||
nsresult JumpListShortcut::GetShellLink(nsCOMPtr<nsIJumpListItem>& item,
|
||||
nsRefPtr<IShellLinkW>& aShellLink,
|
||||
@ -544,7 +413,10 @@ nsresult JumpListShortcut::GetShellLink(nsCOMPtr<nsIJumpListItem>& item,
|
||||
|
||||
if (useUriIcon) {
|
||||
nsString icoFilePath;
|
||||
rv = ObtainCachedIconFile(iconUri, icoFilePath, aIOThread);
|
||||
rv = mozilla::widget::FaviconHelper::ObtainCachedIconFile(iconUri,
|
||||
icoFilePath,
|
||||
aIOThread,
|
||||
false);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// Always use the first icon in the ICO file
|
||||
// our encoded icon only has 1 resource
|
||||
@ -577,7 +449,7 @@ static nsresult IsPathInOurIconCache(nsCOMPtr<nsIJumpListShortcut>& aShortcut,
|
||||
nsCOMPtr<nsIFile> jumpListCache;
|
||||
nsresult rv = NS_GetSpecialDirectory("ProfLDS", getter_AddRefs(jumpListCache));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = jumpListCache->AppendNative(nsDependentCString(JumpListItem::kJumpListCacheDir));
|
||||
rv = jumpListCache->AppendNative(nsDependentCString(FaviconHelper::kJumpListCacheDir));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsAutoString jumpListCachePath;
|
||||
rv = jumpListCache->GetPath(jumpListCachePath);
|
||||
@ -772,33 +644,6 @@ bool JumpListShortcut::ExecutableExists(nsCOMPtr<nsILocalHandlerApp>& handlerApp
|
||||
return false;
|
||||
}
|
||||
|
||||
// (static) Helper method which will hash a URI
|
||||
nsresult JumpListItem::HashURI(nsCOMPtr<nsICryptoHash> &aCryptoHash,
|
||||
nsIURI *aUri, nsACString& aUriHash)
|
||||
{
|
||||
if (!aUri)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
nsCAutoString spec;
|
||||
nsresult rv = aUri->GetSpec(spec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!aCryptoHash) {
|
||||
aCryptoHash = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
rv = aCryptoHash->Init(nsICryptoHash::MD5);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = aCryptoHash->Update(reinterpret_cast<const PRUint8*>(spec.BeginReading()),
|
||||
spec.Length());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = aCryptoHash->Finish(true, aUriHash);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -48,8 +48,6 @@ protected:
|
||||
short Type() { return mItemType; }
|
||||
short mItemType;
|
||||
|
||||
static nsresult HashURI(nsCOMPtr<nsICryptoHash> &aCryptoHash,
|
||||
nsIURI *aUri, nsACString& aUriHash);
|
||||
};
|
||||
|
||||
class JumpListSeparator : public JumpListItem, public nsIJumpListSeparator
|
||||
|
@ -11,9 +11,33 @@
|
||||
#include "nsIDOMMouseEvent.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsDirectoryServiceUtils.h"
|
||||
#include "imgIContainer.h"
|
||||
#include "imgITools.h"
|
||||
#include "nsStringStream.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "mozIAsyncFavicons.h"
|
||||
|
||||
#include "nsIIconURI.h"
|
||||
#include "nsIDownloader.h"
|
||||
#include "nsINetUtil.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIObserver.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
NS_IMPL_ISUPPORTS1(myDownloadObserver, nsIDownloadObserver)
|
||||
NS_IMPL_ISUPPORTS1(AsyncFaviconDataReady, nsIFaviconDataCallback)
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(AsyncWriteIconToDisk, nsIRunnable)
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(AsyncDeleteIconFromDisk, nsIRunnable)
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(AsyncDeleteAllFaviconsFromDisk, nsIRunnable)
|
||||
|
||||
|
||||
const char FaviconHelper::kJumpListCacheDir[] = "jumpListCache";
|
||||
const char FaviconHelper::kShortcutCacheDir[] = "shortcutCache";
|
||||
|
||||
// SHCreateItemFromParsingName is only available on vista and up.
|
||||
WinUtils::SHCreateItemFromParsingNamePtr WinUtils::sCreateItemFromParsingName = nsnull;
|
||||
|
||||
@ -367,6 +391,471 @@ WinUtils::SHCreateItemFromParsingName(PCWSTR pszPath, IBindCtx *pbc,
|
||||
return sCreateItemFromParsingName(pszPath, pbc, riid, ppv);
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
/* Constructs as AsyncFaviconDataReady Object
|
||||
/* @param aIOThread : the thread which performs the action
|
||||
/* @param aURLShortcut : Differentiates between (false)Jumplistcache and (true)Shortcutcache
|
||||
/************************************************************************/
|
||||
|
||||
AsyncFaviconDataReady::AsyncFaviconDataReady(nsIURI *aNewURI,
|
||||
nsCOMPtr<nsIThread> &aIOThread,
|
||||
const bool aURLShortcut):
|
||||
mNewURI(aNewURI),
|
||||
mIOThread(aIOThread),
|
||||
mURLShortcut(aURLShortcut)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
myDownloadObserver::OnDownloadComplete(nsIDownloader *downloader,
|
||||
nsIRequest *request,
|
||||
nsISupports *ctxt,
|
||||
nsresult status,
|
||||
nsIFile *result)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult AsyncFaviconDataReady::OnFaviconDataNotAvailable(void)
|
||||
{
|
||||
if (!mURLShortcut) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> icoFile;
|
||||
nsresult rv = FaviconHelper::GetOutputIconPath(mNewURI, icoFile, mURLShortcut);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIURI> mozIconURI;
|
||||
rv = NS_NewURI(getter_AddRefs(mozIconURI), "moz-icon://.html?size=32");
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
rv = NS_NewChannel(getter_AddRefs(channel), mozIconURI);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<myDownloadObserver> downloadObserver = new myDownloadObserver;
|
||||
nsCOMPtr<nsIStreamListener> listener;
|
||||
rv = NS_NewDownloader(getter_AddRefs(listener), downloadObserver, icoFile);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
channel->AsyncOpen(listener, NULL);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
AsyncFaviconDataReady::OnComplete(nsIURI *aFaviconURI,
|
||||
PRUint32 aDataLen,
|
||||
const PRUint8 *aData,
|
||||
const nsACString &aMimeType)
|
||||
{
|
||||
if (!aDataLen || !aData) {
|
||||
if (mURLShortcut) {
|
||||
OnFaviconDataNotAvailable();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> icoFile;
|
||||
nsresult rv = FaviconHelper::GetOutputIconPath(mNewURI, icoFile, mURLShortcut);
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsAutoString path;
|
||||
rv = icoFile->GetPath(path);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Allocate a new buffer that we own and can use out of line in
|
||||
// another thread. Copy the favicon raw data into it.
|
||||
const fallible_t fallible = fallible_t();
|
||||
PRUint8 *data = new (fallible) PRUint8[aDataLen];
|
||||
if (!data) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
memcpy(data, aData, aDataLen);
|
||||
|
||||
//AsyncWriteIconToDisk takes ownership of the heap allocated buffer.
|
||||
nsCOMPtr<nsIRunnable> event = new AsyncWriteIconToDisk(path, aMimeType,
|
||||
data,
|
||||
aDataLen,
|
||||
mURLShortcut);
|
||||
mIOThread->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Warning: AsyncWriteIconToDisk assumes ownership of the aData buffer passed in
|
||||
AsyncWriteIconToDisk::AsyncWriteIconToDisk(const nsAString &aIconPath,
|
||||
const nsACString &aMimeTypeOfInputData,
|
||||
PRUint8 *aBuffer,
|
||||
PRUint32 aBufferLength,
|
||||
const bool aURLShortcut):
|
||||
mIconPath(aIconPath),
|
||||
mMimeTypeOfInputData(aMimeTypeOfInputData),
|
||||
mBuffer(aBuffer),
|
||||
mBufferLength(aBufferLength),
|
||||
mURLShortcut(aURLShortcut)
|
||||
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP AsyncWriteIconToDisk::Run()
|
||||
{
|
||||
NS_PRECONDITION(!NS_IsMainThread(), "Should not be called on the main thread.");
|
||||
|
||||
// Convert the obtained favicon data to an input stream
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
nsresult rv =
|
||||
NS_NewByteInputStream(getter_AddRefs(stream),
|
||||
reinterpret_cast<const char*>(mBuffer.get()),
|
||||
mBufferLength,
|
||||
NS_ASSIGNMENT_DEPEND);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Decode the image from the format it was returned to us in (probably PNG)
|
||||
nsCOMPtr<imgIContainer> container;
|
||||
nsCOMPtr<imgITools> imgtool = do_CreateInstance("@mozilla.org/image/tools;1");
|
||||
rv = imgtool->DecodeImageData(stream, mMimeTypeOfInputData,
|
||||
getter_AddRefs(container));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Get the recommended icon width and height, or if failure to obtain
|
||||
// these settings, fall back to 16x16 ICOs. These values can be different
|
||||
// if the user has a different DPI setting other than 100%.
|
||||
// Windows would scale the 16x16 icon themselves, but it's better
|
||||
// we let our ICO encoder do it.
|
||||
nsCOMPtr<nsIInputStream> iconStream;
|
||||
if (!mURLShortcut) {
|
||||
PRInt32 systemIconWidth = GetSystemMetrics(SM_CXSMICON);
|
||||
PRInt32 systemIconHeight = GetSystemMetrics(SM_CYSMICON);
|
||||
if ((systemIconWidth == 0 || systemIconHeight == 0)) {
|
||||
systemIconWidth = 16;
|
||||
systemIconHeight = 16;
|
||||
}
|
||||
// Scale the image to the needed size and in ICO format
|
||||
mMimeTypeOfInputData.AssignLiteral("image/vnd.microsoft.icon");
|
||||
rv = imgtool->EncodeScaledImage(container, mMimeTypeOfInputData,
|
||||
systemIconWidth,
|
||||
systemIconHeight,
|
||||
EmptyString(),
|
||||
getter_AddRefs(iconStream));
|
||||
} else {
|
||||
mMimeTypeOfInputData.AssignLiteral("image/vnd.microsoft.icon");
|
||||
rv = imgtool->EncodeImage(container,
|
||||
mMimeTypeOfInputData,
|
||||
NS_LITERAL_STRING("format=bmp;bpp=32"),
|
||||
getter_AddRefs(iconStream));
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIFile> icoFile
|
||||
= do_CreateInstance("@mozilla.org/file/local;1");
|
||||
NS_ENSURE_TRUE(icoFile, NS_ERROR_FAILURE);
|
||||
rv = icoFile->InitWithPath(mIconPath);
|
||||
|
||||
// Setup the output stream for the ICO file on disk
|
||||
nsCOMPtr<nsIOutputStream> outputStream;
|
||||
rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), icoFile);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Obtain the ICO buffer size from the re-encoded ICO stream
|
||||
PRUint32 bufSize;
|
||||
rv = iconStream->Available(&bufSize);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Setup a buffered output stream from the stream object
|
||||
// so that we can simply use WriteFrom with the stream object
|
||||
nsCOMPtr<nsIOutputStream> bufferedOutputStream;
|
||||
rv = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream),
|
||||
outputStream, bufSize);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Write out the icon stream to disk and make sure we wrote everything
|
||||
PRUint32 wrote;
|
||||
rv = bufferedOutputStream->WriteFrom(iconStream, bufSize, &wrote);
|
||||
NS_ASSERTION(bufSize == wrote,
|
||||
"Icon wrote size should be equal to requested write size");
|
||||
|
||||
// Cleanup
|
||||
bufferedOutputStream->Close();
|
||||
outputStream->Close();
|
||||
if (mURLShortcut) {
|
||||
SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, SPI_SETNONCLIENTMETRICS, 0);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
AsyncWriteIconToDisk::~AsyncWriteIconToDisk()
|
||||
{
|
||||
}
|
||||
|
||||
AsyncDeleteIconFromDisk::AsyncDeleteIconFromDisk(const nsAString &aIconPath)
|
||||
: mIconPath(aIconPath)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP AsyncDeleteIconFromDisk::Run()
|
||||
{
|
||||
// Construct the parent path of the passed in path
|
||||
nsCOMPtr<nsIFile> icoFile = do_CreateInstance("@mozilla.org/file/local;1");
|
||||
NS_ENSURE_TRUE(icoFile, NS_ERROR_FAILURE);
|
||||
nsresult rv = icoFile->InitWithPath(mIconPath);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Check if the cached ICO file exists
|
||||
bool exists;
|
||||
rv = icoFile->Exists(&exists);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Check that we aren't deleting some arbitrary file that is not an icon
|
||||
if (StringTail(mIconPath, 4).LowerCaseEqualsASCII(".ico")) {
|
||||
// Check if the cached ICO file exists
|
||||
bool exists;
|
||||
if (NS_FAILED(icoFile->Exists(&exists)) || !exists)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// We found an ICO file that exists, so we should remove it
|
||||
icoFile->Remove(false);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
AsyncDeleteIconFromDisk::~AsyncDeleteIconFromDisk()
|
||||
{
|
||||
}
|
||||
|
||||
AsyncDeleteAllFaviconsFromDisk::AsyncDeleteAllFaviconsFromDisk()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP AsyncDeleteAllFaviconsFromDisk::Run()
|
||||
{
|
||||
// Construct the path of our jump list cache
|
||||
nsCOMPtr<nsIFile> jumpListCacheDir;
|
||||
nsresult rv = NS_GetSpecialDirectory("ProfLDS",
|
||||
getter_AddRefs(jumpListCacheDir));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = jumpListCacheDir->AppendNative(
|
||||
nsDependentCString(FaviconHelper::kJumpListCacheDir));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsISimpleEnumerator> entries;
|
||||
rv = jumpListCacheDir->GetDirectoryEntries(getter_AddRefs(entries));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Loop through each directory entry and remove all ICO files found
|
||||
do {
|
||||
bool hasMore = false;
|
||||
if (NS_FAILED(entries->HasMoreElements(&hasMore)) || !hasMore)
|
||||
break;
|
||||
|
||||
nsCOMPtr<nsISupports> supp;
|
||||
if (NS_FAILED(entries->GetNext(getter_AddRefs(supp))))
|
||||
break;
|
||||
|
||||
nsCOMPtr<nsIFile> currFile(do_QueryInterface(supp));
|
||||
nsAutoString path;
|
||||
if (NS_FAILED(currFile->GetPath(path)))
|
||||
continue;
|
||||
|
||||
PRInt32 len = path.Length();
|
||||
if (StringTail(path, 4).LowerCaseEqualsASCII(".ico")) {
|
||||
// Check if the cached ICO file exists
|
||||
bool exists;
|
||||
if (NS_FAILED(currFile->Exists(&exists)) || !exists)
|
||||
continue;
|
||||
|
||||
// We found an ICO file that exists, so we should remove it
|
||||
currFile->Remove(false);
|
||||
}
|
||||
} while(true);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
AsyncDeleteAllFaviconsFromDisk::~AsyncDeleteAllFaviconsFromDisk()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* (static) If the data is available, will return the path on disk where
|
||||
* the favicon for page aFaviconPageURI is stored. If the favicon does not
|
||||
* exist, or its cache is expired, this method will kick off an async request
|
||||
* for the icon so that next time the method is called it will be available.
|
||||
* @param aFaviconPageURI The URI of the page to obtain
|
||||
* @param aICOFilePath The path of the icon file
|
||||
* @param aIOThread The thread to perform the Fetch on
|
||||
* @param aURLShortcut to distinguish between jumplistcache(false) and shortcutcache(true)
|
||||
*/
|
||||
nsresult FaviconHelper::ObtainCachedIconFile(nsCOMPtr<nsIURI> aFaviconPageURI,
|
||||
nsString &aICOFilePath,
|
||||
nsCOMPtr<nsIThread> &aIOThread,
|
||||
bool aURLShortcut)
|
||||
{
|
||||
// Obtain the ICO file path
|
||||
nsCOMPtr<nsIFile> icoFile;
|
||||
nsresult rv = GetOutputIconPath(aFaviconPageURI, icoFile, aURLShortcut);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Check if the cached ICO file already exists
|
||||
bool exists;
|
||||
rv = icoFile->Exists(&exists);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (exists) {
|
||||
|
||||
// Obtain the file's last modification date in seconds
|
||||
PRInt64 fileModTime = LL_ZERO;
|
||||
rv = icoFile->GetLastModifiedTime(&fileModTime);
|
||||
fileModTime /= PR_MSEC_PER_SEC;
|
||||
PRInt32 icoReCacheSecondsTimeout = GetICOCacheSecondsTimeout();
|
||||
PRInt64 nowTime = PR_Now() / PRInt64(PR_USEC_PER_SEC);
|
||||
|
||||
// If the last mod call failed or the icon is old then re-cache it
|
||||
// This check is in case the favicon of a page changes
|
||||
// the next time we try to build the jump list, the data will be available.
|
||||
if (NS_FAILED(rv) ||
|
||||
(nowTime - fileModTime) > icoReCacheSecondsTimeout) {
|
||||
CacheIconFileFromFaviconURIAsync(aFaviconPageURI, icoFile, aIOThread, aURLShortcut);
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
} else {
|
||||
|
||||
// The file does not exist yet, obtain it async from the favicon service so that
|
||||
// the next time we try to build the jump list it'll be available.
|
||||
CacheIconFileFromFaviconURIAsync(aFaviconPageURI, icoFile, aIOThread, aURLShortcut);
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
// The icoFile is filled with a path that exists, get its path
|
||||
rv = icoFile->GetPath(aICOFilePath);
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult FaviconHelper::HashURI(nsCOMPtr<nsICryptoHash> &aCryptoHash,
|
||||
nsIURI *aUri,
|
||||
nsACString& aUriHash)
|
||||
{
|
||||
if (!aUri)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
nsCAutoString spec;
|
||||
nsresult rv = aUri->GetSpec(spec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!aCryptoHash) {
|
||||
aCryptoHash = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
rv = aCryptoHash->Init(nsICryptoHash::MD5);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = aCryptoHash->Update(reinterpret_cast<const PRUint8*>(spec.BeginReading()),
|
||||
spec.Length());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = aCryptoHash->Finish(true, aUriHash);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// (static) Obtains the ICO file for the favicon at page aFaviconPageURI
|
||||
// If successful, the file path on disk is in the format:
|
||||
// <ProfLDS>\jumpListCache\<hash(aFaviconPageURI)>.ico
|
||||
nsresult FaviconHelper::GetOutputIconPath(nsCOMPtr<nsIURI> aFaviconPageURI,
|
||||
nsCOMPtr<nsIFile> &aICOFile,
|
||||
bool aURLShortcut)
|
||||
{
|
||||
// Hash the input URI and replace any / with _
|
||||
nsCAutoString inputURIHash;
|
||||
nsCOMPtr<nsICryptoHash> cryptoHash;
|
||||
nsresult rv = HashURI(cryptoHash, aFaviconPageURI,
|
||||
inputURIHash);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
char* cur = inputURIHash.BeginWriting();
|
||||
char* end = inputURIHash.EndWriting();
|
||||
for (; cur < end; ++cur) {
|
||||
if ('/' == *cur) {
|
||||
*cur = '_';
|
||||
}
|
||||
}
|
||||
|
||||
// Obtain the local profile directory and construct the output icon file path
|
||||
rv = NS_GetSpecialDirectory("ProfLDS", getter_AddRefs(aICOFile));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!aURLShortcut)
|
||||
rv = aICOFile->AppendNative(nsDependentCString(kJumpListCacheDir));
|
||||
else
|
||||
rv = aICOFile->AppendNative(nsDependentCString(kShortcutCacheDir));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Try to create the directory if it's not there yet
|
||||
rv = aICOFile->Create(nsIFile::DIRECTORY_TYPE, 0777);
|
||||
if (NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Append the icon extension
|
||||
inputURIHash.Append(".ico");
|
||||
rv = aICOFile->AppendNative(inputURIHash);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
// (static) Asynchronously creates a cached ICO file on disk for the favicon of
|
||||
// page aFaviconPageURI and stores it to disk at the path of aICOFile.
|
||||
nsresult
|
||||
FaviconHelper::CacheIconFileFromFaviconURIAsync(nsCOMPtr<nsIURI> aFaviconPageURI,
|
||||
nsCOMPtr<nsIFile> aICOFile,
|
||||
nsCOMPtr<nsIThread> &aIOThread,
|
||||
bool aURLShortcut)
|
||||
{
|
||||
// Obtain the favicon service and get the favicon for the specified page
|
||||
nsCOMPtr<mozIAsyncFavicons> favIconSvc(
|
||||
do_GetService("@mozilla.org/browser/favicon-service;1"));
|
||||
NS_ENSURE_TRUE(favIconSvc, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsIFaviconDataCallback> callback =
|
||||
new mozilla::widget::AsyncFaviconDataReady(aFaviconPageURI,
|
||||
aIOThread,
|
||||
aURLShortcut);
|
||||
|
||||
favIconSvc->GetFaviconDataForPage(aFaviconPageURI, callback);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Obtains the jump list 'ICO cache timeout in seconds' pref
|
||||
PRInt32 FaviconHelper::GetICOCacheSecondsTimeout() {
|
||||
|
||||
// Only obtain the setting at most once from the pref service.
|
||||
// In the rare case that 2 threads call this at the same
|
||||
// time it is no harm and we will simply obtain the pref twice.
|
||||
// None of the taskbar list prefs are currently updated via a
|
||||
// pref observer so I think this should suffice.
|
||||
const PRInt32 kSecondsPerDay = 86400;
|
||||
static bool alreadyObtained = false;
|
||||
static PRInt32 icoReCacheSecondsTimeout = kSecondsPerDay;
|
||||
if (alreadyObtained) {
|
||||
return icoReCacheSecondsTimeout;
|
||||
}
|
||||
|
||||
// Obtain the pref
|
||||
const char PREF_ICOTIMEOUT[] = "browser.taskbar.lists.icoTimeoutInSeconds";
|
||||
icoReCacheSecondsTimeout = Preferences::GetInt(PREF_ICOTIMEOUT,
|
||||
kSecondsPerDay);
|
||||
alreadyObtained = true;
|
||||
return icoReCacheSecondsTimeout;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* static */
|
||||
bool
|
||||
WinUtils::GetShellItemPath(IShellItem* aItem,
|
||||
|
@ -12,11 +12,24 @@
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsString.h"
|
||||
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsICryptoHash.h"
|
||||
#include "nsIFaviconService.h"
|
||||
#include "nsIDownloader.h"
|
||||
|
||||
|
||||
class nsWindow;
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
||||
class myDownloadObserver: public nsIDownloadObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIDOWNLOADOBSERVER
|
||||
};
|
||||
|
||||
class WinUtils {
|
||||
public:
|
||||
enum WinVersion {
|
||||
@ -203,6 +216,99 @@ private:
|
||||
static bool VistaCreateItemFromParsingNameInit();
|
||||
};
|
||||
|
||||
class AsyncFaviconDataReady : public nsIFaviconDataCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIFAVICONDATACALLBACK
|
||||
|
||||
AsyncFaviconDataReady(nsIURI *aNewURI,
|
||||
nsCOMPtr<nsIThread> &aIOThread,
|
||||
const bool aURLShortcut);
|
||||
nsresult OnFaviconDataNotAvailable(void);
|
||||
private:
|
||||
nsCOMPtr<nsIURI> mNewURI;
|
||||
nsCOMPtr<nsIThread> mIOThread;
|
||||
const bool mURLShortcut;
|
||||
};
|
||||
|
||||
/**
|
||||
* Asynchronously tries add the list to the build
|
||||
*/
|
||||
class AsyncWriteIconToDisk : public nsIRunnable
|
||||
{
|
||||
public:
|
||||
const bool mURLShortcut;
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
// Warning: AsyncWriteIconToDisk assumes ownership of the aData buffer passed in
|
||||
AsyncWriteIconToDisk(const nsAString &aIconPath,
|
||||
const nsACString &aMimeTypeOfInputData,
|
||||
PRUint8 *aData,
|
||||
PRUint32 aDataLen,
|
||||
const bool aURLShortcut);
|
||||
virtual ~AsyncWriteIconToDisk();
|
||||
|
||||
private:
|
||||
nsAutoString mIconPath;
|
||||
nsCAutoString mMimeTypeOfInputData;
|
||||
nsAutoArrayPtr<PRUint8> mBuffer;
|
||||
PRUint32 mBufferLength;
|
||||
};
|
||||
|
||||
class AsyncDeleteIconFromDisk : public nsIRunnable
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
AsyncDeleteIconFromDisk(const nsAString &aIconPath);
|
||||
virtual ~AsyncDeleteIconFromDisk();
|
||||
|
||||
private:
|
||||
nsAutoString mIconPath;
|
||||
};
|
||||
|
||||
class AsyncDeleteAllFaviconsFromDisk : public nsIRunnable
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
AsyncDeleteAllFaviconsFromDisk();
|
||||
virtual ~AsyncDeleteAllFaviconsFromDisk();
|
||||
};
|
||||
|
||||
class FaviconHelper
|
||||
{
|
||||
public:
|
||||
static const char kJumpListCacheDir[];
|
||||
static const char kShortcutCacheDir[];
|
||||
static nsresult ObtainCachedIconFile(nsCOMPtr<nsIURI> aFaviconPageURI,
|
||||
nsString &aICOFilePath,
|
||||
nsCOMPtr<nsIThread> &aIOThread,
|
||||
bool aURLShortcut);
|
||||
|
||||
static nsresult HashURI(nsCOMPtr<nsICryptoHash> &aCryptoHash,
|
||||
nsIURI *aUri,
|
||||
nsACString& aUriHash);
|
||||
|
||||
static nsresult GetOutputIconPath(nsCOMPtr<nsIURI> aFaviconPageURI,
|
||||
nsCOMPtr<nsIFile> &aICOFile,
|
||||
bool aURLShortcut);
|
||||
|
||||
static nsresult
|
||||
CacheIconFileFromFaviconURIAsync(nsCOMPtr<nsIURI> aFaviconPageURI,
|
||||
nsCOMPtr<nsIFile> aICOFile,
|
||||
nsCOMPtr<nsIThread> &aIOThread,
|
||||
bool aURLShortcut);
|
||||
|
||||
static PRInt32 GetICOCacheSecondsTimeout();
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace widget
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -30,8 +30,14 @@
|
||||
#include "nsITimer.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
#include "WinUtils.h"
|
||||
#include "mozilla/LazyIdleThread.h"
|
||||
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
#define DEFAULT_THREAD_TIMEOUT_MS 30000
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsDataObj::CStream, nsIStreamListener)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -345,6 +351,9 @@ nsDataObj::nsDataObj(nsIURI * uri)
|
||||
: m_cRef(0), mTransferable(nsnull),
|
||||
mIsAsyncMode(FALSE), mIsInOperation(FALSE)
|
||||
{
|
||||
mIOThread = new LazyIdleThread(DEFAULT_THREAD_TIMEOUT_MS,
|
||||
NS_LITERAL_CSTRING("nsDataObj"),
|
||||
LazyIdleThread::ManualShutdown);
|
||||
m_enumFE = new CEnumFormatEtc();
|
||||
m_enumFE->AddRef();
|
||||
|
||||
@ -1088,10 +1097,27 @@ nsDataObj :: GetFileContentsInternetShortcut ( FORMATETC& aFE, STGMEDIUM& aSTG )
|
||||
// will need to change if we ever support iDNS
|
||||
nsCAutoString asciiUrl;
|
||||
LossyCopyUTF16toASCII(url, asciiUrl);
|
||||
|
||||
static const char* shortcutFormatStr = "[InternetShortcut]\r\nURL=%s\r\n";
|
||||
static const int formatLen = strlen(shortcutFormatStr) - 2; // don't include %s in the len
|
||||
const int totalLen = formatLen + asciiUrl.Length(); // we don't want a null character on the end
|
||||
|
||||
nsCOMPtr<nsIFile> icoFile;
|
||||
nsCOMPtr<nsIURI> aUri;
|
||||
NS_NewURI(getter_AddRefs(aUri), url);
|
||||
|
||||
nsAutoString aUriHash;
|
||||
|
||||
mozilla::widget::FaviconHelper::ObtainCachedIconFile(aUri, aUriHash, mIOThread, true);
|
||||
|
||||
nsresult rv = mozilla::widget::FaviconHelper::GetOutputIconPath(aUri, icoFile, true);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCString path;
|
||||
rv = icoFile->GetNativePath(path);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
static char* shortcutFormatStr = "[InternetShortcut]\r\nURL=%s\r\n"
|
||||
"IDList=\r\nHotKey=0\r\nIconFile=%s\r\n"
|
||||
"IconIndex=0\r\n";
|
||||
static const int formatLen = strlen(shortcutFormatStr) - 2*2; // don't include %s (2 times) in the len
|
||||
const int totalLen = formatLen + asciiUrl.Length()
|
||||
+ path.Length(); // we don't want a null character on the end
|
||||
|
||||
// create a global memory area and build up the file contents w/in it
|
||||
HGLOBAL hGlobalMemory = ::GlobalAlloc(GMEM_SHARE, totalLen);
|
||||
@ -1108,7 +1134,7 @@ nsDataObj :: GetFileContentsInternetShortcut ( FORMATETC& aFE, STGMEDIUM& aSTG )
|
||||
// terminate strings which reach the maximum size of the buffer. Since we know that the
|
||||
// formatted length here is totalLen, this call to _snprintf will format the string into
|
||||
// the buffer without appending the null character.
|
||||
_snprintf( contents, totalLen, shortcutFormatStr, asciiUrl.get() );
|
||||
_snprintf( contents, totalLen, shortcutFormatStr, asciiUrl.get(), path.get() );
|
||||
|
||||
::GlobalUnlock(hGlobalMemory);
|
||||
aSTG.hGlobal = hGlobalMemory;
|
||||
|
@ -19,6 +19,8 @@
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsITimer.h"
|
||||
|
||||
class nsIThread;
|
||||
|
||||
// The SDK shipping with VC11 has renamed IAsyncOperation to
|
||||
// IDataObjectAsyncCapability. We try to detect this, and rename this in our
|
||||
// code too to make sure that we pick the correct name when building.
|
||||
@ -85,6 +87,10 @@ class nsITransferable;
|
||||
class nsDataObj : public IDataObject,
|
||||
public IAsyncOperation
|
||||
{
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIThread> mIOThread;
|
||||
|
||||
public: // construction, destruction
|
||||
nsDataObj(nsIURI *uri = nsnull);
|
||||
virtual ~nsDataObj();
|
||||
|
Loading…
Reference in New Issue
Block a user