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     // overrides the colorspace in the SkImageInfo of the pixmap
48     void setColorSpace(sk_sp<SkColorSpace>);
49 
50     /**
51      *  If supported, set this pixmap to point to the pixels in the specified mask and return true.
52      *  On failure, return false and set this pixmap to empty.
53      */
54     bool SK_WARN_UNUSED_RESULT reset(const SkMask&);
55 
56     /**
57      *  Computes the intersection of area and this pixmap. If that intersection is non-empty,
58      *  set subset to that intersection and return true.
59      *
60      *  On failure, return false and ignore the subset parameter.
61      */
62     bool SK_WARN_UNUSED_RESULT extractSubset(SkPixmap* subset, const SkIRect& area) const;
63 
info()64     const SkImageInfo& info() const { return fInfo; }
rowBytes()65     size_t rowBytes() const { return fRowBytes; }
addr()66     const void* addr() const { return fPixels; }
ctable()67     SkColorTable* ctable() const { return fCTable; }
68 
width()69     int width() const { return fInfo.width(); }
height()70     int height() const { return fInfo.height(); }
colorType()71     SkColorType colorType() const { return fInfo.colorType(); }
alphaType()72     SkAlphaType alphaType() const { return fInfo.alphaType(); }
colorSpace()73     SkColorSpace* colorSpace() const { return fInfo.colorSpace(); }
isOpaque()74     bool isOpaque() const { return fInfo.isOpaque(); }
75 
bounds()76     SkIRect bounds() const { return SkIRect::MakeWH(this->width(), this->height()); }
77 
78     /**
79      *  Return the rowbytes expressed as a number of pixels (like width and height).
80      */
rowBytesAsPixels()81     int rowBytesAsPixels() const { return int(fRowBytes >> this->shiftPerPixel()); }
82 
83     /**
84      *  Return the shift amount per pixel (i.e. 0 for 1-byte per pixel, 1 for 2-bytes per pixel
85      *  colortypes, 2 for 4-bytes per pixel colortypes). Return 0 for kUnknown_SkColorType.
86      */
shiftPerPixel()87     int shiftPerPixel() const { return fInfo.shiftPerPixel(); }
88 
getSize64()89     uint64_t getSize64() const { return sk_64_mul(fInfo.height(), fRowBytes); }
getSafeSize64()90     uint64_t getSafeSize64() const { return fInfo.getSafeSize64(fRowBytes); }
getSafeSize()91     size_t getSafeSize() const { return fInfo.getSafeSize(fRowBytes); }
92 
93     /**
94      *  This will brute-force return true if all of the pixels in the pixmap
95      *  are opaque. If there are no pixels, or encounters an error, returns false.
96      */
97     bool computeIsOpaque() const;
98 
99     /**
100      *  Converts the pixel at the specified coordinate to an unpremultiplied
101      *  SkColor. Note: this ignores any SkColorSpace information, and may return
102      *  lower precision data than is actually in the pixel. Alpha only
103      *  colortypes (e.g. kAlpha_8_SkColorType) return black with the appropriate
104      *  alpha set.  The value is undefined for kUnknown_SkColorType or if x or y
105      *  are out of bounds, or if the pixtap does not have any pixels.
106      */
107     SkColor getColor(int x, int y) const;
108 
addr(int x,int y)109     const void* addr(int x, int y) const {
110         return (const char*)fPixels + fInfo.computeOffset(x, y, fRowBytes);
111     }
addr8()112     const uint8_t* addr8() const {
113         SkASSERT(1 == SkColorTypeBytesPerPixel(fInfo.colorType()));
114         return reinterpret_cast<const uint8_t*>(fPixels);
115     }
addr16()116     const uint16_t* addr16() const {
117         SkASSERT(2 == SkColorTypeBytesPerPixel(fInfo.colorType()));
118         return reinterpret_cast<const uint16_t*>(fPixels);
119     }
addr32()120     const uint32_t* addr32() const {
121         SkASSERT(4 == SkColorTypeBytesPerPixel(fInfo.colorType()));
122         return reinterpret_cast<const uint32_t*>(fPixels);
123     }
addr64()124     const uint64_t* addr64() const {
125         SkASSERT(8 == SkColorTypeBytesPerPixel(fInfo.colorType()));
126         return reinterpret_cast<const uint64_t*>(fPixels);
127     }
addrF16()128     const uint16_t* addrF16() const {
129         SkASSERT(8 == SkColorTypeBytesPerPixel(fInfo.colorType()));
130         SkASSERT(kRGBA_F16_SkColorType == fInfo.colorType());
131         return reinterpret_cast<const uint16_t*>(fPixels);
132     }
133 
134     // Offset by the specified x,y coordinates
135 
addr8(int x,int y)136     const uint8_t* addr8(int x, int y) const {
137         SkASSERT((unsigned)x < (unsigned)fInfo.width());
138         SkASSERT((unsigned)y < (unsigned)fInfo.height());
139         return (const uint8_t*)((const char*)this->addr8() + y * fRowBytes + (x << 0));
140     }
addr16(int x,int y)141     const uint16_t* addr16(int x, int y) const {
142         SkASSERT((unsigned)x < (unsigned)fInfo.width());
143         SkASSERT((unsigned)y < (unsigned)fInfo.height());
144         return (const uint16_t*)((const char*)this->addr16() + y * fRowBytes + (x << 1));
145     }
addr32(int x,int y)146     const uint32_t* addr32(int x, int y) const {
147         SkASSERT((unsigned)x < (unsigned)fInfo.width());
148         SkASSERT((unsigned)y < (unsigned)fInfo.height());
149         return (const uint32_t*)((const char*)this->addr32() + y * fRowBytes + (x << 2));
150     }
addr64(int x,int y)151     const uint64_t* addr64(int x, int y) const {
152         SkASSERT((unsigned)x < (unsigned)fInfo.width());
153         SkASSERT((unsigned)y < (unsigned)fInfo.height());
154         return (const uint64_t*)((const char*)this->addr64() + y * fRowBytes + (x << 3));
155     }
addrF16(int x,int y)156     const uint16_t* addrF16(int x, int y) const {
157         SkASSERT(kRGBA_F16_SkColorType == fInfo.colorType());
158         return reinterpret_cast<const uint16_t*>(this->addr64(x, y));
159     }
160 
161     // Writable versions
162 
writable_addr()163     void* writable_addr() const { return const_cast<void*>(fPixels); }
writable_addr(int x,int y)164     void* writable_addr(int x, int y) const {
165         return const_cast<void*>(this->addr(x, y));
166     }
writable_addr8(int x,int y)167     uint8_t* writable_addr8(int x, int y) const {
168         return const_cast<uint8_t*>(this->addr8(x, y));
169     }
writable_addr16(int x,int y)170     uint16_t* writable_addr16(int x, int y) const {
171         return const_cast<uint16_t*>(this->addr16(x, y));
172     }
writable_addr32(int x,int y)173     uint32_t* writable_addr32(int x, int y) const {
174         return const_cast<uint32_t*>(this->addr32(x, y));
175     }
writable_addr64(int x,int y)176     uint64_t* writable_addr64(int x, int y) const {
177         return const_cast<uint64_t*>(this->addr64(x, y));
178     }
writable_addrF16(int x,int y)179     uint16_t* writable_addrF16(int x, int y) const {
180         return reinterpret_cast<uint16_t*>(writable_addr64(x, y));
181     }
182 
183     // copy methods
184 
185     bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
186                     int srcX, int srcY) const;
readPixels(const SkImageInfo & dstInfo,void * dstPixels,size_t dstRowBytes)187     bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes) const {
188         return this->readPixels(dstInfo, dstPixels, dstRowBytes, 0, 0);
189     }
readPixels(const SkPixmap & dst,int srcX,int srcY)190     bool readPixels(const SkPixmap& dst, int srcX, int srcY) const {
191         return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), srcX, srcY);
192     }
readPixels(const SkPixmap & dst)193     bool readPixels(const SkPixmap& dst) const {
194         return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), 0, 0);
195     }
196 
197     /**
198      *  Copy the pixels from this pixmap into the dst pixmap, converting as needed into dst's
199      *  colortype/alphatype. If the conversion cannot be performed, false is returned.
200      *
201      *  If dst's dimensions differ from the src dimension, the image will be scaled, applying the
202      *  specified filter-quality.
203      */
204     bool scalePixels(const SkPixmap& dst, SkFilterQuality) const;
205 
206     /**
207      *  Returns true if pixels were written to (e.g. if colorType is kUnknown_SkColorType, this
208      *  will return false). If subset does not intersect the bounds of this pixmap, returns false.
209      */
210     bool erase(SkColor, const SkIRect& subset) const;
211 
erase(SkColor color)212     bool erase(SkColor color) const { return this->erase(color, this->bounds()); }
213     bool erase(const SkColor4f&, const SkIRect* subset = nullptr) const;
214 
215 private:
216     const void*     fPixels;
217     SkColorTable*   fCTable;
218     size_t          fRowBytes;
219     SkImageInfo     fInfo;
220 };
221 
222 /////////////////////////////////////////////////////////////////////////////////////////////
223 
224 /////////////////////////////////////////////////////////////////////////////////////////////
225 
226 class SK_API SkAutoPixmapUnlock : ::SkNoncopyable {
227 public:
SkAutoPixmapUnlock()228     SkAutoPixmapUnlock() : fUnlockProc(NULL), fIsLocked(false) {}
SkAutoPixmapUnlock(const SkPixmap & pm,void (* unlock)(void *),void * ctx)229     SkAutoPixmapUnlock(const SkPixmap& pm, void (*unlock)(void*), void* ctx)
230         : fUnlockProc(unlock), fUnlockContext(ctx), fPixmap(pm), fIsLocked(true)
231     {}
~SkAutoPixmapUnlock()232     ~SkAutoPixmapUnlock() { this->unlock(); }
233 
234     /**
235      *  Return the currently locked pixmap. Undefined if it has been unlocked.
236      */
pixmap()237     const SkPixmap& pixmap() const {
238         SkASSERT(this->isLocked());
239         return fPixmap;
240     }
241 
isLocked()242     bool isLocked() const { return fIsLocked; }
243 
244     /**
245      *  Unlocks the pixmap. Can safely be called more than once as it will only call the underlying
246      *  unlock-proc once.
247      */
unlock()248     void unlock() {
249         if (fUnlockProc) {
250             SkASSERT(fIsLocked);
251             fUnlockProc(fUnlockContext);
252             fUnlockProc = NULL;
253             fIsLocked = false;
254         }
255     }
256 
257     /**
258      *  If there is a currently locked pixmap, unlock it, then copy the specified pixmap
259      *  and (optional) unlock proc/context.
260      */
261     void reset(const SkPixmap& pm, void (*unlock)(void*), void* ctx);
262 
263 private:
264     void        (*fUnlockProc)(void*);
265     void*       fUnlockContext;
266     SkPixmap    fPixmap;
267     bool        fIsLocked;
268 
269     friend class SkBitmap;
270 };
271 
272 #endif
273