|
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- |
|
2 * This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #include "gfxCachedTempSurface.h" |
|
7 #include "gfxContext.h" |
|
8 #include "mozilla/Attributes.h" |
|
9 |
|
10 class CachedSurfaceExpirationTracker MOZ_FINAL : |
|
11 public nsExpirationTracker<gfxCachedTempSurface,2> { |
|
12 |
|
13 public: |
|
14 // With K = 2, this means that surfaces will be released when they are not |
|
15 // used for 1-2 seconds. |
|
16 enum { TIMEOUT_MS = 1000 }; |
|
17 CachedSurfaceExpirationTracker() |
|
18 : nsExpirationTracker<gfxCachedTempSurface,2>(TIMEOUT_MS) {} |
|
19 |
|
20 ~CachedSurfaceExpirationTracker() { |
|
21 AgeAllGenerations(); |
|
22 } |
|
23 |
|
24 virtual void NotifyExpired(gfxCachedTempSurface* aSurface) { |
|
25 RemoveObject(aSurface); |
|
26 aSurface->Expire(); |
|
27 } |
|
28 |
|
29 static void MarkSurfaceUsed(gfxCachedTempSurface* aSurface) |
|
30 { |
|
31 if (aSurface->GetExpirationState()->IsTracked()) { |
|
32 sExpirationTracker->MarkUsed(aSurface); |
|
33 return; |
|
34 } |
|
35 |
|
36 if (!sExpirationTracker) { |
|
37 sExpirationTracker = new CachedSurfaceExpirationTracker(); |
|
38 } |
|
39 sExpirationTracker->AddObject(aSurface); |
|
40 } |
|
41 |
|
42 static void RemoveSurface(gfxCachedTempSurface* aSurface) |
|
43 { |
|
44 if (!sExpirationTracker) |
|
45 return; |
|
46 |
|
47 if (aSurface->GetExpirationState()->IsTracked()) { |
|
48 sExpirationTracker->RemoveObject(aSurface); |
|
49 } |
|
50 if (sExpirationTracker->IsEmpty()) { |
|
51 delete sExpirationTracker; |
|
52 sExpirationTracker = nullptr; |
|
53 } |
|
54 } |
|
55 |
|
56 private: |
|
57 static CachedSurfaceExpirationTracker* sExpirationTracker; |
|
58 }; |
|
59 |
|
60 CachedSurfaceExpirationTracker* |
|
61 CachedSurfaceExpirationTracker::sExpirationTracker = nullptr; |
|
62 |
|
63 gfxCachedTempSurface::~gfxCachedTempSurface() |
|
64 { |
|
65 CachedSurfaceExpirationTracker::RemoveSurface(this); |
|
66 } |
|
67 |
|
68 already_AddRefed<gfxContext> |
|
69 gfxCachedTempSurface::Get(gfxContentType aContentType, |
|
70 const gfxRect& aRect, |
|
71 gfxASurface* aSimilarTo) |
|
72 { |
|
73 if (mSurface) { |
|
74 /* Verify the current buffer is valid for this purpose */ |
|
75 if (mSize.width < aRect.width || mSize.height < aRect.height |
|
76 || mSurface->GetContentType() != aContentType |
|
77 || mType != aSimilarTo->GetType()) { |
|
78 mSurface = nullptr; |
|
79 } |
|
80 } |
|
81 |
|
82 bool cleared = false; |
|
83 if (!mSurface) { |
|
84 mSize = gfxIntSize(int32_t(ceil(aRect.width)), int32_t(ceil(aRect.height))); |
|
85 mSurface = aSimilarTo->CreateSimilarSurface(aContentType, mSize); |
|
86 if (!mSurface) |
|
87 return nullptr; |
|
88 |
|
89 cleared = true; |
|
90 mType = aSimilarTo->GetType(); |
|
91 } |
|
92 mSurface->SetDeviceOffset(-aRect.TopLeft()); |
|
93 |
|
94 nsRefPtr<gfxContext> ctx = new gfxContext(mSurface); |
|
95 ctx->Rectangle(aRect); |
|
96 ctx->Clip(); |
|
97 if (!cleared && aContentType != gfxContentType::COLOR) { |
|
98 ctx->SetOperator(gfxContext::OPERATOR_CLEAR); |
|
99 ctx->Paint(); |
|
100 ctx->SetOperator(gfxContext::OPERATOR_OVER); |
|
101 } |
|
102 |
|
103 CachedSurfaceExpirationTracker::MarkSurfaceUsed(this); |
|
104 |
|
105 return ctx.forget(); |
|
106 } |