blob: 3d55bb6b8bb4ecb31e75aaf2b23d6baa3386cc7f [file] [log] [blame]
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file
*/
#ifndef SkSpecialImage_DEFINED
#define SkSpecialImage_DEFINED
#include "include/core/SkImageInfo.h"
#include "include/core/SkRect.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkSamplingOptions.h"
#include "include/core/SkScalar.h"
#include "include/core/SkSize.h"
#include "include/core/SkSurfaceProps.h"
#include <cstddef>
#include <cstdint>
class GrRecordingContext;
class SkBitmap;
class SkCanvas;
class SkColorSpace;
class SkImage;
class SkMatrix;
class SkPaint;
class SkShader;
enum SkAlphaType : int;
enum SkColorType : int;
enum class SkTileMode;
enum {
kNeedNewImageUniqueID_SpecialImage = 0
};
/**
* This is a restricted form of SkImage solely intended for internal use. It
* differs from SkImage in that:
* - it can only be backed by raster or gpu (no generators)
* - it can be backed by a GrTextureProxy larger than its nominal bounds
* - it can't be drawn tiled
* - it can't be drawn with MIPMAPs
* It is similar to SkImage in that it abstracts how the pixels are stored/represented.
*
* Note: the contents of the backing storage outside of the subset rect are undefined.
*/
class SkSpecialImage : public SkRefCnt {
public:
typedef void* ReleaseContext;
typedef void(*RasterReleaseProc)(void* pixels, ReleaseContext);
const SkSurfaceProps& props() const { return fProps; }
int width() const { return fSubset.width(); }
int height() const { return fSubset.height(); }
SkISize dimensions() const { return { this->width(), this->height() }; }
const SkIRect& subset() const { return fSubset; }
uint32_t uniqueID() const { return fUniqueID; }
virtual SkISize backingStoreDimensions() const = 0;
virtual size_t getSize() const = 0;
bool isExactFit() const { return fSubset == SkIRect::MakeSize(this->backingStoreDimensions()); }
const SkColorInfo& colorInfo() const { return fColorInfo; }
SkAlphaType alphaType() const { return fColorInfo.alphaType(); }
SkColorType colorType() const { return fColorInfo.colorType(); }
SkColorSpace* getColorSpace() const { return fColorInfo.colorSpace(); }
/**
* Draw this SpecialImage into the canvas, automatically taking into account the image's subset
*/
void draw(SkCanvas* canvas,
SkScalar x, SkScalar y,
const SkSamplingOptions& sampling,
const SkPaint* paint,
bool strict = true) const;
void draw(SkCanvas* canvas, SkScalar x, SkScalar y) const {
this->draw(canvas, x, y, SkSamplingOptions(), nullptr);
}
/**
* Extract a subset of this special image and return it as a special image.
* It may or may not point to the same backing memory. The input 'subset' is relative to the
* special image's content rect.
*/
sk_sp<SkSpecialImage> makeSubset(const SkIRect& subset) const {
SkIRect absolute = subset.makeOffset(this->subset().topLeft());
return this->onMakeBackingStoreSubset(absolute);
}
/**
* Return a special image with a 1px larger subset in the backing store compared to this image.
* This should only be used when it's externally known that those outer pixels are valid.
*/
sk_sp<SkSpecialImage> makePixelOutset() const {
return this->onMakeBackingStoreSubset(this->subset().makeOutset(1, 1));
}
/**
* Create an SkImage view of the contents of this special image, pointing to the same
* underlying memory.
*
* TODO: If SkImages::MakeFiltered were to return an SkShader that accounted for the subset
* constraint and offset, then this could move to a private virtual for use in draw() and
* asShader().
*/
virtual sk_sp<SkImage> asImage() const = 0;
/**
* Create an SkShader that samples the contents of this special image, applying tile mode for
* any sample that falls outside its internal subset.
*
* 'strict' defaults to true and applies shader-based tiling to the subset. If the subset is
* the same as the backing store dimensions, it is automatically degraded to non-strict
* (HW tiling and sampling). 'strict' can be set to false if it's known that the subset
* boundaries aren't visible AND the texel data in adjacent rows/cols is valid to be included
* by the given sampling options.
*/
virtual sk_sp<SkShader> asShader(SkTileMode,
const SkSamplingOptions&,
const SkMatrix& lm,
bool strict=true) const;
/**
* If the SpecialImage is backed by a gpu texture, return true.
*/
virtual bool isGaneshBacked() const { return false; }
virtual bool isGraphiteBacked() const { return false; }
/**
* Return the GrRecordingContext if the SkSpecialImage is GrTexture-backed
*/
virtual GrRecordingContext* getContext() const { return nullptr; }
protected:
SkSpecialImage(const SkIRect& subset,
uint32_t uniqueID,
const SkColorInfo&,
const SkSurfaceProps&);
// This subset is relative to the backing store's coordinate frame, it has already been mapped
// from the content rect by the non-virtual makeSubset(). The provided 'subset' is not
// necessarily contained within this special image's subset.
virtual sk_sp<SkSpecialImage> onMakeBackingStoreSubset(const SkIRect& subset) const = 0;
private:
const SkIRect fSubset;
const uint32_t fUniqueID;
const SkColorInfo fColorInfo;
const SkSurfaceProps fProps;
};
namespace SkSpecialImages {
sk_sp<SkSpecialImage> MakeFromRaster(const SkIRect& subset, sk_sp<SkImage>, const SkSurfaceProps&);
sk_sp<SkSpecialImage> MakeFromRaster(const SkIRect& subset, const SkBitmap&, const SkSurfaceProps&);
sk_sp<SkSpecialImage> CopyFromRaster(const SkIRect& subset, const SkBitmap&, const SkSurfaceProps&);
bool AsBitmap(const SkSpecialImage* img, SkBitmap*);
} // namespace SkSpecialImages
#endif // SkSpecialImage_DEFINED