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