From 925a3aac3943ff8096503bb3bd046caf20bc9efb Mon Sep 17 00:00:00 2001 From: Marco Bonardo Date: Thu, 25 Mar 2010 12:34:31 +0100 Subject: [PATCH] Bug 553489 - Part2: AsyncFaviconStepper. r=sdwilsh r=dietrich --- .../places/src/AsyncFaviconHelpers.cpp | 220 +++++++++++++++ .../places/src/AsyncFaviconHelpers.h | 261 ++++++++++++++++++ toolkit/components/places/src/Makefile.in | 1 + .../places/src/nsFaviconService.cpp | 1 + 4 files changed, 483 insertions(+) create mode 100644 toolkit/components/places/src/AsyncFaviconHelpers.cpp create mode 100644 toolkit/components/places/src/AsyncFaviconHelpers.h diff --git a/toolkit/components/places/src/AsyncFaviconHelpers.cpp b/toolkit/components/places/src/AsyncFaviconHelpers.cpp new file mode 100644 index 00000000000..94a1ae81bbc --- /dev/null +++ b/toolkit/components/places/src/AsyncFaviconHelpers.cpp @@ -0,0 +1,220 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ : + * ***** 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 Places. + * + * The Initial Developer of the Original Code is the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Marco Bonardo (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 "AsyncFaviconHelpers.h" + +#include "mozilla/storage.h" + +#define TO_CHARBUFFER(_buffer) \ + reinterpret_cast(const_cast(_buffer)) +#define TO_INTBUFFER(_string) \ + reinterpret_cast(const_cast(_string.get())) + +namespace mozilla { +namespace places { + + +//////////////////////////////////////////////////////////////////////////////// +//// AsyncFaviconStep + +NS_IMPL_ISUPPORTS0( + AsyncFaviconStep +) + + +//////////////////////////////////////////////////////////////////////////////// +//// AsyncFaviconStepper + +NS_IMPL_ISUPPORTS0( + AsyncFaviconStepper +) + + +AsyncFaviconStepper::AsyncFaviconStepper(nsIFaviconDataCallback* aCallback) + : mStepper(new AsyncFaviconStepperInternal(aCallback)) +{ +} + + +nsresult +AsyncFaviconStepper::Start() +{ + FAVICONSTEP_FAIL_IF_FALSE_RV(mStepper->mStatus == STEPPER_INITING, + NS_ERROR_FAILURE); + mStepper->mStatus = STEPPER_RUNNING; + nsresult rv = mStepper->Step(); + FAVICONSTEP_FAIL_IF_FALSE_RV(NS_SUCCEEDED(rv), rv); + return NS_OK; +} + + +nsresult +AsyncFaviconStepper::AppendStep(AsyncFaviconStep* aStep) +{ + FAVICONSTEP_FAIL_IF_FALSE_RV(aStep, NS_ERROR_OUT_OF_MEMORY); + FAVICONSTEP_FAIL_IF_FALSE_RV(mStepper->mStatus == STEPPER_INITING, + NS_ERROR_FAILURE); + + aStep->SetStepper(mStepper); + nsresult rv = mStepper->mSteps.AppendObject(aStep); + FAVICONSTEP_FAIL_IF_FALSE_RV(NS_SUCCEEDED(rv), rv); + return NS_OK; +} + + +nsresult +AsyncFaviconStepper::SetIconData(const nsACString& aMimeType, + const PRUint8* _data, + PRUint32 _dataLen) +{ + mStepper->mMimeType = aMimeType; + mStepper->mData.Adopt(TO_CHARBUFFER(_data), _dataLen); + mStepper->mIconStatus |= ICON_STATUS_CHANGED; + return NS_OK; +} + + +nsresult +AsyncFaviconStepper::GetIconData(nsACString& aMimeType, + const PRUint8** aData, + PRUint32* aDataLen) +{ + PRUint32 dataLen = mStepper->mData.Length(); + NS_ENSURE_TRUE(dataLen > 0, NS_ERROR_NOT_AVAILABLE); + aMimeType = mStepper->mMimeType; + *aDataLen = dataLen; + *aData = TO_INTBUFFER(mStepper->mData); + return NS_OK; +} + + +//////////////////////////////////////////////////////////////////////////////// +//// AsyncFaviconStepperInternal + +NS_IMPL_ISUPPORTS0( + AsyncFaviconStepperInternal +) + + +AsyncFaviconStepperInternal::AsyncFaviconStepperInternal( + nsIFaviconDataCallback* aCallback +) + : mCallback(aCallback) + , mPageId(0) + , mIconId(0) + , mExpiration(0) + , mIsRevisit(false) + , mIconStatus(ICON_STATUS_UNKNOWN) + , mStatus(STEPPER_INITING) +{ +} + + +nsresult +AsyncFaviconStepperInternal::Step() +{ + if (mStatus != STEPPER_RUNNING) { + Failure(); + return NS_ERROR_FAILURE; + } + + PRInt32 stepCount = mSteps.Count(); + if (!stepCount) { + mStatus = STEPPER_COMPLETED; + // Ran all steps, let's notify. + if (mCallback) { + (void)mCallback->OnFaviconDataAvailable(mIconURI, + mData.Length(), + TO_INTBUFFER(mData), + mMimeType); + } + return NS_OK; + } + + // Get the next step. + nsCOMPtr step = mSteps[0]; + if (!step) { + Failure(); + return NS_ERROR_UNEXPECTED; + } + + // Break the cycle. + nsresult rv = mSteps.RemoveObjectAt(0); + if (NS_FAILED(rv)) { + Failure(); + return NS_ERROR_UNEXPECTED; + } + + // Run the extracted step. + step->Run(); + + return NS_OK; +} + + +void +AsyncFaviconStepperInternal::Failure() +{ + mStatus = STEPPER_FAILED; + + // Break the cycles so steps are collected. + mSteps.Clear(); +} + + +void +AsyncFaviconStepperInternal::Cancel(bool aNotify) +{ + mStatus = STEPPER_CANCELED; + + // Break the cycles so steps are collected. + mSteps.Clear(); + + if (aNotify && mCallback) { + (void)mCallback->OnFaviconDataAvailable(mIconURI, + mData.Length(), + TO_INTBUFFER(mData), + mMimeType); + } +} + + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace places +} // namespace mozilla diff --git a/toolkit/components/places/src/AsyncFaviconHelpers.h b/toolkit/components/places/src/AsyncFaviconHelpers.h new file mode 100644 index 00000000000..8a4359803af --- /dev/null +++ b/toolkit/components/places/src/AsyncFaviconHelpers.h @@ -0,0 +1,261 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ : + * ***** 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 Places. + * + * The Initial Developer of the Original Code is the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Marco Bonardo (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 ***** */ + +/** + * How to use this stepper: + * + * nsCOMPtr stepper = new AsyncFaviconStepper(callback); + * stepper->AppendStep(new SomeStep()); + * stepper->AppendStep(new SomeOtherStep()); + * stepper->Start(); + */ + +#ifndef AsyncFaviconHelpers_h_ +#define AsyncFaviconHelpers_h_ + +#include "nsCOMPtr.h" +#include "nsCOMArray.h" +#include "nsIURI.h" + +#include "nsIFaviconService.h" + +#include "mozilla/storage.h" + +#define FAVICONSTEP_FAIL_IF_FALSE(_cond) \ + FAVICONSTEP_FAIL_IF_FALSE_RV(_cond, ) + +#define FAVICONSTEP_FAIL_IF_FALSE_RV(_cond, _rv) \ + PR_BEGIN_MACRO \ + if (!(_cond)) { \ + NS_WARNING("AsyncFaviconStep failed!"); \ + mStepper->Failure(); \ + return _rv; \ + } \ + PR_END_MACRO + +#define FAVICONSTEP_CANCEL_IF_TRUE(_cond, _notify) \ + FAVICONSTEP_CANCEL_IF_TRUE_RV(_cond, _notify, ) + +#define FAVICONSTEP_CANCEL_IF_TRUE_RV(_cond, _notify, _rv) \ + PR_BEGIN_MACRO \ + if (_cond) { \ + mStepper->Cancel(_notify); \ + return _rv; \ + } \ + PR_END_MACRO + +#define ICON_STATUS_UNKNOWN 0 +#define ICON_STATUS_CHANGED 1 << 0 +#define ICON_STATUS_SAVED 1 << 1 +#define ICON_STATUS_ASSOCIATED 1 << 2 + +namespace mozilla { +namespace places { + + +// Forward declarations. +class AsyncFaviconStepperInternal; +class AsyncFaviconStepper; + + +/** + * Executes a single async step on a favicon resource. + * Once done, call backs to the stepper to proceed to the next step. + */ +class AsyncFaviconStep : public nsISupports +{ +public: + NS_DECL_ISUPPORTS + + AsyncFaviconStep() {} + + /** + * Associate this step to a stepper. + * + * Automatically called by the stepper when the step is added to it. + * @see AsyncFaviconStepper::appendStep + */ + void SetStepper(AsyncFaviconStepperInternal* aStepper) { mStepper = aStepper; } + + /** + * Executes the step. Virtual since it MUST be overridden. + */ + virtual void Run() {}; + +protected: + nsCOMPtr mStepper; +}; + + +/** + * Status definitions for the stepper. + */ +enum AsyncFaviconStepperStatus { + STEPPER_INITING = 0 +, STEPPER_RUNNING = 1 +, STEPPER_FAILED = 2 +, STEPPER_COMPLETED = 3 +, STEPPER_CANCELED = 4 +}; + + +/** + * This class provides public methods and properties to steps. + * Any other code should use the wrapper (AsyncFaviconStepper) instead. + * + * @see AsyncFaviconStepper + */ +class AsyncFaviconStepperInternal : public nsISupports +{ +public: + NS_DECL_ISUPPORTS + + /** + * Creates the stepper. + * + * @param aCallback + * An nsIFaviconDataCallback to be called when done. + */ + AsyncFaviconStepperInternal(nsIFaviconDataCallback* aCallback); + + /** + * Proceed to next step. + */ + nsresult Step(); + + /** + * Called by the steps when something goes wrong. + * Will unlink all steps and gently return. + */ + void Failure(); + + /** + * Called by the steps when they require us to stop walking. + * This is not an error condition, sometimes we could want to bail out to + * avoid useless additional work. + * Will unlink all steps and gently return. + */ + void Cancel(bool aNotify); + + nsCOMPtr mCallback; + PRInt64 mPageId; + nsCOMPtr mPageURI; + PRInt64 mIconId; + nsCOMPtr mIconURI; + nsCString mData; + nsCString mMimeType; + PRTime mExpiration; + bool mIsRevisit; + PRUint16 mIconStatus; // This is a bitset, see ICON_STATUS_* defines above. + +private: + enum AsyncFaviconStepperStatus mStatus; + nsCOMArray mSteps; + + friend class AsyncFaviconStepper; +}; + + +/** + * Walks through an ordered list of AsyncFaviconSteps. + * Each step call backs the stepper that will proceed to the next one. + * When all steps are complete it calls aCallback, if valid. + * + * This class is a wrapper around AsyncFaviconStepperInternal, where the actual + * work is done. + */ +class AsyncFaviconStepper : public nsISupports +{ +public: + NS_DECL_ISUPPORTS + + /** + * Creates the stepper. + * + * @param aCallback + * An nsIFaviconDataCallback to call when done. + */ + AsyncFaviconStepper(nsIFaviconDataCallback* aCallback); + + /** + * Kick-off the first step. + */ + nsresult Start(); + + /** + * Appends a new step to this stepper. + * + * @param aStep + * An AsyncFaviconStep to append. + */ + nsresult AppendStep(AsyncFaviconStep* aStep); + + // Setters and getters. + // Some definitions are inline to try getting some love from the compiler. + + void SetPageId(PRInt64 aPageId) { mStepper->mPageId = aPageId; } + PRInt64 GetPageId() { return mStepper->mPageId; } + + void SetPageURI(nsIURI* aURI) { mStepper->mPageURI = aURI; } + already_AddRefed GetPageURI() { return mStepper->mPageURI.forget(); } + + void SetIconId(PRInt64 aIconId) { mStepper->mIconId = aIconId; } + PRInt64 GetIconId() { return mStepper->mIconId; } + + void SetIconURI(nsIURI* aURI) { mStepper->mIconURI = aURI; } + already_AddRefed GetIconURI() { return mStepper->mIconURI.forget(); } + + nsresult SetIconData(const nsACString& aMimeType, + const PRUint8* aData, + PRUint32 aDataLen); + nsresult GetIconData(nsACString& aMimeType, + const PRUint8** aData, + PRUint32* aDataLen); + + void SetExpiration(PRTime aExpiration) { mStepper->mExpiration = aExpiration; } + PRTime GetExpiration() { return mStepper->mExpiration; } + +private: + nsCOMPtr mStepper; +}; + + +} // namespace places +} // namespace mozilla + +#endif // AsyncFaviconHelpers_h_ diff --git a/toolkit/components/places/src/Makefile.in b/toolkit/components/places/src/Makefile.in index 8e65defc866..8f5e2e4a411 100644 --- a/toolkit/components/places/src/Makefile.in +++ b/toolkit/components/places/src/Makefile.in @@ -66,6 +66,7 @@ CPPSRCS = \ Helpers.cpp \ History.cpp \ nsPlacesImportExportService.cpp \ + AsyncFaviconHelpers.cpp \ $(NULL) EXTRA_DSO_LDOPTS += \ diff --git a/toolkit/components/places/src/nsFaviconService.cpp b/toolkit/components/places/src/nsFaviconService.cpp index 1eb4f6d8794..c18154624c7 100644 --- a/toolkit/components/places/src/nsFaviconService.cpp +++ b/toolkit/components/places/src/nsFaviconService.cpp @@ -69,6 +69,7 @@ #include "nsPlacesMacros.h" #include "nsIPrefService.h" #include "Helpers.h" +#include "AsyncFaviconHelpers.h" // For large favicons optimization. #include "imgITools.h"