|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- |
|
2 * |
|
3 * This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 #ifndef imgFrame_h |
|
8 #define imgFrame_h |
|
9 |
|
10 #include "mozilla/MemoryReporting.h" |
|
11 #include "mozilla/Mutex.h" |
|
12 #include "mozilla/VolatileBuffer.h" |
|
13 #include "nsRect.h" |
|
14 #include "nsPoint.h" |
|
15 #include "nsSize.h" |
|
16 #include "gfxPattern.h" |
|
17 #include "gfxDrawable.h" |
|
18 #include "gfxImageSurface.h" |
|
19 #if defined(XP_WIN) |
|
20 #include "gfxWindowsSurface.h" |
|
21 #elif defined(XP_MACOSX) |
|
22 #include "gfxQuartzImageSurface.h" |
|
23 #endif |
|
24 #include "nsAutoPtr.h" |
|
25 #include "imgIContainer.h" |
|
26 #include "gfxColor.h" |
|
27 |
|
28 /* |
|
29 * This creates a gfxImageSurface which will unlock the buffer on destruction |
|
30 */ |
|
31 |
|
32 class LockedImageSurface |
|
33 { |
|
34 public: |
|
35 static gfxImageSurface * |
|
36 CreateSurface(mozilla::VolatileBuffer *vbuf, |
|
37 const gfxIntSize& size, |
|
38 gfxImageFormat format); |
|
39 static mozilla::TemporaryRef<mozilla::VolatileBuffer> |
|
40 AllocateBuffer(const gfxIntSize& size, gfxImageFormat format); |
|
41 }; |
|
42 |
|
43 class imgFrame |
|
44 { |
|
45 public: |
|
46 imgFrame(); |
|
47 ~imgFrame(); |
|
48 |
|
49 nsresult Init(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight, gfxImageFormat aFormat, uint8_t aPaletteDepth = 0); |
|
50 nsresult Optimize(); |
|
51 |
|
52 bool Draw(gfxContext *aContext, GraphicsFilter aFilter, |
|
53 const gfxMatrix &aUserSpaceToImageSpace, const gfxRect& aFill, |
|
54 const nsIntMargin &aPadding, const nsIntRect &aSubimage, |
|
55 uint32_t aImageFlags = imgIContainer::FLAG_NONE); |
|
56 |
|
57 nsresult ImageUpdated(const nsIntRect &aUpdateRect); |
|
58 bool GetIsDirty() const; |
|
59 |
|
60 nsIntRect GetRect() const; |
|
61 gfxImageFormat GetFormat() const; |
|
62 bool GetNeedsBackground() const; |
|
63 uint32_t GetImageBytesPerRow() const; |
|
64 uint32_t GetImageDataLength() const; |
|
65 bool GetIsPaletted() const; |
|
66 bool GetHasAlpha() const; |
|
67 void GetImageData(uint8_t **aData, uint32_t *length) const; |
|
68 uint8_t* GetImageData() const; |
|
69 void GetPaletteData(uint32_t **aPalette, uint32_t *length) const; |
|
70 uint32_t* GetPaletteData() const; |
|
71 |
|
72 int32_t GetRawTimeout() const; |
|
73 void SetRawTimeout(int32_t aTimeout); |
|
74 |
|
75 int32_t GetFrameDisposalMethod() const; |
|
76 void SetFrameDisposalMethod(int32_t aFrameDisposalMethod); |
|
77 int32_t GetBlendMethod() const; |
|
78 void SetBlendMethod(int32_t aBlendMethod); |
|
79 bool ImageComplete() const; |
|
80 |
|
81 void SetHasNoAlpha(); |
|
82 void SetAsNonPremult(bool aIsNonPremult); |
|
83 |
|
84 bool GetCompositingFailed() const; |
|
85 void SetCompositingFailed(bool val); |
|
86 |
|
87 nsresult LockImageData(); |
|
88 nsresult UnlockImageData(); |
|
89 void ApplyDirtToSurfaces(); |
|
90 |
|
91 void SetDiscardable(); |
|
92 |
|
93 nsresult GetSurface(gfxASurface **aSurface) |
|
94 { |
|
95 *aSurface = ThebesSurface(); |
|
96 NS_IF_ADDREF(*aSurface); |
|
97 return NS_OK; |
|
98 } |
|
99 |
|
100 nsresult GetPattern(gfxPattern **aPattern) |
|
101 { |
|
102 if (mSinglePixel) |
|
103 *aPattern = new gfxPattern(mSinglePixelColor); |
|
104 else |
|
105 *aPattern = new gfxPattern(ThebesSurface()); |
|
106 NS_ADDREF(*aPattern); |
|
107 return NS_OK; |
|
108 } |
|
109 |
|
110 bool IsSinglePixel() |
|
111 { |
|
112 return mSinglePixel; |
|
113 } |
|
114 |
|
115 gfxASurface* CachedThebesSurface() |
|
116 { |
|
117 if (mOptSurface) |
|
118 return mOptSurface; |
|
119 #if defined(XP_WIN) |
|
120 if (mWinSurface) |
|
121 return mWinSurface; |
|
122 #elif defined(XP_MACOSX) |
|
123 if (mQuartzSurface) |
|
124 return mQuartzSurface; |
|
125 #endif |
|
126 if (mImageSurface) |
|
127 return mImageSurface; |
|
128 return nullptr; |
|
129 } |
|
130 |
|
131 gfxASurface* ThebesSurface() |
|
132 { |
|
133 gfxASurface *sur = CachedThebesSurface(); |
|
134 if (sur) |
|
135 return sur; |
|
136 if (mVBuf) { |
|
137 mozilla::VolatileBufferPtr<uint8_t> ref(mVBuf); |
|
138 if (ref.WasBufferPurged()) |
|
139 return nullptr; |
|
140 |
|
141 gfxImageSurface *imgSur = |
|
142 LockedImageSurface::CreateSurface(mVBuf, mSize, mFormat); |
|
143 #if defined(XP_MACOSX) |
|
144 // Manually addref and release to make sure the cairo surface isn't lost |
|
145 NS_ADDREF(imgSur); |
|
146 gfxQuartzImageSurface *quartzSur = new gfxQuartzImageSurface(imgSur); |
|
147 // quartzSur does not hold on to the gfxImageSurface |
|
148 NS_RELEASE(imgSur); |
|
149 return quartzSur; |
|
150 #else |
|
151 return imgSur; |
|
152 #endif |
|
153 } |
|
154 // We can return null here if we're single pixel optimized |
|
155 // or a paletted image. However, one has to check for paletted |
|
156 // image data first before attempting to get a surface, so |
|
157 // this is only valid for single pixel optimized images |
|
158 MOZ_ASSERT(mSinglePixel, "No image surface and not a single pixel!"); |
|
159 return nullptr; |
|
160 } |
|
161 |
|
162 size_t SizeOfExcludingThisWithComputedFallbackIfHeap( |
|
163 gfxMemoryLocation aLocation, |
|
164 mozilla::MallocSizeOf aMallocSizeOf) const; |
|
165 |
|
166 uint8_t GetPaletteDepth() const { return mPaletteDepth; } |
|
167 uint32_t PaletteDataLength() const { |
|
168 if (!mPaletteDepth) |
|
169 return 0; |
|
170 |
|
171 return ((1 << mPaletteDepth) * sizeof(uint32_t)); |
|
172 } |
|
173 |
|
174 private: // methods |
|
175 |
|
176 struct SurfaceWithFormat { |
|
177 nsRefPtr<gfxDrawable> mDrawable; |
|
178 gfxImageFormat mFormat; |
|
179 SurfaceWithFormat() {} |
|
180 SurfaceWithFormat(gfxDrawable* aDrawable, gfxImageFormat aFormat) |
|
181 : mDrawable(aDrawable), mFormat(aFormat) {} |
|
182 bool IsValid() { return !!mDrawable; } |
|
183 }; |
|
184 |
|
185 SurfaceWithFormat SurfaceForDrawing(bool aDoPadding, |
|
186 bool aDoPartialDecode, |
|
187 bool aDoTile, |
|
188 const nsIntMargin& aPadding, |
|
189 gfxMatrix& aUserSpaceToImageSpace, |
|
190 gfxRect& aFill, |
|
191 gfxRect& aSubimage, |
|
192 gfxRect& aSourceRect, |
|
193 gfxRect& aImageRect, |
|
194 gfxASurface* aSurface); |
|
195 |
|
196 private: // data |
|
197 nsRefPtr<gfxImageSurface> mImageSurface; |
|
198 nsRefPtr<gfxASurface> mOptSurface; |
|
199 #if defined(XP_WIN) |
|
200 nsRefPtr<gfxWindowsSurface> mWinSurface; |
|
201 #elif defined(XP_MACOSX) |
|
202 nsRefPtr<gfxQuartzImageSurface> mQuartzSurface; |
|
203 #endif |
|
204 |
|
205 nsRefPtr<gfxASurface> mDrawSurface; |
|
206 |
|
207 nsIntSize mSize; |
|
208 nsIntPoint mOffset; |
|
209 |
|
210 nsIntRect mDecoded; |
|
211 |
|
212 mutable mozilla::Mutex mDirtyMutex; |
|
213 |
|
214 // The palette and image data for images that are paletted, since Cairo |
|
215 // doesn't support these images. |
|
216 // The paletted data comes first, then the image data itself. |
|
217 // Total length is PaletteDataLength() + GetImageDataLength(). |
|
218 uint8_t* mPalettedImageData; |
|
219 |
|
220 // Note that the data stored in gfxRGBA is *non-alpha-premultiplied*. |
|
221 gfxRGBA mSinglePixelColor; |
|
222 |
|
223 int32_t mTimeout; // -1 means display forever |
|
224 int32_t mDisposalMethod; |
|
225 |
|
226 /** Indicates how many readers currently have locked this frame */ |
|
227 int32_t mLockCount; |
|
228 |
|
229 mozilla::RefPtr<mozilla::VolatileBuffer> mVBuf; |
|
230 |
|
231 gfxImageFormat mFormat; |
|
232 uint8_t mPaletteDepth; |
|
233 int8_t mBlendMethod; |
|
234 bool mSinglePixel; |
|
235 bool mFormatChanged; |
|
236 bool mCompositingFailed; |
|
237 bool mNonPremult; |
|
238 bool mDiscardable; |
|
239 |
|
240 /** Have we called DiscardTracker::InformAllocation()? */ |
|
241 bool mInformedDiscardTracker; |
|
242 |
|
243 bool mDirty; |
|
244 }; |
|
245 |
|
246 namespace mozilla { |
|
247 namespace image { |
|
248 // An RAII class to ensure it's easy to balance locks and unlocks on |
|
249 // imgFrames. |
|
250 class AutoFrameLocker |
|
251 { |
|
252 public: |
|
253 AutoFrameLocker(imgFrame* frame) |
|
254 : mFrame(frame) |
|
255 , mSucceeded(NS_SUCCEEDED(frame->LockImageData())) |
|
256 {} |
|
257 |
|
258 ~AutoFrameLocker() |
|
259 { |
|
260 if (mSucceeded) { |
|
261 mFrame->UnlockImageData(); |
|
262 } |
|
263 } |
|
264 |
|
265 // Whether the lock request succeeded. |
|
266 bool Succeeded() { return mSucceeded; } |
|
267 |
|
268 private: |
|
269 imgFrame* mFrame; |
|
270 bool mSucceeded; |
|
271 }; |
|
272 } |
|
273 } |
|
274 |
|
275 #endif /* imgFrame_h */ |