Files
palemoon27/dom/canvas/CanvasImageCache.cpp
T
roytam1 0e560e6a54 import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1214139 - Connect to HFP, A2DP, and AVRCP if CoD is invalid, r=shuang (459ec4b233)
- bits of Bug 1156229: Make ref-counted class destructors non-public (dc7a57b259)
- Bug 1228909 - Fix PDU packing in |ClientSetAdvDataCmd| for GATT API. r=brsun (08d7ecc898)
- Bug 1228946: Remove '#if 0' block from Bluetooth module, r=joliu (b5f0503541)
- Bug 1209085: Replace simple init ops by |UnpackPDUInitOp| in Blutooth HFP backend, r=joliu (5783c5826c)
- Bug 1211948: Remove registry interfaces from |BluetoothDaemonProtocol|, r=brsun (c7b21bac78)
- Bug 1223804 - remove unused container macro; r=btian (de2e51ddec)
- Bug 1228471 - use Endian.h to write filename and handleId into OBEX packet, r=shuang (38225c81ac)
- Bug 1211435: Cleanup AVRCP interfaces when Bluetooth adapter gets switched off, r=shuang (52d318d250)
- cleanup old BT files (93589e8581)
- Bug 1132343 - Patch2: Replace setPairingConfirmation() with accept() in marionette test due to API change. r=shuang (37645d2d0f)
- Bug 1139774 - Add a function to wait promise for bluetooth adapter creation. r=shuang (cb66b22bc7)
- var-let (aedeed6516)
- Bug 1178654 - Fix the uuid length when parsing bluetooth low energy advertisement data. r=btian (88118d5f2f)
- Bug 1170076 - Use snprintf instead of sprintf when parsing bluetooth GATT advertisement data. r=shuang (3ede2b3a98)
- Bug 1166231 - patch 2 - BluetoothOppManager blob uses fixed CLOSED TREE (559f9cdd90)
- Bug 1178076 - MessagePort should not set listeners nor workerFeature when neutered, r=smaug (ac527766ed)
- Bug 1177727 - MessagePort should call RemoveObserver before calling Release(), r=mccr8 (8d59127b35)
- Bug 1224825 - Race condition in MessagePort::close - patch 1, r=smaug (c655fbfec7)
- Bug 1224825 - Race condition in MessagePort::close - patch 2, r=smaug (fbb702e748)
- Bug 1187115 - Replace nsBaseHashtable::EnumerateRead() calls in dom/{bluetooth,messagechannel}/ with iterators. r=khuey. (40e8a81d13)
- Bug 1185531 - Wrong NS_WARN_IF use in MessagePort.cpp, r=smaug (47077031e4)
- Bug 1181595 - Improve null checks in MessagePort::RemoveDocFromBFCache, r=smaug (f9964384e9)
- fix misspatch of 1180555 (0f9e3b5383)
- Bug 1181595 - MessagePortChild should check if the MessagePort is still alive before dispatching messages, r=smaug (3dd0ca3bac)
- namespace fix (1288e86370)
- Bug 1224061: Fuck bluetooth. r=me CLOSED TREE (b952a5e008)
- Bug 1159650 - Remove incorrect value assertions in BluetoothGattCharacteristic and BluetoothGattDescriptor. r=btian (97376c7d95)
- missing bit of 1140952 (da07ba9392)
- Bug 1194153 - Chrome Registry's convertChromeURL shouldn't crash when given a null url, r=bsmedberg. (aeea438643)
- Bug 1203900 - Fix cycle collection and array buffer creation bug in the implementation of MediaKeyMessageEvent, MediaEncryptedEvent, and BluetoothLeDeviceEvent. r=bz (e30c13f078)
- Bug 1137601 - Fire onadapterremoved before onattributechanged in BluetoothManager, f=jocelyn, r=shuang (4920faebd8)
- Bug 1228479 - Remove redundant blob handling in BluetoothMapRequestHandle::ReplyToFolderListing, r=shuang (a4cda2f71c)
- Bug 1227380 - Move LOCAL_INCLUDES and CXXFLAGS to moz.build in dom/bindings/. r=mshal (2ba98b8c3b)
- Bug 1227987: Simplify CGDOMJSClass::define. r=bz. (bc2686e68a)
- Bug 1229176 - make check for ChromeOnly interfaces for header inclusion more complete; r=bz (506d0b9572)
- Bug 1230291. Correctly include nsContentUtils when generating a manual hasInstance with nsIDOM* stuff or when we have a JS-implemented interface with clearable cached attrs (852e9c3c9e)
- Bug 1229031. Make sure to not init binding pref var caches on worker threads. r=smaug (ae495709cd)
- Bug 1226448. Fix Optional::Construct to do perfect forwarding, and fix the dictionary assignment operator code for members that can have missing values to not try constructing and already constructed member. r=jib (e67eff372e)
- bug 1196460 - add class for wrapping proxies of document accessibles r=surkov (8ec0276e4b)
- Bug 1210549 - Make proxied accessibles defunct when proxy dies r=tbsaunde (ab0fabf2a4)
- bug 1196460 - make the ctor of HyperTextProxyAccessiblewrap public r=surkov (2f3c9ef441)
- bug 1196460 - make IsDoc() return true for wrappers of proxied documents r=surkov (59f0d68130)
- bug 1196460 - provide mapping from id to accessible in DocProxyAccessibleWrap (359a45ddef)
- bug 1168204 - Expose more interfaces to windows for proxied accessibles r=davidb (9db556118a)
- bug 1213327 - expose iAccessibleHyperlink on proxied accessibles r=davidb (935ae7d3df)
- bug 1159828 - make ia2Hyperlink use proxies r=davidb (2d9982d7e3)
- bug 1168202 - ia2AccessibleHyperlink::get_anchor needs to give the caller a reference to the anchor r=davidb (7ea462a6ce)
- bug 1159741 - make ia2HyperText use proxies r=davidb (47fa0bb381)
- bug 1159850 - make ia2Accessiblevalue use proxies r=davidb (b1731c4019)
- Bug 830801 - Part 2. Remove NOMINMAX define from moz.build. r=mshal (0d8375058c)
- Bug 1166169 - Add MOZ_GONK_MEDIACODEC in configure and define it in moz.build. r=cpearce, r=glandium (5ffba1b95d)
- Bug 1200492 - Do not add the top source directory to the include path in dom/canvas; r=gps (eb72451eaf)
- Bug 1226868: Fix test metadata to correctly check things and verify that it has done so afterwards. r=bz (5354c2b3fc)
- Bug 1220565 - Remove non-standard comprehension from addon-sdk/. r=mossop (95a732e149)
- Bug 1146926: Allow attaching a worker to a CPOW window without invoking CPOW operations. r=gabor (590192deec)
- Bug 1228975 - Remove Array generics usage from Places code. r=mak (dd5cc6efca)
- Bug 1217225 - Differentiate between images optimized for skia and skia-gl in the CanvasImageCache. r=mstange (79eaf016f8)
- Bug 1213491 - Change CanvasRenderingContext2D::ContextState::clipsPushed to an nsTArray. r=nical (ae43fc69d2)
- Bug 1163105 - Flush frames before building the filter. r=roc (05b2980b24)
- Bug 655328 - clip canvas drawImage source/dest rectangles instead of throwing IndexSizeError. r=jmuizelaar (9f5274375b)
- Bug 696630 - Take imageSmoothingEnabled into account when creating pattern fills. r=mattwoodrow (f2c99c9cfb)
- Bug 1228287 - Make sure we can't do SkiaGL without the pref set. r=benwa (552495d3c5)
- Bug 1222083 - verify that a Skia GL context is actually available before trying to use it in Canvas2D drawImage. r=jmuizelaar (1c8cf4ba63)
- Bug 1190210 - Part 1: Avoid wrong memory accessing in CropAndCopyDataSourceSurface(). r=smaug (a035874da0)
- Bug 1190210 - Part 2: Make sure the size of created ImageBitmap is the same as the intented cropping area. r=roc (5a80cf8dae)
- Bug 1190210 - Part 3: Fix the assertion in create-from-blob case. r=smaug (4ff1045b98)
- Bug 1190210 - Part 4: Test cases. r=smaug (8ef4c6f293)
- Bug 1224647 - part1 - remove ErrorResult in the creating ImageBitmap from ImageData code path; r=bz (78792f46d1)
- Bug 1224647 - part2 - remove ErrorResult in the creating ImageBitmap from Blob code path; r=bz (de719d4eca)
- Bug 1215414 - Fix ClearBuffer taking TypedArrays. r=jgilbert (22b34bd418)
- Bug 1209384 - Check active query has same type as target. r=jgilbert (483fbce55a)
- Bug 1220783. Map GetUniformIndices names. r=jgilbert (f7c7b03a4d)
- Bug 1228488 - Return INVALID_ENUM for GL_UNIFORM_NAME_LENGTH. r=jgilbert (826a05df79)
- Bug 1228949 - Fix WebGLBuffer content type when the target is LOCAL_GL_COPY_READ_BUFFER or LOCAL_GL_COPY_WRITE_BUFFER. r=jgilbert (a6ecdbce69)
- Bug 1186666 - clamp gl ClearDepth() value to [0,1]. r=jgilbert (c0ee2d0375)
- Bug 1171021. Rewrite SetFullAlpha to choose one method of iterating. (cd48866843)
2023-05-23 09:38:14 +08:00

