1 /*
2  * Copyright 2016 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 SkSpecialImage_DEFINED
9 #define SkSpecialImage_DEFINED
10 
11 #include "include/core/SkImageInfo.h"
12 #include "include/core/SkRefCnt.h"
13 #include "include/core/SkSurfaceProps.h"
14 #include "src/core/SkNextID.h"
15 
16 #if SK_SUPPORT_GPU
17 #include "include/private/GrTypesPriv.h"
18 #endif
19 
20 class GrRecordingContext;
21 class GrTextureProxy;
22 class SkBitmap;
23 class SkCanvas;
24 class SkImage;
25 struct SkImageInfo;
26 class SkPaint;
27 class SkPixmap;
28 class SkSpecialSurface;
29 class SkSurface;
30 
31 enum {
32     kNeedNewImageUniqueID_SpecialImage = 0
33 };
34 
35 /**
36  * This is a restricted form of SkImage solely intended for internal use. It
37  * differs from SkImage in that:
38  *      - it can only be backed by raster or gpu (no generators)
39  *      - it can be backed by a GrTextureProxy larger than its nominal bounds
40  *      - it can't be drawn tiled
41  *      - it can't be drawn with MIPMAPs
42  * It is similar to SkImage in that it abstracts how the pixels are stored/represented.
43  *
44  * Note: the contents of the backing storage outside of the subset rect are undefined.
45  */
46 class SkSpecialImage : public SkRefCnt {
47 public:
48     typedef void* ReleaseContext;
49     typedef void(*RasterReleaseProc)(void* pixels, ReleaseContext);
50 
props()51     const SkSurfaceProps& props() const { return fProps; }
52 
width()53     int width() const { return fSubset.width(); }
height()54     int height() const { return fSubset.height(); }
subset()55     const SkIRect& subset() const { return fSubset; }
56     SkColorSpace* getColorSpace() const;
57 
uniqueID()58     uint32_t uniqueID() const { return fUniqueID; }
59     virtual SkAlphaType alphaType() const = 0;
60     virtual SkColorType colorType() const = 0;
61     virtual size_t getSize() const = 0;
62 
63     /**
64      *  Ensures that a special image is backed by a texture (when GrRecordingContext is non-null).
65      *  If no transformation is required, the returned image may be the same as this special image.
66      *  If this special image is from a different GrRecordingContext, this will fail.
67      */
68     sk_sp<SkSpecialImage> makeTextureImage(GrRecordingContext*) const;
69 
70     /**
71      *  Draw this SpecialImage into the canvas, automatically taking into account the image's subset
72      */
73     void draw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) const;
74 
75     static sk_sp<SkSpecialImage> MakeFromImage(GrRecordingContext*,
76                                                const SkIRect& subset,
77                                                sk_sp<SkImage>,
78                                                const SkSurfaceProps* = nullptr);
79     static sk_sp<SkSpecialImage> MakeFromRaster(const SkIRect& subset,
80                                                 const SkBitmap&,
81                                                 const SkSurfaceProps* = nullptr);
82     static sk_sp<SkSpecialImage> CopyFromRaster(const SkIRect& subset,
83                                                 const SkBitmap&,
84                                                 const SkSurfaceProps* = nullptr);
85 #if SK_SUPPORT_GPU
86     static sk_sp<SkSpecialImage> MakeDeferredFromGpu(GrRecordingContext*,
87                                                      const SkIRect& subset,
88                                                      uint32_t uniqueID,
89                                                      sk_sp<GrTextureProxy>,
90                                                      GrColorType,
91                                                      sk_sp<SkColorSpace>,
92                                                      const SkSurfaceProps* = nullptr,
93                                                      SkAlphaType at = kPremul_SkAlphaType);
94 #endif
95 
96     /**
97      *  Create a new special surface with a backend that is compatible with this special image.
98      */
99     sk_sp<SkSpecialSurface> makeSurface(SkColorType colorType,
100                                         const SkColorSpace* colorSpace,
101                                         const SkISize& size,
102                                         SkAlphaType at = kPremul_SkAlphaType,
103                                         const SkSurfaceProps* props = nullptr) const;
104 
105     /**
106      * Create a new surface with a backend that is compatible with this special image.
107      * TODO: switch this to makeSurface once we resolved the naming issue
108      * TODO (michaelludwig) - This is only used by SkTileImageFilter, which appears should be
109      * updated to work correctly with subsets and then makeTightSurface() can go away entirely.
110      */
111     sk_sp<SkSurface> makeTightSurface(SkColorType colorType,
112                                       const SkColorSpace* colorSpace,
113                                       const SkISize& size,
114                                       SkAlphaType at = kPremul_SkAlphaType) const;
115 
116     /**
117      * Extract a subset of this special image and return it as a special image.
118      * It may or may not point to the same backing memory. The input 'subset' is relative to the
119      * special image's content rect.
120      */
121     sk_sp<SkSpecialImage> makeSubset(const SkIRect& subset) const;
122 
123     /**
124      * Create an SkImage from the contents of this special image optionally extracting a subset.
125      * It may or may not point to the same backing memory.
126      * Note: when no 'subset' parameter is specified the the entire SkSpecialImage will be
127      * returned - including whatever extra padding may have resulted from a loose fit!
128      * When the 'subset' parameter is specified the returned image will be tight even if that
129      * entails a copy! The 'subset' is relative to this special image's content rect.
130      */
131     sk_sp<SkImage> asImage(const SkIRect* subset = nullptr) const;
132 
133     /**
134      *  If the SpecialImage is backed by a gpu texture, return true.
135      */
136     bool isTextureBacked() const;
137 
138     /**
139      * Return the GrRecordingContext if the SkSpecialImage is GrTexture-backed
140      */
141     GrRecordingContext* getContext() const;
142 
143 #if SK_SUPPORT_GPU
144     /**
145      * Regardless of how the underlying backing data is stored, returns the contents as a
146      * GrTextureProxy. The returned proxy represents the entire backing image, so texture
147      * coordinates must be mapped from the content rect (e.g. relative to 'subset()') to the proxy's
148      * space (offset by subset().topLeft()).
149      */
150     sk_sp<GrTextureProxy> asTextureProxyRef(GrRecordingContext*) const;
151 #endif
152 
153     /**
154      *  Regardless of the underlying backing store, return the contents as an SkBitmap.
155      *  The returned bitmap represents the subset accessed by this image, thus (0,0) refers to the
156      *  top-left corner of 'subset'.
157      */
158     bool getROPixels(SkBitmap*) const;
159 
160 protected:
161     SkSpecialImage(const SkIRect& subset, uint32_t uniqueID, const SkSurfaceProps*);
162 
163 private:
164     const SkSurfaceProps fProps;
165     const SkIRect        fSubset;
166     const uint32_t       fUniqueID;
167 
168     typedef SkRefCnt INHERITED;
169 };
170 
171 #endif
172