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 "include/core/SkBitmap.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkData.h"
11 #include "include/core/SkPixelRef.h"
12 #include "include/core/SkSurface.h"
13 #include "include/private/SkImageInfoPriv.h"
14 #include "src/codec/SkColorTable.h"
15 #include "src/core/SkCompressedDataUtils.h"
16 #include "src/core/SkConvertPixels.h"
17 #include "src/core/SkImagePriv.h"
18 #include "src/core/SkTLazy.h"
19 #include "src/image/SkImage_Base.h"
20 #include "src/shaders/SkBitmapProcShader.h"
21
22 #if SK_SUPPORT_GPU
23 #include "src/gpu/SkGr.h"
24 #include "src/gpu/effects/GrBicubicEffect.h"
25 #include "src/gpu/effects/GrTextureEffect.h"
26 #endif
27
28 // fixes https://bug.skia.org/5096
is_not_subset(const SkBitmap & bm)29 static bool is_not_subset(const SkBitmap& bm) {
30 SkASSERT(bm.pixelRef());
31 SkISize dim = SkISize::Make(bm.pixelRef()->width(), bm.pixelRef()->height());
32 SkASSERT(dim != bm.dimensions() || bm.pixelRefOrigin().isZero());
33 return dim == bm.dimensions();
34 }
35
36 class SkImage_Raster : public SkImage_Base {
37 public:
ValidArgs(const SkImageInfo & info,size_t rowBytes,size_t * minSize)38 static bool ValidArgs(const SkImageInfo& info, size_t rowBytes, size_t* minSize) {
39 const int maxDimension = SK_MaxS32 >> 2;
40
41 // TODO(mtklein): eliminate anything here that setInfo() has already checked.
42 SkBitmap dummy;
43 if (!dummy.setInfo(info, rowBytes)) {
44 return false;
45 }
46
47 if (info.width() <= 0 || info.height() <= 0) {
48 return false;
49 }
50 if (info.width() > maxDimension || info.height() > maxDimension) {
51 return false;
52 }
53 if ((unsigned)info.colorType() > (unsigned)kLastEnum_SkColorType) {
54 return false;
55 }
56 if ((unsigned)info.alphaType() > (unsigned)kLastEnum_SkAlphaType) {
57 return false;
58 }
59
60 if (kUnknown_SkColorType == info.colorType()) {
61 return false;
62 }
63 if (!info.validRowBytes(rowBytes)) {
64 return false;
65 }
66
67 size_t size = info.computeByteSize(rowBytes);
68 if (SkImageInfo::ByteSizeOverflowed(size)) {
69 return false;
70 }
71
72 if (minSize) {
73 *minSize = size;
74 }
75 return true;
76 }
77
78 SkImage_Raster(const SkImageInfo&, sk_sp<SkData>, size_t rb,
79 uint32_t id = kNeedNewImageUniqueID);
80 ~SkImage_Raster() override;
81
82 bool onReadPixels(GrDirectContext*, const SkImageInfo&, void*, size_t, int srcX, int srcY,
83 CachingHint) const override;
84 bool onPeekPixels(SkPixmap*) const override;
onPeekBitmap() const85 const SkBitmap* onPeekBitmap() const override { return &fBitmap; }
86
87 bool getROPixels(GrDirectContext*, SkBitmap*, CachingHint) const override;
88 sk_sp<SkImage> onMakeSubset(const SkIRect&, GrDirectContext*) const override;
89
getPixelRef() const90 SkPixelRef* getPixelRef() const { return fBitmap.pixelRef(); }
91
92 bool onAsLegacyBitmap(GrDirectContext*, SkBitmap*) const override;
93
SkImage_Raster(const SkBitmap & bm,bool bitmapMayBeMutable=false)94 SkImage_Raster(const SkBitmap& bm, bool bitmapMayBeMutable = false)
95 : INHERITED(bm.info(),
96 is_not_subset(bm) ? bm.getGenerationID() : (uint32_t)kNeedNewImageUniqueID)
97 , fBitmap(bm) {
98 SkASSERT(bitmapMayBeMutable || fBitmap.isImmutable());
99 }
100
101 sk_sp<SkImage> onMakeColorTypeAndColorSpace(SkColorType, sk_sp<SkColorSpace>,
102 GrDirectContext*) const override;
103
104 sk_sp<SkImage> onReinterpretColorSpace(sk_sp<SkColorSpace>) const override;
105
onIsValid(GrRecordingContext * context) const106 bool onIsValid(GrRecordingContext* context) const override { return true; }
notifyAddedToRasterCache() const107 void notifyAddedToRasterCache() const override {
108 // We explicitly DON'T want to call INHERITED::notifyAddedToRasterCache. That ties the
109 // lifetime of derived/cached resources to the image. In this case, we only want cached
110 // data (eg mips) tied to the lifetime of the underlying pixelRef.
111 SkASSERT(fBitmap.pixelRef());
112 fBitmap.pixelRef()->notifyAddedToCache();
113 }
114
115 #if SK_SUPPORT_GPU
116 bool onPinAsTexture(GrRecordingContext*) const override;
117 void onUnpinAsTexture(GrRecordingContext*) const override;
118 bool isPinnedOnContext(GrRecordingContext*) const override;
119 #endif
120
onHasMipmaps() const121 bool onHasMipmaps() const override { return SkToBool(fBitmap.fMips); }
122
onPeekMips() const123 SkMipmap* onPeekMips() const override { return fBitmap.fMips.get(); }
124
onMakeWithMipmaps(sk_sp<SkMipmap> mips) const125 sk_sp<SkImage> onMakeWithMipmaps(sk_sp<SkMipmap> mips) const override {
126 auto img = new SkImage_Raster(fBitmap);
127 if (mips) {
128 img->fBitmap.fMips = std::move(mips);
129 } else {
130 img->fBitmap.fMips.reset(SkMipmap::Build(fBitmap.pixmap(), nullptr));
131 }
132 return sk_sp<SkImage>(img);
133 }
134
135 private:
136 #if SK_SUPPORT_GPU
137 std::tuple<GrSurfaceProxyView, GrColorType> onAsView(GrRecordingContext*,
138 GrMipmapped,
139 GrImageTexGenPolicy) const override;
140
141 std::unique_ptr<GrFragmentProcessor> onAsFragmentProcessor(GrRecordingContext*,
142 SkSamplingOptions,
143 const SkTileMode[2],
144 const SkMatrix&,
145 const SkRect*,
146 const SkRect*) const override;
147 #endif
148
149 SkBitmap fBitmap;
150
151 #if SK_SUPPORT_GPU
152 mutable GrSurfaceProxyView fPinnedView;
153 mutable int32_t fPinnedCount = 0;
154 mutable uint32_t fPinnedUniqueID = SK_InvalidUniqueID;
155 mutable uint32_t fPinnedContextID = SK_InvalidUniqueID;
156 mutable GrColorType fPinnedColorType = GrColorType::kUnknown;
157 #endif
158
159 using INHERITED = SkImage_Base;
160 };
161
162 ///////////////////////////////////////////////////////////////////////////////
163
release_data(void * addr,void * context)164 static void release_data(void* addr, void* context) {
165 SkData* data = static_cast<SkData*>(context);
166 data->unref();
167 }
168
SkImage_Raster(const SkImageInfo & info,sk_sp<SkData> data,size_t rowBytes,uint32_t id)169 SkImage_Raster::SkImage_Raster(const SkImageInfo& info, sk_sp<SkData> data, size_t rowBytes,
170 uint32_t id)
171 : INHERITED(info, id) {
172 void* addr = const_cast<void*>(data->data());
173
174 fBitmap.installPixels(info, addr, rowBytes, release_data, data.release());
175 fBitmap.setImmutable();
176 }
177
~SkImage_Raster()178 SkImage_Raster::~SkImage_Raster() {
179 #if SK_SUPPORT_GPU
180 SkASSERT(!fPinnedView); // want the caller to have manually unpinned
181 #endif
182 }
183
onReadPixels(GrDirectContext *,const SkImageInfo & dstInfo,void * dstPixels,size_t dstRowBytes,int srcX,int srcY,CachingHint) const184 bool SkImage_Raster::onReadPixels(GrDirectContext*,
185 const SkImageInfo& dstInfo,
186 void* dstPixels,
187 size_t dstRowBytes,
188 int srcX,
189 int srcY,
190 CachingHint) const {
191 SkBitmap shallowCopy(fBitmap);
192 return shallowCopy.readPixels(dstInfo, dstPixels, dstRowBytes, srcX, srcY);
193 }
194
onPeekPixels(SkPixmap * pm) const195 bool SkImage_Raster::onPeekPixels(SkPixmap* pm) const {
196 return fBitmap.peekPixels(pm);
197 }
198
getROPixels(GrDirectContext *,SkBitmap * dst,CachingHint) const199 bool SkImage_Raster::getROPixels(GrDirectContext*, SkBitmap* dst, CachingHint) const {
200 *dst = fBitmap;
201 return true;
202 }
203
204 #if SK_SUPPORT_GPU
onPinAsTexture(GrRecordingContext * rContext) const205 bool SkImage_Raster::onPinAsTexture(GrRecordingContext* rContext) const {
206 if (fPinnedView) {
207 SkASSERT(fPinnedCount > 0);
208 SkASSERT(fPinnedUniqueID != 0);
209 if (rContext->priv().contextID() != fPinnedContextID) {
210 return false;
211 }
212 } else {
213 SkASSERT(fPinnedCount == 0);
214 SkASSERT(fPinnedUniqueID == 0);
215 std::tie(fPinnedView, fPinnedColorType) = GrMakeCachedBitmapProxyView(rContext,
216 fBitmap,
217 GrMipmapped::kNo);
218 if (!fPinnedView) {
219 fPinnedColorType = GrColorType::kUnknown;
220 return false;
221 }
222 fPinnedUniqueID = fBitmap.getGenerationID();
223 fPinnedContextID = rContext->priv().contextID();
224 }
225 // Note: we only increment if the texture was successfully pinned
226 ++fPinnedCount;
227 return true;
228 }
229
onUnpinAsTexture(GrRecordingContext * rContext) const230 void SkImage_Raster::onUnpinAsTexture(GrRecordingContext* rContext) const {
231 // Note: we always decrement, even if fPinnedTexture is null
232 SkASSERT(fPinnedCount > 0);
233 SkASSERT(fPinnedUniqueID != 0);
234 #if 0 // This would be better but Android currently calls with an already freed context ptr.
235 if (rContext->priv().contextID() != fPinnedContextID) {
236 return;
237 }
238 #endif
239
240 if (0 == --fPinnedCount) {
241 fPinnedView = GrSurfaceProxyView();
242 fPinnedUniqueID = SK_InvalidUniqueID;
243 fPinnedContextID = SK_InvalidUniqueID;
244 fPinnedColorType = GrColorType::kUnknown;
245 }
246 }
247
isPinnedOnContext(GrRecordingContext * rContext) const248 bool SkImage_Raster::isPinnedOnContext(GrRecordingContext* rContext) const {
249 return fPinnedContextID == rContext->priv().contextID();
250 }
251 #endif
252
onMakeSubset(const SkIRect & subset,GrDirectContext *) const253 sk_sp<SkImage> SkImage_Raster::onMakeSubset(const SkIRect& subset, GrDirectContext*) const {
254 SkImageInfo info = fBitmap.info().makeDimensions(subset.size());
255 SkBitmap bitmap;
256 if (!bitmap.tryAllocPixels(info)) {
257 return nullptr;
258 }
259
260 void* dst = bitmap.getPixels();
261 void* src = fBitmap.getAddr(subset.x(), subset.y());
262 if (!dst || !src) {
263 SkDEBUGFAIL("SkImage_Raster::onMakeSubset with nullptr src or dst");
264 return nullptr;
265 }
266
267 SkRectMemcpy(dst, bitmap.rowBytes(), src, fBitmap.rowBytes(), bitmap.rowBytes(),
268 subset.height());
269
270 bitmap.setImmutable();
271 return bitmap.asImage();
272 }
273
274 ///////////////////////////////////////////////////////////////////////////////
275
MakeRasterCopyPriv(const SkPixmap & pmap,uint32_t id)276 sk_sp<SkImage> MakeRasterCopyPriv(const SkPixmap& pmap, uint32_t id) {
277 size_t size;
278 if (!SkImage_Raster::ValidArgs(pmap.info(), pmap.rowBytes(), &size) || !pmap.addr()) {
279 return nullptr;
280 }
281
282 // Here we actually make a copy of the caller's pixel data
283 sk_sp<SkData> data(SkData::MakeWithCopy(pmap.addr(), size));
284 return sk_make_sp<SkImage_Raster>(pmap.info(), std::move(data), pmap.rowBytes(), id);
285 }
286
MakeRasterCopy(const SkPixmap & pmap)287 sk_sp<SkImage> SkImage::MakeRasterCopy(const SkPixmap& pmap) {
288 return MakeRasterCopyPriv(pmap, kNeedNewImageUniqueID);
289 }
290
MakeRasterData(const SkImageInfo & info,sk_sp<SkData> data,size_t rowBytes)291 sk_sp<SkImage> SkImage::MakeRasterData(const SkImageInfo& info, sk_sp<SkData> data,
292 size_t rowBytes) {
293 size_t size;
294 if (!SkImage_Raster::ValidArgs(info, rowBytes, &size) || !data) {
295 return nullptr;
296 }
297
298 // did they give us enough data?
299 if (data->size() < size) {
300 return nullptr;
301 }
302
303 return sk_make_sp<SkImage_Raster>(info, std::move(data), rowBytes);
304 }
305
306 // TODO: this could be improved to decode and make use of the mipmap
307 // levels potentially present in the compressed data. For now, any
308 // mipmap levels are discarded.
MakeRasterFromCompressed(sk_sp<SkData> data,int width,int height,CompressionType type)309 sk_sp<SkImage> SkImage::MakeRasterFromCompressed(sk_sp<SkData> data,
310 int width, int height,
311 CompressionType type) {
312 size_t expectedSize = SkCompressedFormatDataSize(type, { width, height }, false);
313 if (!data || data->size() < expectedSize) {
314 return nullptr;
315 }
316
317 SkAlphaType at = SkCompressionTypeIsOpaque(type) ? kOpaque_SkAlphaType
318 : kPremul_SkAlphaType;
319
320 SkImageInfo ii = SkImageInfo::MakeN32(width, height, at);
321
322 if (!SkImage_Raster::ValidArgs(ii, ii.minRowBytes(), nullptr)) {
323 return nullptr;
324 }
325
326 SkBitmap bitmap;
327 if (!bitmap.tryAllocPixels(ii)) {
328 return nullptr;
329 }
330
331 if (!SkDecompress(std::move(data), { width, height }, type, &bitmap)) {
332 return nullptr;
333 }
334
335 bitmap.setImmutable();
336 return MakeFromBitmap(bitmap);
337 }
338
MakeFromRaster(const SkPixmap & pmap,RasterReleaseProc proc,ReleaseContext ctx)339 sk_sp<SkImage> SkImage::MakeFromRaster(const SkPixmap& pmap, RasterReleaseProc proc,
340 ReleaseContext ctx) {
341 size_t size;
342 if (!SkImage_Raster::ValidArgs(pmap.info(), pmap.rowBytes(), &size) || !pmap.addr()) {
343 return nullptr;
344 }
345
346 sk_sp<SkData> data(SkData::MakeWithProc(pmap.addr(), size, proc, ctx));
347 return sk_make_sp<SkImage_Raster>(pmap.info(), std::move(data), pmap.rowBytes());
348 }
349
SkMakeImageFromRasterBitmapPriv(const SkBitmap & bm,SkCopyPixelsMode cpm,uint32_t idForCopy)350 sk_sp<SkImage> SkMakeImageFromRasterBitmapPriv(const SkBitmap& bm, SkCopyPixelsMode cpm,
351 uint32_t idForCopy) {
352 if (kAlways_SkCopyPixelsMode == cpm || (!bm.isImmutable() && kNever_SkCopyPixelsMode != cpm)) {
353 SkPixmap pmap;
354 if (bm.peekPixels(&pmap)) {
355 return MakeRasterCopyPriv(pmap, idForCopy);
356 } else {
357 return sk_sp<SkImage>();
358 }
359 }
360
361 return sk_make_sp<SkImage_Raster>(bm, kNever_SkCopyPixelsMode == cpm);
362 }
363
SkMakeImageFromRasterBitmap(const SkBitmap & bm,SkCopyPixelsMode cpm)364 sk_sp<SkImage> SkMakeImageFromRasterBitmap(const SkBitmap& bm, SkCopyPixelsMode cpm) {
365 if (!SkImageInfoIsValid(bm.info()) || bm.rowBytes() < bm.info().minRowBytes()) {
366 return nullptr;
367 }
368
369 return SkMakeImageFromRasterBitmapPriv(bm, cpm, kNeedNewImageUniqueID);
370 }
371
SkBitmapImageGetPixelRef(const SkImage * image)372 const SkPixelRef* SkBitmapImageGetPixelRef(const SkImage* image) {
373 return ((const SkImage_Raster*)image)->getPixelRef();
374 }
375
onAsLegacyBitmap(GrDirectContext *,SkBitmap * bitmap) const376 bool SkImage_Raster::onAsLegacyBitmap(GrDirectContext*, SkBitmap* bitmap) const {
377 // When we're a snapshot from a surface, our bitmap may not be marked immutable
378 // even though logically always we are, but in that case we can't physically share our
379 // pixelref since the caller might call setImmutable() themselves
380 // (thus changing our state).
381 if (fBitmap.isImmutable()) {
382 SkIPoint origin = fBitmap.pixelRefOrigin();
383 bitmap->setInfo(fBitmap.info(), fBitmap.rowBytes());
384 bitmap->setPixelRef(sk_ref_sp(fBitmap.pixelRef()), origin.x(), origin.y());
385 return true;
386 }
387 return this->INHERITED::onAsLegacyBitmap(nullptr, bitmap);
388 }
389
390 ///////////////////////////////////////////////////////////////////////////////
391
onMakeColorTypeAndColorSpace(SkColorType targetCT,sk_sp<SkColorSpace> targetCS,GrDirectContext *) const392 sk_sp<SkImage> SkImage_Raster::onMakeColorTypeAndColorSpace(SkColorType targetCT,
393 sk_sp<SkColorSpace> targetCS,
394 GrDirectContext*) const {
395 SkPixmap src;
396 SkAssertResult(fBitmap.peekPixels(&src));
397
398 SkBitmap dst;
399 dst.allocPixels(fBitmap.info().makeColorType(targetCT).makeColorSpace(targetCS));
400
401 SkAssertResult(dst.writePixels(src));
402 dst.setImmutable();
403 return dst.asImage();
404 }
405
onReinterpretColorSpace(sk_sp<SkColorSpace> newCS) const406 sk_sp<SkImage> SkImage_Raster::onReinterpretColorSpace(sk_sp<SkColorSpace> newCS) const {
407 // TODO: If our bitmap is immutable, then we could theoretically create another image sharing
408 // our pixelRef. That doesn't work (without more invasive logic), because the image gets its
409 // gen ID from the bitmap, which gets it from the pixelRef.
410 SkPixmap pixmap = fBitmap.pixmap();
411 pixmap.setColorSpace(std::move(newCS));
412 return SkImage::MakeRasterCopy(pixmap);
413 }
414
415 #if SK_SUPPORT_GPU
onAsView(GrRecordingContext * rContext,GrMipmapped mipmapped,GrImageTexGenPolicy policy) const416 std::tuple<GrSurfaceProxyView, GrColorType> SkImage_Raster::onAsView(
417 GrRecordingContext* rContext,
418 GrMipmapped mipmapped,
419 GrImageTexGenPolicy policy) const {
420 if (fPinnedView) {
421 if (policy != GrImageTexGenPolicy::kDraw) {
422 return {CopyView(rContext, fPinnedView, mipmapped, policy), fPinnedColorType};
423 }
424 if (mipmapped == GrMipmapped::kYes) {
425 auto view = FindOrMakeCachedMipmappedView(rContext, fPinnedView, fPinnedUniqueID);
426 return {std::move(view), fPinnedColorType};
427 }
428 return {fPinnedView, fPinnedColorType};
429 }
430 if (policy == GrImageTexGenPolicy::kDraw) {
431 return GrMakeCachedBitmapProxyView(rContext, fBitmap, mipmapped);
432 }
433 auto budgeted = (policy == GrImageTexGenPolicy::kNew_Uncached_Unbudgeted)
434 ? SkBudgeted::kNo
435 : SkBudgeted::kYes;
436 return GrMakeUncachedBitmapProxyView(rContext,
437 fBitmap,
438 mipmapped,
439 SkBackingFit::kExact,
440 budgeted);
441 }
442
onAsFragmentProcessor(GrRecordingContext * rContext,SkSamplingOptions sampling,const SkTileMode tileModes[2],const SkMatrix & m,const SkRect * subset,const SkRect * domain) const443 std::unique_ptr<GrFragmentProcessor> SkImage_Raster::onAsFragmentProcessor(
444 GrRecordingContext* rContext,
445 SkSamplingOptions sampling,
446 const SkTileMode tileModes[2],
447 const SkMatrix& m,
448 const SkRect* subset,
449 const SkRect* domain) const {
450 auto mm = sampling.mipmap == SkMipmapMode::kNone ? GrMipmapped::kNo : GrMipmapped::kYes;
451 return MakeFragmentProcessorFromView(rContext,
452 std::get<0>(this->asView(rContext, mm)),
453 this->alphaType(),
454 sampling,
455 tileModes,
456 m,
457 subset,
458 domain);
459 }
460 #endif
461