Plumb dst color space in many places, rather than "mode"
[platform/upstream/libSkiaSharp.git] / src / image / SkImage_Raster.cpp
1 /*
2  * Copyright 2012 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 #include "SkImage_Base.h"
9 #include "SkBitmap.h"
10 #include "SkBitmapProcShader.h"
11 #include "SkCanvas.h"
12 #include "SkColorTable.h"
13 #include "SkData.h"
14 #include "SkImagePriv.h"
15 #include "SkPixelRef.h"
16 #include "SkSurface.h"
17
18 #if SK_SUPPORT_GPU
19 #include "GrContext.h"
20 #include "GrTextureAdjuster.h"
21 #include "SkGr.h"
22 #include "SkGrPriv.h"
23 #endif
24
25 // fixes https://bug.skia.org/5096
26 static bool is_not_subset(const SkBitmap& bm) {
27     SkASSERT(bm.pixelRef());
28     SkISize dim = bm.pixelRef()->info().dimensions();
29     SkASSERT(dim != bm.dimensions() || bm.pixelRefOrigin().isZero());
30     return dim == bm.dimensions();
31 }
32
33 class SkImage_Raster : public SkImage_Base {
34 public:
35     static bool ValidArgs(const Info& info, size_t rowBytes, bool hasColorTable,
36                           size_t* minSize) {
37         const int maxDimension = SK_MaxS32 >> 2;
38
39         if (info.width() <= 0 || info.height() <= 0) {
40             return false;
41         }
42         if (info.width() > maxDimension || info.height() > maxDimension) {
43             return false;
44         }
45         if ((unsigned)info.colorType() > (unsigned)kLastEnum_SkColorType) {
46             return false;
47         }
48         if ((unsigned)info.alphaType() > (unsigned)kLastEnum_SkAlphaType) {
49             return false;
50         }
51
52         if (kUnknown_SkColorType == info.colorType()) {
53             return false;
54         }
55
56         const bool needsCT = kIndex_8_SkColorType == info.colorType();
57         if (needsCT != hasColorTable) {
58             return false;
59         }
60
61         if (rowBytes < info.minRowBytes()) {
62             return false;
63         }
64
65         size_t size = info.getSafeSize(rowBytes);
66         if (0 == size) {
67             return false;
68         }
69
70         if (minSize) {
71             *minSize = size;
72         }
73         return true;
74     }
75
76     SkImage_Raster(const SkImageInfo&, sk_sp<SkData>, size_t rb, SkColorTable*);
77     virtual ~SkImage_Raster();
78
79     SkImageInfo onImageInfo() const override {
80         return fBitmap.info();
81     }
82     SkAlphaType onAlphaType() const override {
83         return fBitmap.alphaType();
84     }
85
86     bool onReadPixels(const SkImageInfo&, void*, size_t, int srcX, int srcY, CachingHint) const override;
87     bool onPeekPixels(SkPixmap*) const override;
88     const SkBitmap* onPeekBitmap() const override { return &fBitmap; }
89
90     bool getROPixels(SkBitmap*, SkColorSpace* dstColorSpace, CachingHint) const override;
91     GrTexture* asTextureRef(GrContext*, const GrSamplerParams&, SkColorSpace*,
92                             sk_sp<SkColorSpace>*) const override;
93     sk_sp<SkImage> onMakeSubset(const SkIRect&) const override;
94
95     // exposed for SkSurface_Raster via SkNewImageFromPixelRef
96     SkImage_Raster(const SkImageInfo&, SkPixelRef*, const SkIPoint& origin, size_t rowBytes);
97
98     SkPixelRef* getPixelRef() const { return fBitmap.pixelRef(); }
99
100     bool onAsLegacyBitmap(SkBitmap*, LegacyBitmapMode) const override;
101
102     SkImage_Raster(const SkBitmap& bm, bool bitmapMayBeMutable = false)
103         : INHERITED(bm.width(), bm.height(),
104                     is_not_subset(bm) ? bm.getGenerationID()
105                                       : (uint32_t)kNeedNewImageUniqueID)
106         , fBitmap(bm)
107     {
108         if (bm.pixelRef()->isPreLocked()) {
109             // we only preemptively lock if there is no chance of triggering something expensive
110             // like a lazy decode or imagegenerator. PreLocked means it is flat pixels already.
111             fBitmap.lockPixels();
112         }
113         SkASSERT(bitmapMayBeMutable || fBitmap.isImmutable());
114     }
115
116     bool onIsLazyGenerated() const override {
117         return fBitmap.pixelRef() && fBitmap.pixelRef()->isLazyGenerated();
118     }
119
120 #if SK_SUPPORT_GPU
121     sk_sp<GrTexture> refPinnedTexture(uint32_t* uniqueID) const override;
122     bool onPinAsTexture(GrContext*) const override;
123     void onUnpinAsTexture(GrContext*) const override;
124 #endif
125
126 private:
127     SkBitmap fBitmap;
128
129 #if SK_SUPPORT_GPU
130     mutable sk_sp<GrTexture> fPinnedTexture;
131     mutable int32_t fPinnedCount = 0;
132     mutable uint32_t fPinnedUniqueID = 0;
133 #endif
134
135     typedef SkImage_Base INHERITED;
136 };
137
138 ///////////////////////////////////////////////////////////////////////////////
139
140 static void release_data(void* addr, void* context) {
141     SkData* data = static_cast<SkData*>(context);
142     data->unref();
143 }
144
145 SkImage_Raster::SkImage_Raster(const Info& info, sk_sp<SkData> data, size_t rowBytes,
146                                SkColorTable* ctable)
147     : INHERITED(info.width(), info.height(), kNeedNewImageUniqueID)
148 {
149     void* addr = const_cast<void*>(data->data());
150
151     fBitmap.installPixels(info, addr, rowBytes, ctable, release_data, data.release());
152     fBitmap.setImmutable();
153     fBitmap.lockPixels();
154 }
155
156 SkImage_Raster::SkImage_Raster(const Info& info, SkPixelRef* pr, const SkIPoint& pixelRefOrigin,
157                                size_t rowBytes)
158     : INHERITED(info.width(), info.height(), pr->getGenerationID())
159 {
160     fBitmap.setInfo(info, rowBytes);
161     fBitmap.setPixelRef(pr, pixelRefOrigin);
162     fBitmap.lockPixels();
163     SkASSERT(fBitmap.isImmutable());
164 }
165
166 SkImage_Raster::~SkImage_Raster() {
167 #if SK_SUPPORT_GPU
168     SkASSERT(nullptr == fPinnedTexture.get());  // want the caller to have manually unpinned
169 #endif
170 }
171
172 bool SkImage_Raster::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
173                                   int srcX, int srcY, CachingHint) const {
174     SkBitmap shallowCopy(fBitmap);
175     return shallowCopy.readPixels(dstInfo, dstPixels, dstRowBytes, srcX, srcY);
176 }
177
178 bool SkImage_Raster::onPeekPixels(SkPixmap* pm) const {
179     return fBitmap.peekPixels(pm);
180 }
181
182 bool SkImage_Raster::getROPixels(SkBitmap* dst, SkColorSpace* dstColorSpace, CachingHint) const {
183     *dst = fBitmap;
184     return true;
185 }
186
187 GrTexture* SkImage_Raster::asTextureRef(GrContext* ctx, const GrSamplerParams& params,
188                                         SkColorSpace* dstColorSpace,
189                                         sk_sp<SkColorSpace>* texColorSpace) const {
190 #if SK_SUPPORT_GPU
191     if (!ctx) {
192         return nullptr;
193     }
194
195     if (texColorSpace) {
196         *texColorSpace = sk_ref_sp(fBitmap.colorSpace());
197     }
198
199     uint32_t uniqueID;
200     sk_sp<GrTexture> tex = this->refPinnedTexture(&uniqueID);
201     if (tex) {
202         GrTextureAdjuster adjuster(fPinnedTexture.get(), fBitmap.alphaType(), fBitmap.bounds(),
203                                    fPinnedUniqueID, fBitmap.colorSpace());
204         return adjuster.refTextureSafeForParams(params, nullptr);
205     }
206
207     return GrRefCachedBitmapTexture(ctx, fBitmap, params);
208 #endif
209
210     return nullptr;
211 }
212
213 #if SK_SUPPORT_GPU
214
215 sk_sp<GrTexture> SkImage_Raster::refPinnedTexture(uint32_t* uniqueID) const {
216     if (fPinnedTexture) {
217         SkASSERT(fPinnedCount > 0);
218         SkASSERT(fPinnedUniqueID != 0);
219         *uniqueID = fPinnedUniqueID;
220         return fPinnedTexture;
221     }
222     return nullptr;
223 }
224
225 bool SkImage_Raster::onPinAsTexture(GrContext* ctx) const {
226     if (fPinnedTexture) {
227         SkASSERT(fPinnedCount > 0);
228         SkASSERT(fPinnedUniqueID != 0);
229         SkASSERT(fPinnedTexture->getContext() == ctx);
230     } else {
231         SkASSERT(fPinnedCount == 0);
232         SkASSERT(fPinnedUniqueID == 0);
233         fPinnedTexture.reset(
234             GrRefCachedBitmapTexture(ctx, fBitmap, GrSamplerParams::ClampNoFilter()));
235         if (!fPinnedTexture) {
236             return false;
237         }
238         fPinnedUniqueID = fBitmap.getGenerationID();
239     }
240     // Note: we only increment if the texture was successfully pinned
241     ++fPinnedCount;
242     return true;
243 }
244
245 void SkImage_Raster::onUnpinAsTexture(GrContext* ctx) const {
246     // Note: we always decrement, even if fPinnedTexture is null
247     SkASSERT(fPinnedCount > 0);
248     SkASSERT(fPinnedUniqueID != 0);
249     if (fPinnedTexture) {
250         SkASSERT(fPinnedTexture->getContext() == ctx);
251     }
252
253     if (0 == --fPinnedCount) {
254         fPinnedTexture.reset(nullptr);
255         fPinnedUniqueID = 0;
256     }
257 }
258 #endif
259
260 sk_sp<SkImage> SkImage_Raster::onMakeSubset(const SkIRect& subset) const {
261     // TODO : could consider heurist of sharing pixels, if subset is pretty close to complete
262
263     SkImageInfo info = SkImageInfo::MakeN32(subset.width(), subset.height(), fBitmap.alphaType());
264     auto surface(SkSurface::MakeRaster(info));
265     if (!surface) {
266         return nullptr;
267     }
268     surface->getCanvas()->clear(0);
269     surface->getCanvas()->drawImage(this, SkIntToScalar(-subset.x()), SkIntToScalar(-subset.y()),
270                                     nullptr);
271     return surface->makeImageSnapshot();
272 }
273
274 ///////////////////////////////////////////////////////////////////////////////
275
276 sk_sp<SkImage> SkImage::MakeRasterCopy(const SkPixmap& pmap) {
277     size_t size;
278     if (!SkImage_Raster::ValidArgs(pmap.info(), pmap.rowBytes(),
279                                    pmap.ctable() != nullptr, &size) || !pmap.addr()) {
280         return nullptr;
281     }
282
283     // Here we actually make a copy of the caller's pixel data
284     sk_sp<SkData> data(SkData::MakeWithCopy(pmap.addr(), size));
285     return sk_make_sp<SkImage_Raster>(pmap.info(), std::move(data), pmap.rowBytes(), pmap.ctable());
286 }
287
288
289 sk_sp<SkImage> SkImage::MakeRasterData(const SkImageInfo& info, sk_sp<SkData> data,
290                                        size_t rowBytes) {
291     size_t size;
292     if (!SkImage_Raster::ValidArgs(info, rowBytes, false, &size) || !data) {
293         return nullptr;
294     }
295
296     // did they give us enough data?
297     if (data->size() < size) {
298         return nullptr;
299     }
300
301     SkColorTable* ctable = nullptr;
302     return sk_make_sp<SkImage_Raster>(info, std::move(data), rowBytes, ctable);
303 }
304
305 sk_sp<SkImage> SkImage::MakeFromRaster(const SkPixmap& pmap, RasterReleaseProc proc,
306                                        ReleaseContext ctx) {
307     size_t size;
308     if (!SkImage_Raster::ValidArgs(pmap.info(), pmap.rowBytes(), false, &size) || !pmap.addr()) {
309         return nullptr;
310     }
311
312     sk_sp<SkData> data(SkData::MakeWithProc(pmap.addr(), size, proc, ctx));
313     return sk_make_sp<SkImage_Raster>(pmap.info(), std::move(data), pmap.rowBytes(), pmap.ctable());
314 }
315
316 sk_sp<SkImage> SkMakeImageFromPixelRef(const SkImageInfo& info, SkPixelRef* pr,
317                                        const SkIPoint& pixelRefOrigin, size_t rowBytes) {
318     if (!SkImage_Raster::ValidArgs(info, rowBytes, false, nullptr)) {
319         return nullptr;
320     }
321     return sk_make_sp<SkImage_Raster>(info, pr, pixelRefOrigin, rowBytes);
322 }
323
324 sk_sp<SkImage> SkMakeImageFromRasterBitmap(const SkBitmap& bm, SkCopyPixelsMode cpm,
325                                            SkTBlitterAllocator* allocator) {
326     bool hasColorTable = false;
327     if (kIndex_8_SkColorType == bm.colorType()) {
328         SkAutoLockPixels autoLockPixels(bm);
329         hasColorTable = bm.getColorTable() != nullptr;
330     }
331
332     if (!SkImage_Raster::ValidArgs(bm.info(), bm.rowBytes(), hasColorTable, nullptr)) {
333         return nullptr;
334     }
335
336     sk_sp<SkImage> image;
337     if (kAlways_SkCopyPixelsMode == cpm || (!bm.isImmutable() && kNever_SkCopyPixelsMode != cpm)) {
338         SkBitmap tmp(bm);
339         tmp.lockPixels();
340         SkPixmap pmap;
341         if (tmp.getPixels() && tmp.peekPixels(&pmap)) {
342             image = SkImage::MakeRasterCopy(pmap);
343         }
344     } else {
345         if (allocator) {
346             image.reset(allocator->createT<SkImage_Raster>(bm, kNever_SkCopyPixelsMode == cpm));
347             image.get()->ref(); // account for the allocator being an owner
348         } else {
349             image = sk_make_sp<SkImage_Raster>(bm, kNever_SkCopyPixelsMode == cpm);
350         }
351     }
352     return image;
353 }
354
355 const SkPixelRef* SkBitmapImageGetPixelRef(const SkImage* image) {
356     return ((const SkImage_Raster*)image)->getPixelRef();
357 }
358
359 bool SkImage_Raster::onAsLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode mode) const {
360     if (kRO_LegacyBitmapMode == mode) {
361         // When we're a snapshot from a surface, our bitmap may not be marked immutable
362         // even though logically always we are, but in that case we can't physically share our
363         // pixelref since the caller might call setImmutable() themselves
364         // (thus changing our state).
365         if (fBitmap.isImmutable()) {
366             bitmap->setInfo(fBitmap.info(), fBitmap.rowBytes());
367             bitmap->setPixelRef(fBitmap.pixelRef(), fBitmap.pixelRefOrigin());
368             return true;
369         }
370     }
371     return this->INHERITED::onAsLegacyBitmap(bitmap, mode);
372 }