Bug 553489 - Part2: AsyncFaviconStepper. r=sdwilsh r=dietrich

This commit is contained in:
Marco Bonardo 2010-03-25 12:34:31 +01:00
parent d31d86de04
commit 925a3aac39
4 changed files with 483 additions and 0 deletions

View File

@ -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 <mak77@bonardo.net> (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<char*>(const_cast<PRUint8*>(_buffer))
#define TO_INTBUFFER(_string) \
reinterpret_cast<PRUint8*>(const_cast<char*>(_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<AsyncFaviconStep> 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

View File

@ -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 <mak77@bonardo.net> (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<AsyncFaviconStepper> 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<AsyncFaviconStepperInternal> 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<nsIFaviconDataCallback> mCallback;
PRInt64 mPageId;
nsCOMPtr<nsIURI> mPageURI;
PRInt64 mIconId;
nsCOMPtr<nsIURI> 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<AsyncFaviconStep> 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<nsIURI> 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<nsIURI> 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<AsyncFaviconStepperInternal> mStepper;
};
} // namespace places
} // namespace mozilla
#endif // AsyncFaviconHelpers_h_

View File

@ -66,6 +66,7 @@ CPPSRCS = \
Helpers.cpp \
History.cpp \
nsPlacesImportExportService.cpp \
AsyncFaviconHelpers.cpp \
$(NULL)
EXTRA_DSO_LDOPTS += \

View File

@ -69,6 +69,7 @@
#include "nsPlacesMacros.h"
#include "nsIPrefService.h"
#include "Helpers.h"
#include "AsyncFaviconHelpers.h"
// For large favicons optimization.
#include "imgITools.h"