1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
|
/*
* Copyright 2008 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkPixelRef_DEFINED
#define SkPixelRef_DEFINED
#include "SkBitmap.h"
#include "SkRefCnt.h"
#include "SkString.h"
#include "SkFlattenable.h"
#include "SkImageInfo.h"
#include "SkTDArray.h"
//#define xed
#ifdef SK_DEBUG
/**
* Defining SK_IGNORE_PIXELREF_SETPRELOCKED will force all pixelref
* subclasses to correctly handle lock/unlock pixels. For performance
* reasons, simple malloc-based subclasses call setPreLocked() to skip
* the overhead of implementing these calls.
*
* This build-flag disables that optimization, to add in debugging our
* call-sites, to ensure that they correctly balance their calls of
* lock and unlock.
*/
// #define SK_IGNORE_PIXELREF_SETPRELOCKED
#endif
class SkColorTable;
class SkData;
struct SkIRect;
class SkMutex;
class GrTexture;
/** \class SkPixelRef
This class is the smart container for pixel memory, and is used with
SkBitmap. A pixelref is installed into a bitmap, and then the bitmap can
access the actual pixel memory by calling lockPixels/unlockPixels.
This class can be shared/accessed between multiple threads.
*/
class SK_API SkPixelRef : public SkFlattenable {
public:
SK_DECLARE_INST_COUNT(SkPixelRef)
explicit SkPixelRef(const SkImageInfo&);
SkPixelRef(const SkImageInfo&, SkBaseMutex* mutex);
virtual ~SkPixelRef();
const SkImageInfo& info() const {
return fInfo;
}
/** Return the pixel memory returned from lockPixels, or null if the
lockCount is 0.
*/
void* pixels() const { return fRec.fPixels; }
/** Return the current colorTable (if any) if pixels are locked, or null.
*/
SkColorTable* colorTable() const { return fRec.fColorTable; }
size_t rowBytes() const { return fRec.fRowBytes; }
/**
* To access the actual pixels of a pixelref, it must be "locked".
* Calling lockPixels returns a LockRec struct (on success).
*/
struct LockRec {
void* fPixels;
SkColorTable* fColorTable;
size_t fRowBytes;
void zero() { sk_bzero(this, sizeof(*this)); }
bool isZero() const {
return NULL == fPixels && NULL == fColorTable && 0 == fRowBytes;
}
};
/**
* Returns true if the lockcount > 0
*/
bool isLocked() const { return fLockCount > 0; }
SkDEBUGCODE(int getLockCount() const { return fLockCount; })
/**
* Call to access the pixel memory. Return true on success. Balance this
* with a call to unlockPixels().
*/
bool lockPixels();
/**
* Call to access the pixel memory. On success, return true and fill out
* the specified rec. On failure, return false and ignore the rec parameter.
* Balance this with a call to unlockPixels().
*/
bool lockPixels(LockRec* rec);
/** Call to balanace a previous call to lockPixels(). Returns the pixels
(or null) after the unlock. NOTE: lock calls can be nested, but the
matching number of unlock calls must be made in order to free the
memory (if the subclass implements caching/deferred-decoding.)
*/
void unlockPixels();
/**
* Some bitmaps can return a copy of their pixels for lockPixels(), but
* that copy, if modified, will not be pushed back. These bitmaps should
* not be used as targets for a raster device/canvas (since all pixels
* modifications will be lost when unlockPixels() is called.)
*/
bool lockPixelsAreWritable() const;
/** Returns a non-zero, unique value corresponding to the pixels in this
pixelref. Each time the pixels are changed (and notifyPixelsChanged is
called), a different generation ID will be returned.
*/
uint32_t getGenerationID() const;
/**
* Call this if you have changed the contents of the pixels. This will in-
* turn cause a different generation ID value to be returned from
* getGenerationID().
*/
void notifyPixelsChanged();
/**
* Change the info's AlphaType. Note that this does not automatically
* invalidate the generation ID. If the pixel values themselves have
* changed, then you must explicitly call notifyPixelsChanged() as well.
*/
void changeAlphaType(SkAlphaType at);
/** Returns true if this pixelref is marked as immutable, meaning that the
contents of its pixels will not change for the lifetime of the pixelref.
*/
bool isImmutable() const { return fIsImmutable; }
/** Marks this pixelref is immutable, meaning that the contents of its
pixels will not change for the lifetime of the pixelref. This state can
be set on a pixelref, but it cannot be cleared once it is set.
*/
void setImmutable();
/** Return the optional URI string associated with this pixelref. May be
null.
*/
const char* getURI() const { return fURI.size() ? fURI.c_str() : NULL; }
/** Copy a URI string to this pixelref, or clear the URI if the uri is null
*/
void setURI(const char uri[]) {
fURI.set(uri);
}
/** Copy a URI string to this pixelref
*/
void setURI(const char uri[], size_t len) {
fURI.set(uri, len);
}
/** Assign a URI string to this pixelref.
*/
void setURI(const SkString& uri) { fURI = uri; }
/**
* If the pixelRef has an encoded (i.e. compressed) representation,
* return a ref to its data. If the pixelRef
* is uncompressed or otherwise does not have this form, return NULL.
*
* If non-null is returned, the caller is responsible for calling unref()
* on the data when it is finished.
*/
SkData* refEncodedData() {
return this->onRefEncodedData();
}
/**
* Experimental -- tells the caller if it is worth it to call decodeInto().
* Just an optimization at this point, to avoid checking the cache first.
* We may remove/change this call in the future.
*/
bool implementsDecodeInto() {
return this->onImplementsDecodeInto();
}
/**
* Return a decoded instance of this pixelRef in bitmap. If this cannot be
* done, return false and the bitmap parameter is ignored/unchanged.
*
* pow2 is the requeste power-of-two downscale that the caller needs. This
* can be ignored, and the "original" size can be returned, but if the
* underlying codec can efficiently return a smaller size, that should be
* done. Some examples:
*
* To request the "base" version (original scale), pass 0 for pow2
* To request 1/2 scale version (1/2 width, 1/2 height), pass 1 for pow2
* To request 1/4 scale version (1/4 width, 1/4 height), pass 2 for pow2
* ...
*
* If this returns true, then bitmap must be "locked" such that
* bitmap->getPixels() will return the correct address.
*/
bool decodeInto(int pow2, SkBitmap* bitmap) {
SkASSERT(pow2 >= 0);
return this->onDecodeInto(pow2, bitmap);
}
/** Are we really wrapping a texture instead of a bitmap?
*/
virtual GrTexture* getTexture() { return NULL; }
bool readPixels(SkBitmap* dst, const SkIRect* subset = NULL);
/**
* Makes a deep copy of this PixelRef, respecting the requested config.
* @param config Desired config.
* @param subset Subset of this PixelRef to copy. Must be fully contained within the bounds of
* of this PixelRef.
* @return A new SkPixelRef, or NULL if either there is an error (e.g. the destination could
* not be created with the given config), or this PixelRef does not support deep
* copies.
*/
virtual SkPixelRef* deepCopy(SkBitmap::Config config, const SkIRect* subset = NULL) {
return NULL;
}
#ifdef SK_BUILD_FOR_ANDROID
/**
* Acquire a "global" ref on this object.
* The default implementation just calls ref(), but subclasses can override
* this method to implement additional behavior.
*/
virtual void globalRef(void* data=NULL);
/**
* Release a "global" ref on this object.
* The default implementation just calls unref(), but subclasses can override
* this method to implement additional behavior.
*/
virtual void globalUnref();
#endif
SK_DEFINE_FLATTENABLE_TYPE(SkPixelRef)
// Register a listener that may be called the next time our generation ID changes.
//
// We'll only call the listener if we're confident that we are the only SkPixelRef with this
// generation ID. If our generation ID changes and we decide not to call the listener, we'll
// never call it: you must add a new listener for each generation ID change. We also won't call
// the listener when we're certain no one knows what our generation ID is.
//
// This can be used to invalidate caches keyed by SkPixelRef generation ID.
struct GenIDChangeListener {
virtual ~GenIDChangeListener() {}
virtual void onChange() = 0;
};
// Takes ownership of listener.
void addGenIDChangeListener(GenIDChangeListener* listener);
protected:
/**
* On success, returns true and fills out the LockRec for the pixels. On
* failure returns false and ignores the LockRec parameter.
*
* The caller will have already acquired a mutex for thread safety, so this
* method need not do that.
*/
virtual bool onNewLockPixels(LockRec*) = 0;
/**
* Balancing the previous successful call to onNewLockPixels. The locked
* pixel address will no longer be referenced, so the subclass is free to
* move or discard that memory.
*
* The caller will have already acquired a mutex for thread safety, so this
* method need not do that.
*/
virtual void onUnlockPixels() = 0;
/** Default impl returns true */
virtual bool onLockPixelsAreWritable() const;
// returns false;
virtual bool onImplementsDecodeInto();
// returns false;
virtual bool onDecodeInto(int pow2, SkBitmap* bitmap);
/**
* For pixelrefs that don't have access to their raw pixels, they may be
* able to make a copy of them (e.g. if the pixels are on the GPU).
*
* The base class implementation returns false;
*/
virtual bool onReadPixels(SkBitmap* dst, const SkIRect* subsetOrNull);
// default impl returns NULL.
virtual SkData* onRefEncodedData();
/**
* Returns the size (in bytes) of the internally allocated memory.
* This should be implemented in all serializable SkPixelRef derived classes.
* SkBitmap::fPixelRefOffset + SkBitmap::getSafeSize() should never overflow this value,
* otherwise the rendering code may attempt to read memory out of bounds.
*
* @return default impl returns 0.
*/
virtual size_t getAllocatedSizeInBytes() const;
/** Return the mutex associated with this pixelref. This value is assigned
in the constructor, and cannot change during the lifetime of the object.
*/
SkBaseMutex* mutex() const { return fMutex; }
// serialization
SkPixelRef(SkReadBuffer&, SkBaseMutex*);
virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE;
// only call from constructor. Flags this to always be locked, removing
// the need to grab the mutex and call onLockPixels/onUnlockPixels.
// Performance tweak to avoid those calls (esp. in multi-thread use case).
void setPreLocked(void*, size_t rowBytes, SkColorTable*);
private:
SkBaseMutex* fMutex; // must remain in scope for the life of this object
// mostly const. fInfo.fAlpahType can be changed at runtime.
const SkImageInfo fInfo;
// LockRec is only valid if we're in a locked state (isLocked())
LockRec fRec;
int fLockCount;
mutable uint32_t fGenerationID;
mutable bool fUniqueGenerationID;
SkTDArray<GenIDChangeListener*> fGenIDChangeListeners; // pointers are owned
SkString fURI;
// can go from false to true, but never from true to false
bool fIsImmutable;
// only ever set in constructor, const after that
bool fPreLocked;
void needsNewGenID();
void callGenIDChangeListeners();
void setMutex(SkBaseMutex* mutex);
// When copying a bitmap to another with the same shape and config, we can safely
// clone the pixelref generation ID too, which makes them equivalent under caching.
friend class SkBitmap; // only for cloneGenID
void cloneGenID(const SkPixelRef&);
typedef SkFlattenable INHERITED;
};
class SkPixelRefFactory : public SkRefCnt {
public:
/**
* Allocate a new pixelref matching the specified ImageInfo, allocating
* the memory for the pixels. If the ImageInfo requires a ColorTable,
* the pixelref will ref() the colortable.
* On failure return NULL.
*/
virtual SkPixelRef* create(const SkImageInfo&, SkColorTable*) = 0;
};
#endif
|