michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "gfxCachedTempSurface.h" michael@0: #include "gfxContext.h" michael@0: #include "mozilla/Attributes.h" michael@0: michael@0: class CachedSurfaceExpirationTracker MOZ_FINAL : michael@0: public nsExpirationTracker { michael@0: michael@0: public: michael@0: // With K = 2, this means that surfaces will be released when they are not michael@0: // used for 1-2 seconds. michael@0: enum { TIMEOUT_MS = 1000 }; michael@0: CachedSurfaceExpirationTracker() michael@0: : nsExpirationTracker(TIMEOUT_MS) {} michael@0: michael@0: ~CachedSurfaceExpirationTracker() { michael@0: AgeAllGenerations(); michael@0: } michael@0: michael@0: virtual void NotifyExpired(gfxCachedTempSurface* aSurface) { michael@0: RemoveObject(aSurface); michael@0: aSurface->Expire(); michael@0: } michael@0: michael@0: static void MarkSurfaceUsed(gfxCachedTempSurface* aSurface) michael@0: { michael@0: if (aSurface->GetExpirationState()->IsTracked()) { michael@0: sExpirationTracker->MarkUsed(aSurface); michael@0: return; michael@0: } michael@0: michael@0: if (!sExpirationTracker) { michael@0: sExpirationTracker = new CachedSurfaceExpirationTracker(); michael@0: } michael@0: sExpirationTracker->AddObject(aSurface); michael@0: } michael@0: michael@0: static void RemoveSurface(gfxCachedTempSurface* aSurface) michael@0: { michael@0: if (!sExpirationTracker) michael@0: return; michael@0: michael@0: if (aSurface->GetExpirationState()->IsTracked()) { michael@0: sExpirationTracker->RemoveObject(aSurface); michael@0: } michael@0: if (sExpirationTracker->IsEmpty()) { michael@0: delete sExpirationTracker; michael@0: sExpirationTracker = nullptr; michael@0: } michael@0: } michael@0: michael@0: private: michael@0: static CachedSurfaceExpirationTracker* sExpirationTracker; michael@0: }; michael@0: michael@0: CachedSurfaceExpirationTracker* michael@0: CachedSurfaceExpirationTracker::sExpirationTracker = nullptr; michael@0: michael@0: gfxCachedTempSurface::~gfxCachedTempSurface() michael@0: { michael@0: CachedSurfaceExpirationTracker::RemoveSurface(this); michael@0: } michael@0: michael@0: already_AddRefed michael@0: gfxCachedTempSurface::Get(gfxContentType aContentType, michael@0: const gfxRect& aRect, michael@0: gfxASurface* aSimilarTo) michael@0: { michael@0: if (mSurface) { michael@0: /* Verify the current buffer is valid for this purpose */ michael@0: if (mSize.width < aRect.width || mSize.height < aRect.height michael@0: || mSurface->GetContentType() != aContentType michael@0: || mType != aSimilarTo->GetType()) { michael@0: mSurface = nullptr; michael@0: } michael@0: } michael@0: michael@0: bool cleared = false; michael@0: if (!mSurface) { michael@0: mSize = gfxIntSize(int32_t(ceil(aRect.width)), int32_t(ceil(aRect.height))); michael@0: mSurface = aSimilarTo->CreateSimilarSurface(aContentType, mSize); michael@0: if (!mSurface) michael@0: return nullptr; michael@0: michael@0: cleared = true; michael@0: mType = aSimilarTo->GetType(); michael@0: } michael@0: mSurface->SetDeviceOffset(-aRect.TopLeft()); michael@0: michael@0: nsRefPtr ctx = new gfxContext(mSurface); michael@0: ctx->Rectangle(aRect); michael@0: ctx->Clip(); michael@0: if (!cleared && aContentType != gfxContentType::COLOR) { michael@0: ctx->SetOperator(gfxContext::OPERATOR_CLEAR); michael@0: ctx->Paint(); michael@0: ctx->SetOperator(gfxContext::OPERATOR_OVER); michael@0: } michael@0: michael@0: CachedSurfaceExpirationTracker::MarkSurfaceUsed(this); michael@0: michael@0: return ctx.forget(); michael@0: }