blob: 523c40f294db0b1e5c69b234748dcd4f3340bdab [file] [log] [blame]
reed92fc2ae2015-05-22 08:06:21 -07001/*
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
reed7aefe032015-06-08 10:22:22 -070011#include "SkColor.h"
reed09553032015-11-23 12:32:16 -080012#include "SkFilterQuality.h"
reed92fc2ae2015-05-22 08:06:21 -070013#include "SkImageInfo.h"
14
15class SkColorTable;
fmalita3a94c6c2016-02-04 13:09:59 -080016class SkData;
reed183b57f2015-06-05 14:33:17 -070017struct SkMask;
reed92fc2ae2015-05-22 08:06:21 -070018
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 */
fmalita9a5d1ab2015-07-27 10:27:28 -070023class SK_API SkPixmap {
reed92fc2ae2015-05-22 08:06:21 -070024public:
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)
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
reed884e97c2015-05-26 11:31:54 -070040 void reset();
41 void reset(const SkImageInfo& info, const void* addr, size_t rowBytes,
42 SkColorTable* ctable = NULL);
reed183b57f2015-06-05 14:33:17 -070043 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;
reed884e97c2015-05-26 11:31:54 -070060
reed92fc2ae2015-05-22 08:06:21 -070061 const SkImageInfo& info() const { return fInfo; }
62 size_t rowBytes() const { return fRowBytes; }
63 const void* addr() const { return fPixels; }
64 SkColorTable* ctable() const { return fCTable; }
65
66 int width() const { return fInfo.width(); }
67 int height() const { return fInfo.height(); }
68 SkColorType colorType() const { return fInfo.colorType(); }
69 SkAlphaType alphaType() const { return fInfo.alphaType(); }
70 bool isOpaque() const { return fInfo.isOpaque(); }
71
reedad7ae6c2015-06-04 14:12:25 -070072 SkIRect bounds() const { return SkIRect::MakeWH(this->width(), this->height()); }
73
reed95d343f2015-05-23 13:21:06 -070074 uint64_t getSize64() const { return sk_64_mul(fInfo.height(), fRowBytes); }
75 uint64_t getSafeSize64() const { return fInfo.getSafeSize64(fRowBytes); }
reed92fc2ae2015-05-22 08:06:21 -070076 size_t getSafeSize() const { return fInfo.getSafeSize(fRowBytes); }
77
78 const uint32_t* addr32() const {
79 SkASSERT(4 == SkColorTypeBytesPerPixel(fInfo.colorType()));
80 return reinterpret_cast<const uint32_t*>(fPixels);
81 }
82
83 const uint16_t* addr16() const {
84 SkASSERT(2 == SkColorTypeBytesPerPixel(fInfo.colorType()));
85 return reinterpret_cast<const uint16_t*>(fPixels);
86 }
87
88 const uint8_t* addr8() const {
89 SkASSERT(1 == SkColorTypeBytesPerPixel(fInfo.colorType()));
90 return reinterpret_cast<const uint8_t*>(fPixels);
91 }
92
93 const uint32_t* addr32(int x, int y) const {
94 SkASSERT((unsigned)x < (unsigned)fInfo.width());
95 SkASSERT((unsigned)y < (unsigned)fInfo.height());
96 return (const uint32_t*)((const char*)this->addr32() + y * fRowBytes + (x << 2));
97 }
98 const uint16_t* addr16(int x, int y) const {
99 SkASSERT((unsigned)x < (unsigned)fInfo.width());
100 SkASSERT((unsigned)y < (unsigned)fInfo.height());
101 return (const uint16_t*)((const char*)this->addr16() + y * fRowBytes + (x << 1));
102 }
103 const uint8_t* addr8(int x, int y) const {
104 SkASSERT((unsigned)x < (unsigned)fInfo.width());
105 SkASSERT((unsigned)y < (unsigned)fInfo.height());
106 return (const uint8_t*)((const char*)this->addr8() + y * fRowBytes + (x << 0));
107 }
108 const void* addr(int x, int y) const {
109 return (const char*)fPixels + fInfo.computeOffset(x, y, fRowBytes);
110 }
111
112 // Writable versions
113
114 void* writable_addr() const { return const_cast<void*>(fPixels); }
115 uint32_t* writable_addr32(int x, int y) const {
116 return const_cast<uint32_t*>(this->addr32(x, y));
117 }
118 uint16_t* writable_addr16(int x, int y) const {
119 return const_cast<uint16_t*>(this->addr16(x, y));
120 }
121 uint8_t* writable_addr8(int x, int y) const {
122 return const_cast<uint8_t*>(this->addr8(x, y));
123 }
124
reed95d343f2015-05-23 13:21:06 -0700125 // copy methods
126
127 bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
128 int srcX, int srcY) const;
129 bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes) const {
130 return this->readPixels(dstInfo, dstPixels, dstRowBytes, 0, 0);
131 }
132 bool readPixels(const SkPixmap& dst, int srcX, int srcY) const {
133 return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), srcX, srcY);
134 }
135 bool readPixels(const SkPixmap& dst) const {
136 return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), 0, 0);
137 }
138
reed7aefe032015-06-08 10:22:22 -0700139 /**
reed09553032015-11-23 12:32:16 -0800140 * Copy the pixels from this pixmap into the dst pixmap, converting as needed into dst's
141 * colortype/alphatype. If the conversion cannot be performed, false is returned.
142 *
143 * If dst's dimensions differ from the src dimension, the image will be scaled, applying the
144 * specified filter-quality.
145 */
146 bool scalePixels(const SkPixmap& dst, SkFilterQuality) const;
147
148 /**
reed7aefe032015-06-08 10:22:22 -0700149 * Returns true if pixels were written to (e.g. if colorType is kUnknown_SkColorType, this
150 * will return false). If subset does not intersect the bounds of this pixmap, returns false.
151 */
152 bool erase(SkColor, const SkIRect& subset) const;
153
154 bool erase(SkColor color) const { return this->erase(color, this->bounds()); }
155
reed92fc2ae2015-05-22 08:06:21 -0700156private:
157 const void* fPixels;
158 SkColorTable* fCTable;
159 size_t fRowBytes;
160 SkImageInfo fInfo;
161};
162
163/////////////////////////////////////////////////////////////////////////////////////////////
164
fmalita9a5d1ab2015-07-27 10:27:28 -0700165class SK_API SkAutoPixmapStorage : public SkPixmap {
reed183b57f2015-06-05 14:33:17 -0700166public:
167 SkAutoPixmapStorage();
168 ~SkAutoPixmapStorage();
169
170 /**
171 * Try to allocate memory for the pixels needed to match the specified Info. On success
172 * return true and fill out the pixmap to point to that memory. The storage will be freed
173 * when this object is destroyed, or if another call to tryAlloc() or alloc() is made.
174 *
175 * On failure, return false and reset() the pixmap to empty.
176 */
177 bool tryAlloc(const SkImageInfo&);
178
179 /**
180 * Allocate memory for the pixels needed to match the specified Info and fill out the pixmap
181 * to point to that memory. The storage will be freed when this object is destroyed,
182 * or if another call to tryAlloc() or alloc() is made.
183 *
184 * If the memory cannot be allocated, calls sk_throw().
185 */
186 void alloc(const SkImageInfo&);
187
fmalita3a94c6c2016-02-04 13:09:59 -0800188 /**
189 * Returns an SkData object wrapping the allocated pixels memory, and resets the pixmap.
190 * If the storage hasn't been allocated, the result is NULL.
191 */
192 const SkData* SK_WARN_UNUSED_RESULT detachPixelsAsData();
193
reed7aefe032015-06-08 10:22:22 -0700194 // We wrap these so we can clear our internal storage
195
196 void reset() {
197 this->freeStorage();
198 this->INHERITED::reset();
199 }
200 void reset(const SkImageInfo& info, const void* addr, size_t rb, SkColorTable* ctable = NULL) {
201 this->freeStorage();
202 this->INHERITED::reset(info, addr, rb, ctable);
203 }
204 void reset(const SkImageInfo& info) {
205 this->freeStorage();
206 this->INHERITED::reset(info);
207 }
208 bool SK_WARN_UNUSED_RESULT reset(const SkMask& mask) {
209 this->freeStorage();
210 return this->INHERITED::reset(mask);
211 }
212
reed183b57f2015-06-05 14:33:17 -0700213private:
214 void* fStorage;
reed7aefe032015-06-08 10:22:22 -0700215
216 void freeStorage() {
217 sk_free(fStorage);
fmalita3a94c6c2016-02-04 13:09:59 -0800218 fStorage = nullptr;
reed7aefe032015-06-08 10:22:22 -0700219 }
220
221 typedef SkPixmap INHERITED;
reed183b57f2015-06-05 14:33:17 -0700222};
223
224/////////////////////////////////////////////////////////////////////////////////////////////
225
fmalita9a5d1ab2015-07-27 10:27:28 -0700226class SK_API SkAutoPixmapUnlock : ::SkNoncopyable {
reed92fc2ae2015-05-22 08:06:21 -0700227public:
228 SkAutoPixmapUnlock() : fUnlockProc(NULL), fIsLocked(false) {}
229 SkAutoPixmapUnlock(const SkPixmap& pm, void (*unlock)(void*), void* ctx)
230 : fUnlockProc(unlock), fUnlockContext(ctx), fPixmap(pm), fIsLocked(true)
231 {}
232 ~SkAutoPixmapUnlock() { this->unlock(); }
233
234 /**
235 * Return the currently locked pixmap. Undefined if it has been unlocked.
236 */
237 const SkPixmap& pixmap() const {
238 SkASSERT(this->isLocked());
239 return fPixmap;
240 }
241
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 */
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
263private:
264 void (*fUnlockProc)(void*);
265 void* fUnlockContext;
266 SkPixmap fPixmap;
267 bool fIsLocked;
268
269 friend class SkBitmap;
270};
271
272#endif