blob: 3f517c1e6ed3d1a452b84874ebfe6c413dcf3cee [file] [log] [blame]
/*
* Copyright 2020 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrPixmap_DEFINED
#define GrPixmap_DEFINED
#include "include/core/SkData.h"
#include "include/core/SkPixmap.h"
#include "src/gpu/ganesh/GrImageInfo.h"
template <typename T, typename DERIVED> class GrPixmapBase {
public:
const GrImageInfo& info() const { return fInfo; }
const GrColorInfo& colorInfo() const { return fInfo.colorInfo(); }
T* addr() const { return fAddr; }
size_t rowBytes() const { return fRowBytes; }
bool hasPixels() const { return SkToBool(fAddr); }
bool ownsPixels() const { return SkToBool(fPixelStorage); }
sk_sp<SkData> pixelStorage() const { return fPixelStorage; }
int width() const { return fInfo.width(); }
int height() const { return fInfo.height(); }
SkISize dimensions() const { return fInfo.dimensions(); }
GrColorType colorType() const { return fInfo.colorType(); }
SkAlphaType alphaType() const { return fInfo.alphaType(); }
SkColorSpace* colorSpace() const { return fInfo.colorSpace(); }
sk_sp<SkColorSpace> refColorSpace() const { return fInfo.refColorSpace(); }
/**
* Map this pixmap to a rect in a surface of indicated dimensions at offset surfacePt. Clip the
* logical rectangle to the bounds of the surface. If the rect does not intersect the surface
* bounds or is empty then return a default GrPixmap. Otherwise, surfacePt is updated to refer
* to the upper left of the clipped rectangle. The returned pixmap will refer to the portion
* of the original pixmap inside the surface bounds.
*/
DERIVED clip(SkISize surfaceDims, SkIPoint* surfacePt) {
auto bounds = SkIRect::MakeSize(surfaceDims);
auto rect = SkIRect::MakePtSize(*surfacePt, this->dimensions());
if (!rect.intersect(bounds)) {
return {};
}
T* addr = static_cast<sknonstd::copy_const_t<char, T>*>(fAddr) +
(rect.fTop - surfacePt->fY) * fRowBytes +
(rect.fLeft - surfacePt->fX) * fInfo.bpp();
surfacePt->fX = rect.fLeft;
surfacePt->fY = rect.fTop;
return DERIVED{this->info().makeDimensions(rect.size()), addr, fRowBytes};
}
protected:
GrPixmapBase() = default;
GrPixmapBase(const GrPixmapBase& that) = default;
GrPixmapBase(GrPixmapBase&& that) = default;
GrPixmapBase& operator=(const GrPixmapBase& that) = default;
GrPixmapBase& operator=(GrPixmapBase&& that) = default;
GrPixmapBase(GrImageInfo info, T* addr, size_t rowBytes)
: fAddr(addr), fRowBytes(rowBytes), fInfo(std::move(info)) {
if (fRowBytes < fInfo.minRowBytes() || !addr) {
*this = {};
}
}
GrPixmapBase(GrImageInfo info, sk_sp<SkData> storage, size_t rowBytes)
: GrPixmapBase(std::move(info), const_cast<void*>(storage->data()), rowBytes) {
fPixelStorage = std::move(storage);
}
private:
T* fAddr = nullptr;
size_t fRowBytes = 0;
GrImageInfo fInfo;
sk_sp<SkData> fPixelStorage;
};
/** A pixmap with mutable pixels. */
class GrPixmap : public GrPixmapBase<void, GrPixmap> {
public:
GrPixmap() = default;
GrPixmap(const GrPixmap&) = default;
GrPixmap(GrPixmap&&) = default;
GrPixmap& operator=(const GrPixmap&) = default;
GrPixmap& operator=(GrPixmap&&) = default;
GrPixmap(GrImageInfo info, void* addr, size_t rowBytes)
: GrPixmapBase(std::move(info), addr, rowBytes) {}
/* implicit */ GrPixmap(const SkPixmap& pixmap)
: GrPixmapBase(pixmap.info(), pixmap.writable_addr(), pixmap.rowBytes()) {}
/**
* Returns a GrPixmap that owns its backing store. Copies of the pixmap (as GrPixmap or
* GrCPixmap) will share ownership.
*/
static GrPixmap Allocate(const GrImageInfo& info) {
size_t rb = info.minRowBytes();
size_t size = info.height()*rb;
if (!size) {
return {};
}
return GrPixmap(info, SkData::MakeUninitialized(size), rb);
}
private:
GrPixmap(GrImageInfo info, sk_sp<SkData> storage, size_t rowBytes)
: GrPixmapBase(std::move(info), std::move(storage), rowBytes) {}
};
/**
* A pixmap with immutable pixels. Note that this pixmap need not be the unique owner of the pixels
* and thus it is context-dependent whether the pixels could be manipulated externally.
*/
class GrCPixmap : public GrPixmapBase<const void, GrCPixmap> {
public:
GrCPixmap() = default;
GrCPixmap(const GrCPixmap&) = default;
GrCPixmap(GrCPixmap&&) = default;
GrCPixmap& operator=(const GrCPixmap&) = default;
GrCPixmap& operator=(GrCPixmap&&) = default;
/* implicit*/ GrCPixmap(const GrPixmap& pixmap) {
if (auto storage = pixmap.pixelStorage()) {
*this = GrCPixmap(pixmap.info(), std::move(storage), pixmap.rowBytes());
} else {
*this = GrCPixmap(pixmap.info(), pixmap.addr(), pixmap.rowBytes());
}
}
/* implicit */ GrCPixmap(const SkPixmap& pixmap)
: GrPixmapBase(pixmap.info(), pixmap.addr(), pixmap.rowBytes()) {}
GrCPixmap(GrImageInfo info, const void* addr, size_t rowBytes)
: GrPixmapBase(std::move(info), addr, rowBytes) {}
private:
GrCPixmap(GrImageInfo info, sk_sp<SkData> storage, size_t rowBytes)
: GrPixmapBase(std::move(info), std::move(storage), rowBytes) {}
};
#endif