376 lines
10 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CanvasImageCache.h"
#include "nsIImageLoadingContent.h"
#include "nsExpirationTracker.h"
#include "imgIRequest.h"
#include "mozilla/dom/Element.h"
#include "nsTHashtable.h"
#include "mozilla/dom/HTMLCanvasElement.h"
#include "nsContentUtils.h"
#include "mozilla/Preferences.h"
#include "mozilla/gfx/2D.h"
#include "gfx2DGlue.h"
namespace mozilla {
using namespace dom;
using namespace gfx;
struct ImageCacheKey {
ImageCacheKey(Element* aImage,
HTMLCanvasElement* aCanvas,
bool aIsAccelerated)
: mImage(aImage)
, mCanvas(aCanvas)
, mIsAccelerated(aIsAccelerated)
{}
Element* mImage;
HTMLCanvasElement* mCanvas;
bool mIsAccelerated;
};
struct ImageCacheEntryData {
ImageCacheEntryData(const ImageCacheEntryData& aOther)
: mImage(aOther.mImage)
, mILC(aOther.mILC)
, mCanvas(aOther.mCanvas)
, mIsAccelerated(aOther.mIsAccelerated)
, mRequest(aOther.mRequest)
, mSourceSurface(aOther.mSourceSurface)
, mSize(aOther.mSize)
{}
explicit ImageCacheEntryData(const ImageCacheKey& aKey)
: mImage(aKey.mImage)
, mILC(nullptr)
, mCanvas(aKey.mCanvas)
, mIsAccelerated(aKey.mIsAccelerated)
{}
nsExpirationState* GetExpirationState() { return &mState; }
size_t SizeInBytes() { return mSize.width * mSize.height * 4; }
// Key
RefPtr<Element> mImage;
nsIImageLoadingContent* mILC;
RefPtr<HTMLCanvasElement> mCanvas;
bool mIsAccelerated;
// Value
nsCOMPtr<imgIRequest> mRequest;
RefPtr<SourceSurface> mSourceSurface;
IntSize mSize;
nsExpirationState mState;
};
class ImageCacheEntry : public PLDHashEntryHdr {
public:
typedef ImageCacheKey KeyType;
typedef const ImageCacheKey* KeyTypePointer;
explicit ImageCacheEntry(const KeyType* aKey) :
mData(new ImageCacheEntryData(*aKey)) {}
ImageCacheEntry(const ImageCacheEntry &toCopy) :
mData(new ImageCacheEntryData(*toCopy.mData)) {}
~ImageCacheEntry() {}
bool KeyEquals(KeyTypePointer key) const
{
return mData->mImage == key->mImage &&
mData->mCanvas == key->mCanvas &&
mData->mIsAccelerated == key->mIsAccelerated;
}
static KeyTypePointer KeyToPointer(KeyType& key) { return &key; }
static PLDHashNumber HashKey(KeyTypePointer key)
{
return HashGeneric(key->mImage, key->mCanvas, key->mIsAccelerated);
}
enum { ALLOW_MEMMOVE = true };
nsAutoPtr<ImageCacheEntryData> mData;
};
struct SimpleImageCacheKey {
SimpleImageCacheKey(const imgIRequest* aImage,
bool aIsAccelerated)
: mImage(aImage)
, mIsAccelerated(aIsAccelerated)
{}
const imgIRequest* mImage;
bool mIsAccelerated;
};
class SimpleImageCacheEntry : public PLDHashEntryHdr {
public:
typedef SimpleImageCacheKey KeyType;
typedef const SimpleImageCacheKey* KeyTypePointer;
explicit SimpleImageCacheEntry(KeyTypePointer aKey)
: mRequest(const_cast<imgIRequest*>(aKey->mImage))
, mIsAccelerated(aKey->mIsAccelerated)
{}
SimpleImageCacheEntry(const SimpleImageCacheEntry &toCopy)
: mRequest(toCopy.mRequest)
, mIsAccelerated(toCopy.mIsAccelerated)
, mSourceSurface(toCopy.mSourceSurface)
{}
~SimpleImageCacheEntry() {}
bool KeyEquals(KeyTypePointer key) const
{
return key->mImage == mRequest && key->mIsAccelerated == mIsAccelerated;
}
static KeyTypePointer KeyToPointer(KeyType& key) { return &key; }
static PLDHashNumber HashKey(KeyTypePointer key)
{
return HashGeneric(key->mImage, key->mIsAccelerated);
}
enum { ALLOW_MEMMOVE = true };
nsCOMPtr<imgIRequest> mRequest;
bool mIsAccelerated;
RefPtr<SourceSurface> mSourceSurface;
};
static bool sPrefsInitialized = false;
static int32_t sCanvasImageCacheLimit = 0;
class ImageCacheObserver;
class ImageCache final : public nsExpirationTracker<ImageCacheEntryData,4> {
public:
// We use 3 generations of 1 second each to get a 2-3 seconds timeout.
enum { GENERATION_MS = 1000 };
ImageCache();
~ImageCache();
virtual void NotifyExpired(ImageCacheEntryData* aObject)
{
mTotal -= aObject->SizeInBytes();
RemoveObject(aObject);
// Deleting the entry will delete aObject since the entry owns aObject
mSimpleCache.RemoveEntry(SimpleImageCacheKey(aObject->mRequest, aObject->mIsAccelerated));
mCache.RemoveEntry(ImageCacheKey(aObject->mImage, aObject->mCanvas, aObject->mIsAccelerated));
}
nsTHashtable<ImageCacheEntry> mCache;
nsTHashtable<SimpleImageCacheEntry> mSimpleCache;
size_t mTotal;
RefPtr<ImageCacheObserver> mImageCacheObserver;
};
static ImageCache* gImageCache = nullptr;
// Listen memory-pressure event for image cache purge
class ImageCacheObserver final : public nsIObserver
{
public:
NS_DECL_ISUPPORTS
explicit ImageCacheObserver(ImageCache* aImageCache)
: mImageCache(aImageCache)
{
RegisterMemoryPressureEvent();
}
void Destroy()
{
UnregisterMemoryPressureEvent();
mImageCache = nullptr;
}
NS_IMETHODIMP Observe(nsISupports* aSubject,
const char* aTopic,
const char16_t* aSomeData) override
{
if (!mImageCache || strcmp(aTopic, "memory-pressure")) {
return NS_OK;
}
mImageCache->AgeAllGenerations();
return NS_OK;
}
private:
virtual ~ImageCacheObserver()
{
}
void RegisterMemoryPressureEvent()
{
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
MOZ_ASSERT(observerService);
if (observerService) {
observerService->AddObserver(this, "memory-pressure", false);
}
}
void UnregisterMemoryPressureEvent()
{
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
// Do not assert on observerService here. This might be triggered by
// the cycle collector at a late enough time, that XPCOM services are
// no longer available. See bug 1029504.
if (observerService) {
observerService->RemoveObserver(this, "memory-pressure");
}
}
ImageCache* mImageCache;
};
NS_IMPL_ISUPPORTS(ImageCacheObserver, nsIObserver)
class CanvasImageCacheShutdownObserver final : public nsIObserver
{
~CanvasImageCacheShutdownObserver() {}
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
};
ImageCache::ImageCache()
: nsExpirationTracker<ImageCacheEntryData,4>(GENERATION_MS, "ImageCache")
, mTotal(0)
{
if (!sPrefsInitialized) {
sPrefsInitialized = true;
Preferences::AddIntVarCache(&sCanvasImageCacheLimit, "canvas.image.cache.limit", 0);
}
mImageCacheObserver = new ImageCacheObserver(this);
MOZ_RELEASE_ASSERT(mImageCacheObserver, "Can't alloc ImageCacheObserver");
}
ImageCache::~ImageCache() {
AgeAllGenerations();
mImageCacheObserver->Destroy();
}
void
CanvasImageCache::NotifyDrawImage(Element* aImage,
HTMLCanvasElement* aCanvas,
imgIRequest* aRequest,
SourceSurface* aSource,
const IntSize& aSize,
bool aIsAccelerated)
{
if (!gImageCache) {
gImageCache = new ImageCache();
nsContentUtils::RegisterShutdownObserver(new CanvasImageCacheShutdownObserver());
}
ImageCacheEntry* entry =
gImageCache->mCache.PutEntry(ImageCacheKey(aImage, aCanvas, aIsAccelerated));
if (entry) {
if (entry->mData->mSourceSurface) {
// We are overwriting an existing entry.
gImageCache->mTotal -= entry->mData->SizeInBytes();
gImageCache->RemoveObject(entry->mData);
gImageCache->mSimpleCache.RemoveEntry(SimpleImageCacheKey(entry->mData->mRequest, entry->mData->mIsAccelerated));
}
gImageCache->AddObject(entry->mData);
nsCOMPtr<nsIImageLoadingContent> ilc = do_QueryInterface(aImage);
if (ilc) {
ilc->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
getter_AddRefs(entry->mData->mRequest));
}
entry->mData->mILC = ilc;
entry->mData->mSourceSurface = aSource;
entry->mData->mSize = aSize;
gImageCache->mTotal += entry->mData->SizeInBytes();
if (entry->mData->mRequest) {
SimpleImageCacheEntry* simpleentry =
gImageCache->mSimpleCache.PutEntry(SimpleImageCacheKey(entry->mData->mRequest, aIsAccelerated));
simpleentry->mSourceSurface = aSource;
}
}
if (!sCanvasImageCacheLimit)
return;
// Expire the image cache early if its larger than we want it to be.
while (gImageCache->mTotal > size_t(sCanvasImageCacheLimit))
gImageCache->AgeOneGeneration();
}
SourceSurface*
CanvasImageCache::Lookup(Element* aImage,
HTMLCanvasElement* aCanvas,
gfx::IntSize* aSize,
bool aIsAccelerated)
{
if (!gImageCache)
return nullptr;
ImageCacheEntry* entry =
gImageCache->mCache.GetEntry(ImageCacheKey(aImage, aCanvas, aIsAccelerated));
if (!entry || !entry->mData->mILC)
return nullptr;
nsCOMPtr<imgIRequest> request;
entry->mData->mILC->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST, getter_AddRefs(request));
if (request != entry->mData->mRequest)
return nullptr;
gImageCache->MarkUsed(entry->mData);
*aSize = entry->mData->mSize;
return entry->mData->mSourceSurface;
}
SourceSurface*
CanvasImageCache::SimpleLookup(Element* aImage,
bool aIsAccelerated)
{
if (!gImageCache)
return nullptr;
nsCOMPtr<imgIRequest> request;
nsCOMPtr<nsIImageLoadingContent> ilc = do_QueryInterface(aImage);
if (!ilc)
return nullptr;
ilc->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
getter_AddRefs(request));
if (!request)
return nullptr;
SimpleImageCacheEntry* entry = gImageCache->mSimpleCache.GetEntry(SimpleImageCacheKey(request, aIsAccelerated));
if (!entry)
return nullptr;
return entry->mSourceSurface;
}
NS_IMPL_ISUPPORTS(CanvasImageCacheShutdownObserver, nsIObserver)
NS_IMETHODIMP
CanvasImageCacheShutdownObserver::Observe(nsISupports *aSubject,
const char *aTopic,
const char16_t *aData)
{
if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
delete gImageCache;
gImageCache = nullptr;
nsContentUtils::UnregisterShutdownObserver(this);
}
return NS_OK;
}
} // namespace mozilla