Home | History | Annotate | Download | only in core
      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:
     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 
     40     void reset();
     41     void reset(const SkImageInfo& info, const void* addr, size_t rowBytes,
     42                SkColorTable* ctable = NULL);
     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 
     61     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 
     72     SkIRect bounds() const { return SkIRect::MakeWH(this->width(), this->height()); }
     73 
     74     uint64_t getSize64() const { return sk_64_mul(fInfo.height(), fRowBytes); }
     75     uint64_t getSafeSize64() const { return fInfo.getSafeSize64(fRowBytes); }
     76     size_t getSafeSize() const { return fInfo.getSafeSize(fRowBytes); }
     77 
     78     const void* addr(int x, int y) const {
     79         return (const char*)fPixels + fInfo.computeOffset(x, y, fRowBytes);
     80     }
     81     const uint8_t* addr8() const {
     82         SkASSERT(1 == SkColorTypeBytesPerPixel(fInfo.colorType()));
     83         return reinterpret_cast<const uint8_t*>(fPixels);
     84     }
     85     const uint16_t* addr16() const {
     86         SkASSERT(2 == SkColorTypeBytesPerPixel(fInfo.colorType()));
     87         return reinterpret_cast<const uint16_t*>(fPixels);
     88     }
     89     const uint32_t* addr32() const {
     90         SkASSERT(4 == SkColorTypeBytesPerPixel(fInfo.colorType()));
     91         return reinterpret_cast<const uint32_t*>(fPixels);
     92     }
     93     const uint64_t* addr64() const {
     94         SkASSERT(8 == SkColorTypeBytesPerPixel(fInfo.colorType()));
     95         return reinterpret_cast<const uint64_t*>(fPixels);
     96     }
     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 
    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     }
    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     }
    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     }
    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     }
    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 
    132     void* writable_addr() const { return const_cast<void*>(fPixels); }
    133     uint8_t* writable_addr8(int x, int y) const {
    134         return const_cast<uint8_t*>(this->addr8(x, y));
    135     }
    136     uint16_t* writable_addr16(int x, int y) const {
    137         return const_cast<uint16_t*>(this->addr16(x, y));
    138     }
    139     uint32_t* writable_addr32(int x, int y) const {
    140         return const_cast<uint32_t*>(this->addr32(x, y));
    141     }
    142     uint64_t* writable_addr64(int x, int y) const {
    143         return const_cast<uint64_t*>(this->addr64(x, y));
    144     }
    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;
    153     bool readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes) const {
    154         return this->readPixels(dstInfo, dstPixels, dstRowBytes, 0, 0);
    155     }
    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     }
    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 
    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 
    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     }
    229     void reset(const SkImageInfo& info) {
    230         this->freeStorage();
    231         this->INHERITED::reset(info);
    232     }
    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 
    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:
    253     SkAutoPixmapUnlock() : fUnlockProc(NULL), fIsLocked(false) {}
    254     SkAutoPixmapUnlock(const SkPixmap& pm, void (*unlock)(void*), void* ctx)
    255         : fUnlockProc(unlock), fUnlockContext(ctx), fPixmap(pm), fIsLocked(true)
    256     {}
    257     ~SkAutoPixmapUnlock() { this->unlock(); }
    258 
    259     /**
    260      *  Return the currently locked pixmap. Undefined if it has been unlocked.
    261      */
    262     const SkPixmap& pixmap() const {
    263         SkASSERT(this->isLocked());
    264         return fPixmap;
    265     }
    266 
    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      */
    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