зеркало из https://github.com/mozilla/gecko-dev.git
Bug 502694 - Images should not have individual discard timers.r=jrmuizel
This commit is contained in:
Родитель
283b92b9e1
Коммит
43f9633453
|
@ -58,6 +58,7 @@
|
|||
#include "imgRequest.h"
|
||||
#include "imgRequestProxy.h"
|
||||
#include "imgTools.h"
|
||||
#include "imgDiscardTracker.h"
|
||||
|
||||
#ifdef IMG_BUILD_DECODER_gif
|
||||
// gif
|
||||
|
@ -295,6 +296,7 @@ static void
|
|||
imglib_Shutdown(nsIModule* aSelf)
|
||||
{
|
||||
imgLoader::Shutdown();
|
||||
imgDiscardTracker::Shutdown();
|
||||
}
|
||||
|
||||
NS_IMPL_NSGETMODULE_WITH_CTOR_DTOR(nsImageLib2Module, components,
|
||||
|
|
|
@ -58,6 +58,7 @@ CPPSRCS = \
|
|||
imgRequestProxy.cpp \
|
||||
imgTools.cpp \
|
||||
imgContainerRequest.cpp \
|
||||
imgDiscardTracker.cpp \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -144,7 +144,6 @@ imgContainer::imgContainer() :
|
|||
mLoopCount(-1),
|
||||
mObserver(nsnull),
|
||||
mLockCount(0),
|
||||
mDiscardTimer(nsnull),
|
||||
mDecoder(nsnull),
|
||||
mWorker(nsnull),
|
||||
mBytesDecoded(0),
|
||||
|
@ -161,6 +160,10 @@ imgContainer::imgContainer() :
|
|||
mInDecoder(PR_FALSE),
|
||||
mError(PR_FALSE)
|
||||
{
|
||||
// Set up the discard tracker node.
|
||||
mDiscardTrackerNode.curr = this;
|
||||
mDiscardTrackerNode.prev = mDiscardTrackerNode.next = nsnull;
|
||||
|
||||
// Statistics
|
||||
num_containers++;
|
||||
}
|
||||
|
@ -190,10 +193,7 @@ imgContainer::~imgContainer()
|
|||
discardable_source_bytes));
|
||||
}
|
||||
|
||||
if (mDiscardTimer) {
|
||||
mDiscardTimer->Cancel();
|
||||
mDiscardTimer = nsnull;
|
||||
}
|
||||
imgDiscardTracker::Remove(&mDiscardTrackerNode);
|
||||
|
||||
// If we have a decoder open, shut it down
|
||||
if (mDecoder) {
|
||||
|
@ -1026,9 +1026,9 @@ NS_IMETHODIMP imgContainer::DecodingComplete(void)
|
|||
|
||||
// We now have one of the qualifications for discarding. Re-evaluate.
|
||||
if (CanDiscard()) {
|
||||
NS_ABORT_IF_FALSE(!mDiscardTimer,
|
||||
NS_ABORT_IF_FALSE(!DiscardingActive(),
|
||||
"We shouldn't have been discardable before this");
|
||||
rv = ResetDiscardTimer();
|
||||
rv = imgDiscardTracker::Reset(&mDiscardTrackerNode);
|
||||
CONTAINER_ENSURE_SUCCESS(rv);
|
||||
}
|
||||
|
||||
|
@ -1345,7 +1345,7 @@ NS_IMETHODIMP imgContainer::SourceDataComplete()
|
|||
|
||||
// We now have one of the qualifications for discarding. Re-evaluate.
|
||||
if (CanDiscard()) {
|
||||
nsresult rv = ResetDiscardTimer();
|
||||
nsresult rv = imgDiscardTracker::Reset(&mDiscardTrackerNode);
|
||||
CONTAINER_ENSURE_SUCCESS(rv);
|
||||
}
|
||||
return NS_OK;
|
||||
|
@ -2014,46 +2014,32 @@ NS_IMETHODIMP imgContainer::GetKeys(PRUint32 *count, char ***keys)
|
|||
return mProperties->GetKeys(count, keys);
|
||||
}
|
||||
|
||||
static int
|
||||
get_discard_timer_ms (void)
|
||||
{
|
||||
/* FIXME: don't hardcode this */
|
||||
return 15000; /* 15 seconds */
|
||||
}
|
||||
|
||||
void
|
||||
imgContainer::sDiscardTimerCallback(nsITimer *aTimer, void *aClosure)
|
||||
imgContainer::Discard()
|
||||
{
|
||||
// Retrieve self pointer and null out the expired timer
|
||||
imgContainer *self = (imgContainer *) aClosure;
|
||||
NS_ABORT_IF_FALSE(aTimer == self->mDiscardTimer,
|
||||
"imgContainer::DiscardTimerCallback() got a callback "
|
||||
"for an unknown timer");
|
||||
self->mDiscardTimer = nsnull;
|
||||
|
||||
// We should be ok for discard
|
||||
NS_ABORT_IF_FALSE(self->CanDiscard(), "Hit discard callback but can't discard!");
|
||||
NS_ABORT_IF_FALSE(CanDiscard(), "Asked to discard but can't!");
|
||||
|
||||
// We should never discard when we have an active decoder
|
||||
NS_ABORT_IF_FALSE(!self->mDecoder, "Discard callback fired with open decoder!");
|
||||
NS_ABORT_IF_FALSE(!mDecoder, "Asked to discard with open decoder!");
|
||||
|
||||
// As soon as an image becomes animated, it becomes non-discardable and any
|
||||
// timers are cancelled.
|
||||
NS_ABORT_IF_FALSE(!self->mAnim, "Discard callback fired for animated image!");
|
||||
NS_ABORT_IF_FALSE(!mAnim, "Asked to discard for animated image!");
|
||||
|
||||
// For post-operation logging
|
||||
int old_frame_count = self->mFrames.Length();
|
||||
int old_frame_count = mFrames.Length();
|
||||
|
||||
// Delete all the decoded frames, then clear the array.
|
||||
for (int i = 0; i < old_frame_count; ++i)
|
||||
delete self->mFrames[i];
|
||||
self->mFrames.Clear();
|
||||
delete mFrames[i];
|
||||
mFrames.Clear();
|
||||
|
||||
// Flag that we no longer have decoded frames for this image
|
||||
self->mDecoded = PR_FALSE;
|
||||
mDecoded = PR_FALSE;
|
||||
|
||||
// Notify that we discarded
|
||||
nsCOMPtr<imgIDecoderObserver> observer(do_QueryReferent(self->mObserver));
|
||||
nsCOMPtr<imgIDecoderObserver> observer(do_QueryReferent(mObserver));
|
||||
if (observer)
|
||||
observer->OnDiscard(nsnull);
|
||||
|
||||
|
@ -2063,43 +2049,16 @@ imgContainer::sDiscardTimerCallback(nsITimer *aTimer, void *aClosure)
|
|||
"data from imgContainer %p (%s) - %d frames (cached count: %d); "
|
||||
"Total Containers: %d, Discardable containers: %d, "
|
||||
"Total source bytes: %lld, Source bytes for discardable containers %lld",
|
||||
self,
|
||||
self->mSourceDataMimeType.get(),
|
||||
this,
|
||||
mSourceDataMimeType.get(),
|
||||
old_frame_count,
|
||||
self->mFrames.Length(),
|
||||
mFrames.Length(),
|
||||
num_containers,
|
||||
num_discardable_containers,
|
||||
total_source_bytes,
|
||||
discardable_source_bytes));
|
||||
}
|
||||
|
||||
nsresult
|
||||
imgContainer::ResetDiscardTimer()
|
||||
{
|
||||
// We should not call this function if we can't discard
|
||||
NS_ABORT_IF_FALSE(CanDiscard(), "Calling ResetDiscardTimer but can't discard!");
|
||||
|
||||
// As soon as an image becomes animated it is set non-discardable
|
||||
NS_ABORT_IF_FALSE(!mAnim, "Trying to reset discard timer on animated image!");
|
||||
|
||||
// If we have a timer already ticking, cancel it
|
||||
if (mDiscardTimer) {
|
||||
nsresult rv = mDiscardTimer->Cancel();
|
||||
CONTAINER_ENSURE_SUCCESS(rv);
|
||||
mDiscardTimer = nsnull;
|
||||
}
|
||||
|
||||
// Create a new timer
|
||||
mDiscardTimer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
CONTAINER_ENSURE_TRUE(mDiscardTimer, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
// Activate the timer
|
||||
return mDiscardTimer->InitWithFuncCallback(sDiscardTimerCallback,
|
||||
(void *) this,
|
||||
get_discard_timer_ms (),
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
}
|
||||
|
||||
// Helper method to determine if we can discard an image
|
||||
PRBool
|
||||
imgContainer::CanDiscard() {
|
||||
|
@ -2110,6 +2069,13 @@ imgContainer::CanDiscard() {
|
|||
mDecoded); // ...and have something to discard.
|
||||
}
|
||||
|
||||
// Helper method to tell us whether the clock is currently running for
|
||||
// discarding this image. Mainly for assertions.
|
||||
PRBool
|
||||
imgContainer::DiscardingActive() {
|
||||
return !!(mDiscardTrackerNode.prev || mDiscardTrackerNode.next);
|
||||
}
|
||||
|
||||
// Helper method to determine if we're storing the source data in a buffer
|
||||
// or just writing it directly to the decoder
|
||||
PRBool
|
||||
|
@ -2130,7 +2096,7 @@ imgContainer::InitDecoder (PRUint32 dFlags)
|
|||
NS_ABORT_IF_FALSE(!mDecoded, "Calling InitDecoder() but already decoded!");
|
||||
|
||||
// Since we're not decoded, we should not have a discard timer active
|
||||
NS_ABORT_IF_FALSE(!mDiscardTimer, "Discard Timer active in InitDecoder()!");
|
||||
NS_ABORT_IF_FALSE(!DiscardingActive(), "Discard Timer active in InitDecoder()!");
|
||||
|
||||
// Find and instantiate the decoder
|
||||
nsCAutoString decoderCID(NS_LITERAL_CSTRING("@mozilla.org/image/decoder;3?type=") +
|
||||
|
@ -2277,10 +2243,11 @@ imgContainer::WantDecodedFrames()
|
|||
{
|
||||
nsresult rv;
|
||||
|
||||
// If we can discard, we should have a timer already. reset it.
|
||||
// If we can discard, the clock should be running. Reset it.
|
||||
if (CanDiscard()) {
|
||||
NS_ABORT_IF_FALSE(mDiscardTimer, "Decoded and discardable but timer not set!");
|
||||
rv = ResetDiscardTimer();
|
||||
NS_ABORT_IF_FALSE(DiscardingActive(),
|
||||
"Decoded and discardable but discarding not activated!");
|
||||
rv = imgDiscardTracker::Reset(&mDiscardTrackerNode);
|
||||
CONTAINER_ENSURE_SUCCESS(rv);
|
||||
}
|
||||
|
||||
|
@ -2445,11 +2412,7 @@ imgContainer::LockImage()
|
|||
return NS_ERROR_FAILURE;
|
||||
|
||||
// Cancel the discard timer if it's there
|
||||
if (mDiscardTimer) {
|
||||
mDiscardTimer->Cancel();
|
||||
mDiscardTimer = nsnull; // It's wasteful to null out the discard timers each
|
||||
// time, but we'll wait to fix that until bug 502694.
|
||||
}
|
||||
imgDiscardTracker::Remove(&mDiscardTrackerNode);
|
||||
|
||||
// Increment the lock count
|
||||
mLockCount++;
|
||||
|
@ -2471,15 +2434,15 @@ imgContainer::UnlockImage()
|
|||
if (mLockCount == 0)
|
||||
return NS_ERROR_ABORT;
|
||||
|
||||
// We're locked, so we shouldn't have a discard timer set
|
||||
NS_ABORT_IF_FALSE(!mDiscardTimer, "Locked, but discard timer set!");
|
||||
// We're locked, so discarding should not be active
|
||||
NS_ABORT_IF_FALSE(!DiscardingActive(), "Locked, but discarding activated");
|
||||
|
||||
// Decrement our lock count
|
||||
mLockCount--;
|
||||
|
||||
// We now _might_ have one of the qualifications for discarding. Re-evaluate.
|
||||
if (CanDiscard()) {
|
||||
nsresult rv = ResetDiscardTimer();
|
||||
nsresult rv = imgDiscardTracker::Reset(&mDiscardTrackerNode);
|
||||
CONTAINER_ENSURE_SUCCESS(rv);
|
||||
}
|
||||
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
#include "nsTArray.h"
|
||||
#include "imgFrame.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "imgDiscardTracker.h"
|
||||
|
||||
#define NS_IMGCONTAINER_CID \
|
||||
{ /* c76ff2c1-9bf6-418a-b143-3340c00112f7 */ \
|
||||
|
@ -157,6 +158,9 @@ public:
|
|||
PRUint32 GetDecodedDataSize();
|
||||
PRUint32 GetSourceDataSize();
|
||||
|
||||
/* Triggers discarding. */
|
||||
void Discard();
|
||||
|
||||
private:
|
||||
struct Anim
|
||||
{
|
||||
|
@ -321,13 +325,14 @@ private: // data
|
|||
|
||||
// Discard members
|
||||
PRUint32 mLockCount;
|
||||
nsCOMPtr<nsITimer> mDiscardTimer;
|
||||
imgDiscardTrackerNode mDiscardTrackerNode;
|
||||
|
||||
// Source data members
|
||||
nsTArray<char> mSourceData;
|
||||
nsCString mSourceDataMimeType;
|
||||
|
||||
friend class imgDecodeWorker;
|
||||
friend class imgDiscardTracker;
|
||||
|
||||
// Decoder and friends
|
||||
nsCOMPtr<imgIDecoder> mDecoder;
|
||||
|
@ -353,10 +358,6 @@ private: // data
|
|||
|
||||
PRPackedBool mError:1; // Error handling
|
||||
|
||||
// Discard code
|
||||
nsresult ResetDiscardTimer();
|
||||
static void sDiscardTimerCallback(nsITimer *aTimer, void *aClosure);
|
||||
|
||||
// Decoding
|
||||
nsresult WantDecodedFrames();
|
||||
nsresult SyncDecode();
|
||||
|
@ -377,6 +378,7 @@ private: // data
|
|||
// Helpers
|
||||
void DoError();
|
||||
PRBool CanDiscard();
|
||||
PRBool DiscardingActive();
|
||||
PRBool StoringSourceData();
|
||||
|
||||
};
|
||||
|
|
|
@ -0,0 +1,215 @@
|
|||
/* -*- 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
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2001
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Bobby Holley <bobbyholley@gmail.com>
|
||||
*
|
||||
* 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 "nsComponentManagerUtils.h"
|
||||
#include "nsITimer.h"
|
||||
#include "imgContainer.h"
|
||||
#include "imgDiscardTracker.h"
|
||||
|
||||
static PRBool sInitialized = PR_FALSE;
|
||||
static PRBool sTimerOn = PR_FALSE;
|
||||
/* TODO - don't hardcode. See bug 478398. */
|
||||
static PRUint32 sMinDiscardTimeoutMs = 10000;
|
||||
static nsITimer *sTimer = nsnull;
|
||||
static struct imgDiscardTrackerNode sHead, sSentinel, sTail;
|
||||
|
||||
/*
|
||||
* Puts an image in the back of the tracker queue. If the image is already
|
||||
* in the tracker, this removes it first.
|
||||
*/
|
||||
nsresult
|
||||
imgDiscardTracker::Reset(imgDiscardTrackerNode *node)
|
||||
{
|
||||
nsresult rv;
|
||||
PRBool isSentinel = (node == &sSentinel);
|
||||
|
||||
// Sanity check the node.
|
||||
NS_ABORT_IF_FALSE(isSentinel || node->curr, "Node doesn't point to anything!");
|
||||
|
||||
// We should not call this function if we can't discard
|
||||
NS_ABORT_IF_FALSE(isSentinel || node->curr->CanDiscard(),
|
||||
"trying to reset discarding but can't discard!");
|
||||
|
||||
// As soon as an image becomes animated it is set non-discardable
|
||||
NS_ABORT_IF_FALSE(isSentinel || !node->curr->mAnim,
|
||||
"Trying to reset discarding on animated image!");
|
||||
|
||||
|
||||
// Initialize the first time through
|
||||
if (NS_UNLIKELY(!sInitialized)) {
|
||||
rv = Initialize();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// Remove the node if it's in the list.
|
||||
Remove(node);
|
||||
|
||||
// Append it to the list.
|
||||
node->prev = sTail.prev;
|
||||
node->next = &sTail;
|
||||
node->prev->next = sTail.prev = node;
|
||||
|
||||
// Make sure the timer is running
|
||||
rv = TimerOn();
|
||||
NS_ENSURE_SUCCESS(rv,rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes a node from the tracker. No-op if the node is currently untracked.
|
||||
*/
|
||||
void
|
||||
imgDiscardTracker::Remove(imgDiscardTrackerNode *node)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(node != nsnull, "Can't pass null node");
|
||||
|
||||
// If we're not in a list, we have nothing to do.
|
||||
if ((node->prev == nsnull) || (node->next == nsnull)) {
|
||||
NS_ABORT_IF_FALSE(node->prev == node->next,
|
||||
"Node is half in a list!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Connect around ourselves
|
||||
node->prev->next = node->next;
|
||||
node->next->prev = node->prev;
|
||||
|
||||
// Clean up the node we removed.
|
||||
node->prev = node->next = nsnull;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the tracker.
|
||||
*/
|
||||
nsresult
|
||||
imgDiscardTracker::Initialize()
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
// Set up the list. Head<->Sentinel<->Tail
|
||||
sHead.curr = sTail.curr = sSentinel.curr = nsnull;
|
||||
sHead.prev = sTail.next = nsnull;
|
||||
sHead.next = sTail.prev = &sSentinel;
|
||||
sSentinel.prev = &sHead;
|
||||
sSentinel.next = &sTail;
|
||||
|
||||
// Create and start the timer
|
||||
nsCOMPtr<nsITimer> t = do_CreateInstance("@mozilla.org/timer;1");
|
||||
NS_ENSURE_TRUE(t, NS_ERROR_OUT_OF_MEMORY);
|
||||
t.forget(&sTimer);
|
||||
rv = TimerOn();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Mark us as initialized
|
||||
sInitialized = PR_TRUE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shut down the tracker, deallocating the timer.
|
||||
*/
|
||||
void
|
||||
imgDiscardTracker::Shutdown()
|
||||
{
|
||||
if (sTimer) {
|
||||
sTimer->Cancel();
|
||||
NS_RELEASE(sTimer);
|
||||
sTimer = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the timer. No-op if the timer is already running.
|
||||
*/
|
||||
nsresult
|
||||
imgDiscardTracker::TimerOn()
|
||||
{
|
||||
// Nothing to do if the timer's already on.
|
||||
if (sTimerOn)
|
||||
return NS_OK;
|
||||
sTimerOn = PR_TRUE;
|
||||
|
||||
// Activate
|
||||
return sTimer->InitWithFuncCallback(TimerCallback,
|
||||
nsnull,
|
||||
sMinDiscardTimeoutMs,
|
||||
nsITimer::TYPE_REPEATING_SLACK);
|
||||
}
|
||||
|
||||
/*
|
||||
* Disables the timer. No-op if the timer isn't running.
|
||||
*/
|
||||
void
|
||||
imgDiscardTracker::TimerOff()
|
||||
{
|
||||
// Nothing to do if the timer's already off.
|
||||
if (!sTimerOn)
|
||||
return;
|
||||
sTimerOn = PR_FALSE;
|
||||
|
||||
// Deactivate
|
||||
sTimer->Cancel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Routine activated when the timer fires. This discards everything
|
||||
* in front of sentinel, and resets the sentinel to the back of the
|
||||
* list.
|
||||
*/
|
||||
void
|
||||
imgDiscardTracker::TimerCallback(nsITimer *aTimer, void *aClosure)
|
||||
{
|
||||
imgDiscardTrackerNode *node;
|
||||
|
||||
// Remove and discard everything before the sentinel
|
||||
for (node = sSentinel.prev; node != &sHead; node = sSentinel.prev) {
|
||||
NS_ABORT_IF_FALSE(node->curr, "empty node!");
|
||||
Remove(node);
|
||||
node->curr->Discard();
|
||||
}
|
||||
|
||||
// Append the sentinel to the back of the list
|
||||
Reset(&sSentinel);
|
||||
|
||||
// If there's nothing in front of the sentinel, the next callback
|
||||
// is guaranteed to be a no-op. Disable the timer as an optimization.
|
||||
if (sSentinel.prev == &sHead)
|
||||
TimerOff();
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
/* -*- 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
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2001
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Bobby Holley <bobbyholley@gmail.com>
|
||||
*
|
||||
* 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 ***** */
|
||||
|
||||
#ifndef __imgDiscardTracker_h__
|
||||
#define __imgDiscardTracker_h__
|
||||
|
||||
class imgContainer;
|
||||
class nsITimer;
|
||||
|
||||
// Struct to make an imgContainer insertable into the tracker list. This
|
||||
// is embedded within each imgContainer object, and we do 'this->curr = this'
|
||||
// on imgContainer construction. Thus, an imgContainer must always call
|
||||
// imgDiscardTracker::Remove() in its destructor to avoid having the tracker
|
||||
// point to bogus memory.
|
||||
struct imgDiscardTrackerNode
|
||||
{
|
||||
// Pointer to the imgContainer that this node tracks
|
||||
imgContainer *curr;
|
||||
|
||||
// Pointers to the previous and next nodes in the list
|
||||
imgDiscardTrackerNode *prev, *next;
|
||||
};
|
||||
|
||||
/**
|
||||
* This static class maintains a linked list of imgContainer nodes. When Reset()
|
||||
* is called, the node is removed from its position in the list (if it was there
|
||||
* before) and appended to the end. When Remove() is called, the node is removed
|
||||
* from the list. The timer fires once every MIN_DISCARD_TIMEOUT_MS ms. When it
|
||||
* does, it calls Discard() on each container preceding it, and then appends
|
||||
* itself to the end of the list. Thus, the discard timeout varies between
|
||||
* MIN_DISCARD_TIMEOUT_MS and 2*MIN_DISCARD_TIMEOUT_MS.
|
||||
*/
|
||||
|
||||
class imgDiscardTracker
|
||||
{
|
||||
public:
|
||||
static nsresult Reset(struct imgDiscardTrackerNode *node);
|
||||
static void Remove(struct imgDiscardTrackerNode *node);
|
||||
static void Shutdown();
|
||||
private:
|
||||
static nsresult Initialize();
|
||||
static nsresult TimerOn();
|
||||
static void TimerOff();
|
||||
static void TimerCallback(nsITimer *aTimer, void *aClosure);
|
||||
};
|
||||
|
||||
#endif /* __imgDiscardTracker_h__ */
|
Загрузка…
Ссылка в новой задаче