mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-11 23:54:18 +00:00
233 lines
6 KiB
C++
233 lines
6 KiB
C++
/*
|
|
==============================================================================
|
|
|
|
This file is part of the JUCE library - "Jules' Utility Class Extensions"
|
|
Copyright 2004-9 by Raw Material Software Ltd.
|
|
|
|
------------------------------------------------------------------------------
|
|
|
|
JUCE can be redistributed and/or modified under the terms of the GNU General
|
|
Public License (Version 2), as published by the Free Software Foundation.
|
|
A copy of the license is included in the JUCE distribution, or can be found
|
|
online at www.gnu.org/licenses.
|
|
|
|
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
------------------------------------------------------------------------------
|
|
|
|
To release a closed-source product which uses JUCE, commercial licenses are
|
|
available: visit www.rawmaterialsoftware.com/juce for more information.
|
|
|
|
==============================================================================
|
|
*/
|
|
|
|
#include "../../../core/juce_StandardHeader.h"
|
|
|
|
BEGIN_JUCE_NAMESPACE
|
|
|
|
#include "juce_ImageCache.h"
|
|
#include "juce_ImageFileFormat.h"
|
|
#include "../../../threads/juce_ScopedLock.h"
|
|
|
|
|
|
//==============================================================================
|
|
struct ImageCacheItem
|
|
{
|
|
ScopedPointer <Image> image;
|
|
int64 hashCode;
|
|
int refCount;
|
|
uint32 releaseTime;
|
|
|
|
juce_UseDebuggingNewOperator
|
|
};
|
|
|
|
//==============================================================================
|
|
static ImageCache* instance = 0;
|
|
static int cacheTimeout = 5000;
|
|
|
|
|
|
ImageCache::ImageCache()
|
|
{
|
|
}
|
|
|
|
ImageCache::~ImageCache()
|
|
{
|
|
jassert (instance == this);
|
|
instance = 0;
|
|
}
|
|
|
|
Image* ImageCache::getFromHashCode (const int64 hashCode)
|
|
{
|
|
if (instance != 0)
|
|
{
|
|
const ScopedLock sl (instance->lock);
|
|
|
|
for (int i = instance->images.size(); --i >= 0;)
|
|
{
|
|
ImageCacheItem* const ci = instance->images.getUnchecked(i);
|
|
|
|
if (ci->hashCode == hashCode)
|
|
{
|
|
ci->refCount++;
|
|
return ci->image;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void ImageCache::addImageToCache (Image* const image,
|
|
const int64 hashCode)
|
|
{
|
|
if (image != 0)
|
|
{
|
|
if (instance == 0)
|
|
instance = new ImageCache();
|
|
|
|
ImageCacheItem* const newC = new ImageCacheItem();
|
|
newC->hashCode = hashCode;
|
|
newC->image = image;
|
|
newC->refCount = 1;
|
|
newC->releaseTime = 0;
|
|
|
|
const ScopedLock sl (instance->lock);
|
|
instance->images.add (newC);
|
|
}
|
|
}
|
|
|
|
void ImageCache::release (Image* const imageToRelease)
|
|
{
|
|
if (imageToRelease != 0 && instance != 0)
|
|
{
|
|
const ScopedLock sl (instance->lock);
|
|
|
|
for (int i = instance->images.size(); --i >= 0;)
|
|
{
|
|
ImageCacheItem* const ci = instance->images.getUnchecked(i);
|
|
|
|
if ((Image*) ci->image == imageToRelease)
|
|
{
|
|
if (--(ci->refCount) == 0)
|
|
ci->releaseTime = Time::getApproximateMillisecondCounter();
|
|
|
|
if (! instance->isTimerRunning())
|
|
instance->startTimer (999);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ImageCache::releaseOrDelete (Image* const imageToRelease)
|
|
{
|
|
if (isImageInCache (imageToRelease))
|
|
release (imageToRelease);
|
|
else
|
|
delete imageToRelease;
|
|
}
|
|
|
|
bool ImageCache::isImageInCache (Image* const imageToLookFor)
|
|
{
|
|
if (instance != 0)
|
|
{
|
|
const ScopedLock sl (instance->lock);
|
|
|
|
for (int i = instance->images.size(); --i >= 0;)
|
|
if ((Image*) instance->images.getUnchecked(i)->image == imageToLookFor)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void ImageCache::incReferenceCount (Image* const image)
|
|
{
|
|
if (instance != 0)
|
|
{
|
|
const ScopedLock sl (instance->lock);
|
|
|
|
for (int i = instance->images.size(); --i >= 0;)
|
|
{
|
|
ImageCacheItem* const ci = (ImageCacheItem*) instance->images.getUnchecked(i);
|
|
|
|
if ((Image*) ci->image == image)
|
|
{
|
|
ci->refCount++;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
jassertfalse // (trying to inc the ref count of an image that's not in the cache)
|
|
}
|
|
|
|
void ImageCache::timerCallback()
|
|
{
|
|
int numberStillNeedingReleasing = 0;
|
|
const unsigned int now = Time::getApproximateMillisecondCounter();
|
|
|
|
const ScopedLock sl (lock);
|
|
|
|
for (int i = images.size(); --i >= 0;)
|
|
{
|
|
ImageCacheItem* const ci = images.getUnchecked(i);
|
|
|
|
if (ci->refCount <= 0)
|
|
{
|
|
if (now > ci->releaseTime + cacheTimeout
|
|
|| now < ci->releaseTime - 1000)
|
|
{
|
|
images.remove (i);
|
|
}
|
|
else
|
|
{
|
|
++numberStillNeedingReleasing;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (numberStillNeedingReleasing == 0)
|
|
stopTimer();
|
|
}
|
|
|
|
Image* ImageCache::getFromFile (const File& file)
|
|
{
|
|
const int64 hashCode = file.hashCode64();
|
|
Image* image = getFromHashCode (hashCode);
|
|
|
|
if (image == 0)
|
|
{
|
|
image = ImageFileFormat::loadFrom (file);
|
|
addImageToCache (image, hashCode);
|
|
}
|
|
|
|
return image;
|
|
}
|
|
|
|
Image* ImageCache::getFromMemory (const void* imageData,
|
|
const int dataSize)
|
|
{
|
|
const int64 hashCode = (int64) (pointer_sized_int) imageData;
|
|
|
|
Image* image = getFromHashCode (hashCode);
|
|
|
|
if (image == 0)
|
|
{
|
|
image = ImageFileFormat::loadFrom (imageData, dataSize);
|
|
addImageToCache (image, hashCode);
|
|
}
|
|
|
|
return image;
|
|
}
|
|
|
|
void ImageCache::setCacheTimeout (const int millisecs)
|
|
{
|
|
cacheTimeout = millisecs;
|
|
}
|
|
|
|
|
|
END_JUCE_NAMESPACE
|