1 /*
2  * Copyright 2015 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef SkPixmap_DEFINED
9 #define SkPixmap_DEFINED
10 
11 #include "SkColor.h"
12 #include "SkFilterQuality.h"
13 #include "SkImageInfo.h"
14 
15 class SkColorTable;
16 class SkData;
17 struct SkMask;
18 
19 /**
20  *  Pairs SkImageInfo with actual pixels and rowbytes. This class does not try to manage the
21  *  lifetime of the pixel memory (nor the colortable if provided).
22  */
23 class SK_API SkPixmap {
24 public:
SkPixmap()25     SkPixmap()
26         : fPixels(NULL), fCTable(NULL), fRowBytes(0), fInfo(SkImageInfo::MakeUnknown(0, 0))
27     {}
28 
29     SkPixmap(const SkImageInfo& info, const void* addr, size_t rowBytes,
30              SkColorTable* ctable = NULL)
fPixels(addr)31         : fPixels(addr), fCTable(ctable), fRowBytes(rowBytes), fInfo(info)
32     {
33         if (kIndex_8_SkColorType == info.colorType()) {
34             SkASSERT(ctable);
35         } else {
36             SkASSERT(NULL == ctable);
37         }
38     }
39 
40     void reset();
41     void reset(const SkImageInfo& info, const void* addr, size_t rowBytes,
42                SkColorTable* ctable = NULL);
reset(const SkImageInfo & info)43     void reset(const SkImageInfo& info) {
44         this->reset(info, NULL, 0, NULL);
45     }
46 
47     /**
48      *  If supported, set this pixmap to point to the pixels in the specified mask and return true.
49      *  On failure, return false and set this pixmap to empty.
50      */
51     bool SK_WARN_UNUSED_RESULT reset(const SkMask&);
52 
53     /**
54      *  Computes the intersection of area and this pixmap. If that intersection is non-empty,
55      *  set subset to that intersection and return true.
56      *
57      *  On failure, return false and ignore the subset parameter.
58      */
59     bool SK_WARN_UNUSED_RESULT extractSubset(SkPixmap* subset, const SkIRect& area) const;
60 
info()61     const SkImageInfo& info() const { return fInfo; }
rowBytes()62     size_t rowBytes() const { return fRowBytes; }
addr()63     const void* addr() const { return fPixels; }
ctable()64     SkColorTable* ctable() const { return fCTable; }
65 
width()66     int width() const { return fInfo.width(); }
height()67     int height() const { return fInfo.height(); }
colorType()68     SkColorType colorType() const { return fInfo.colorType(); }
alphaType()69     SkAlphaType alphaType() const { return fInfo.alphaType(); }
isOpaque()70     bool isOpaque() const { return fInfo.isOpaque(); }
71 
bounds()72     SkIRect bounds() const { return SkIRect::MakeWH(this->width(), this->height()); }
73 
getSize64()74     uint64_t getSize64() const { return sk_64_mul(fInfo.height(), fRowBytes); }
getSafeSize64()75     uint64_t getSafeSize64() const { return fInfo.getSafeSize64(fRowBytes); }
getSafeSize()76     size_t getSafeSize() const { return fInfo.getSafeSize(fRowBytes); }
77 
addr(int x,int y)78     const void* addr(int x, int y) const {
79         return (const char*)fPixels + fInfo.computeOffset(x, y, fRowBytes);
80     }
addr8()81     const uint8_t* addr8() const {
82         SkASSERT(1 == SkColorTypeBytesPerPixel(fInfo.colorType()));
83         return reinterpret_cast<const uint8_t*>(fPixels);
84     }
addr16()85     const uint16_t* addr16() const {
86         SkASSERT(2 == SkColorTypeBytesPerPixel(fInfo.colorType()));
87         return reinterpret_cast<const uint16_t*>(fPixels);
88     }
addr32()89     const uint32_t* addr32() const {
90         SkASSERT(4 == SkColorTypeBytesPerPixel(fInfo.colorType()));
91         return reinterpret_cast<const uint32_t*>(fPixels);
92     }
addr64()93     const uint64_t* addr64() const {
94         SkASSERT(8 == SkColorTypeBytesPerPixel(fInfo.colorType()));
95         return reinterpret_cast<const uint64_t*>(fPixels);
96     }
addrF16()97     const uint16_t* addrF16() const {
98         SkASSERT(8 == SkColorTypeBytesPerPixel(fInfo.colorType()));
99         SkASSERT(kRGBA_F16_SkColorType == fInfo.colorType());
100         return reinterpret_cast<const uint16_t*>(fPixels);
101     }
102 
103     // Offset by the specified x,y coordinates
104 
addr8(int x,int y)105     const uint8_t* addr8(int x, int y) const {
106         SkASSERT((unsigned)x < (unsigned)fInfo.width());
107         SkASSERT((unsigned)y < (unsigned)fInfo.height());
108         return (const uint8_t*)((const char*)this->addr8() + y * fRowBytes + (x << 0));
109     }
addr16(int x,int y)110     const uint16_t* addr16(int x, int y) const {
111         SkASSERT((unsigned)x < (unsigned)fInfo.width());
112         SkASSERT((unsigned)y < (unsigned)fInfo.height());
113         return (const uint16_t*)((const char*)this->addr16() + y * fRowBytes + (x << 1));
114     }
addr32(int x,int y)115     const uint32_t* addr32(int x, int y) const {
116         SkASSERT((unsigned)x < (unsigned)fInfo.width());
117         SkASSERT((unsigned)y < (unsigned)fInfo.height());
118         return (const uint32_t*)((const char*)this->addr32() + y * fRowBytes + (x << 2));
119     }
addr64(int x,int y)120     const uint64_t* addr64(int x, int y) const {
121         SkASSERT((unsigned)x < (unsigned)fInfo.width());
122         SkASSERT((unsigned)y < (unsigned)fInfo.height());
123         return (const uint64_t*)((const char*)this->addr64() + y * fRowBytes + (x << 3));
124     }
addrF16(int x,int y)125     const uint16_t* addrF16(int x, int y) const {
126         SkASSERT(kRGBA_F16_SkColorType == fInfo.colorType());
127         return reinterpret_cast<const uint16_t*>(this->addr64(x, y));
128     }
129 
130     // Writable versions
131 
writable_addr()132     void* writable_addr() const { return const_cast<void*>(fPixels); }
writable_addr8(int x,int y)133     uint8_t* writable_addr8(int x, int y) const {
134         return const_cast<uint8_t*>(this->addr8(x, y));
135     }
writable_addr16(int x,int y)136     uint16_t* writable_addr16(int x, int y) const {
137         return const_cast<uint16_t*>(this->addr16(x, y));
138     }
writable_addr32(int x,int y)139     uint32_t* writable_addr32(int x, int y) const {
140         return const_cast<uint32_t*>(this->addr32(x, y));
141     }
writable_addr64(int x,int y)142     uint64_t* writable_addr64(int x, int y) const {
143         return const_cast<uint64_t*>(this->addr64(x, y));
144     }
writable_addrF16(int x,int y)145     uint16_t* writable_addrF16(int x, int y) const {
146         return reinterpret_cast<uint16_t*>(writable_addr64(x, y));
147     }
148 
149     // copy methods
150 
151     bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
152                     int srcX, int srcY) const;
readPixels(const SkImageInfo & dstInfo,void * dstPixels,size_t dstRowBytes)153     bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes) const {
154         return this->readPixels(dstInfo, dstPixels, dstRowBytes, 0, 0);
155     }
readPixels(const SkPixmap & dst,int srcX,int srcY)156     bool readPixels(const SkPixmap& dst, int srcX, int srcY) const {
157         return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), srcX, srcY);
158     }
readPixels(const SkPixmap & dst)159     bool readPixels(const SkPixmap& dst) const {
160         return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), 0, 0);
161     }
162 
163     /**
164      *  Copy the pixels from this pixmap into the dst pixmap, converting as needed into dst's
165      *  colortype/alphatype. If the conversion cannot be performed, false is returned.
166      *
167      *  If dst's dimensions differ from the src dimension, the image will be scaled, applying the
168      *  specified filter-quality.
169      */
170     bool scalePixels(const SkPixmap& dst, SkFilterQuality) const;
171 
172     /**
173      *  Returns true if pixels were written to (e.g. if colorType is kUnknown_SkColorType, this
174      *  will return false). If subset does not intersect the bounds of this pixmap, returns false.
175      */
176     bool erase(SkColor, const SkIRect& subset) const;
177 
erase(SkColor color)178     bool erase(SkColor color) const { return this->erase(color, this->bounds()); }
179     bool erase(const SkColor4f&, const SkIRect* subset = nullptr) const;
180 
181 private:
182     const void*     fPixels;
183     SkColorTable*   fCTable;
184     size_t          fRowBytes;
185     SkImageInfo     fInfo;
186 };
187 
188 /////////////////////////////////////////////////////////////////////////////////////////////
189 
190 class SK_API SkAutoPixmapStorage : public SkPixmap {
191 public:
192     SkAutoPixmapStorage();
193     ~SkAutoPixmapStorage();
194 
195     /**
196      *  Try to allocate memory for the pixels needed to match the specified Info. On success
197      *  return true and fill out the pixmap to point to that memory. The storage will be freed
198      *  when this object is destroyed, or if another call to tryAlloc() or alloc() is made.
199      *
200      *  On failure, return false and reset() the pixmap to empty.
201      */
202     bool tryAlloc(const SkImageInfo&);
203 
204     /**
205      *  Allocate memory for the pixels needed to match the specified Info and fill out the pixmap
206      *  to point to that memory. The storage will be freed when this object is destroyed,
207      *  or if another call to tryAlloc() or alloc() is made.
208      *
209      *  If the memory cannot be allocated, calls sk_throw().
210      */
211     void alloc(const SkImageInfo&);
212 
213     /**
214      *  Returns an SkData object wrapping the allocated pixels memory, and resets the pixmap.
215      *  If the storage hasn't been allocated, the result is NULL.
216      */
217     const SkData* SK_WARN_UNUSED_RESULT detachPixelsAsData();
218 
219     // We wrap these so we can clear our internal storage
220 
reset()221     void reset() {
222         this->freeStorage();
223         this->INHERITED::reset();
224     }
225     void reset(const SkImageInfo& info, const void* addr, size_t rb, SkColorTable* ctable = NULL) {
226         this->freeStorage();
227         this->INHERITED::reset(info, addr, rb, ctable);
228     }
reset(const SkImageInfo & info)229     void reset(const SkImageInfo& info) {
230         this->freeStorage();
231         this->INHERITED::reset(info);
232     }
reset(const SkMask & mask)233     bool SK_WARN_UNUSED_RESULT reset(const SkMask& mask) {
234         this->freeStorage();
235         return this->INHERITED::reset(mask);
236     }
237 
238 private:
239     void*   fStorage;
240 
freeStorage()241     void freeStorage() {
242         sk_free(fStorage);
243         fStorage = nullptr;
244     }
245 
246     typedef SkPixmap INHERITED;
247 };
248 
249 /////////////////////////////////////////////////////////////////////////////////////////////
250 
251 class SK_API SkAutoPixmapUnlock : ::SkNoncopyable {
252 public:
SkAutoPixmapUnlock()253     SkAutoPixmapUnlock() : fUnlockProc(NULL), fIsLocked(false) {}
SkAutoPixmapUnlock(const SkPixmap & pm,void (* unlock)(void *),void * ctx)254     SkAutoPixmapUnlock(const SkPixmap& pm, void (*unlock)(void*), void* ctx)
255         : fUnlockProc(unlock), fUnlockContext(ctx), fPixmap(pm), fIsLocked(true)
256     {}
~SkAutoPixmapUnlock()257     ~SkAutoPixmapUnlock() { this->unlock(); }
258 
259     /**
260      *  Return the currently locked pixmap. Undefined if it has been unlocked.
261      */
pixmap()262     const SkPixmap& pixmap() const {
263         SkASSERT(this->isLocked());
264         return fPixmap;
265     }
266 
isLocked()267     bool isLocked() const { return fIsLocked; }
268 
269     /**
270      *  Unlocks the pixmap. Can safely be called more than once as it will only call the underlying
271      *  unlock-proc once.
272      */
unlock()273     void unlock() {
274         if (fUnlockProc) {
275             SkASSERT(fIsLocked);
276             fUnlockProc(fUnlockContext);
277             fUnlockProc = NULL;
278             fIsLocked = false;
279         }
280     }
281 
282     /**
283      *  If there is a currently locked pixmap, unlock it, then copy the specified pixmap
284      *  and (optional) unlock proc/context.
285      */
286     void reset(const SkPixmap& pm, void (*unlock)(void*), void* ctx);
287 
288 private:
289     void        (*fUnlockProc)(void*);
290     void*       fUnlockContext;
291     SkPixmap    fPixmap;
292     bool        fIsLocked;
293 
294     friend class SkBitmap;
295 };
296 
297 #endif
298