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