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 "SkColorSpaceXform_Base.h" 13#include "SkColorSpaceXformImageGenerator.h" 14#include "SkColorSpaceXformPriv.h" 15#include "SkColorTable.h" 16#include "SkData.h" 17#include "SkImageInfoPriv.h" 18#include "SkImagePriv.h" 19#include "SkPixelRef.h" 20#include "SkSurface.h" 21#include "SkTLazy.h" 22#include "SkUnPreMultiplyPriv.h" 23 24#if SK_SUPPORT_GPU 25#include "GrContext.h" 26#include "GrTextureAdjuster.h" 27#include "SkGr.h" 28#endif 29 30// fixes https://bug.skia.org/5096 31static bool is_not_subset(const SkBitmap& bm) { 32 SkASSERT(bm.pixelRef()); 33 SkISize dim = SkISize::Make(bm.pixelRef()->width(), bm.pixelRef()->height()); 34 SkASSERT(dim != bm.dimensions() || bm.pixelRefOrigin().isZero()); 35 return dim == bm.dimensions(); 36} 37 38class SkImage_Raster : public SkImage_Base { 39public: 40 static bool ValidArgs(const Info& info, size_t rowBytes, size_t* minSize) { 41 const int maxDimension = SK_MaxS32 >> 2; 42 43 if (info.width() <= 0 || info.height() <= 0) { 44 return false; 45 } 46 if (info.width() > maxDimension || info.height() > maxDimension) { 47 return false; 48 } 49 if ((unsigned)info.colorType() > (unsigned)kLastEnum_SkColorType) { 50 return false; 51 } 52 if ((unsigned)info.alphaType() > (unsigned)kLastEnum_SkAlphaType) { 53 return false; 54 } 55 56 if (kUnknown_SkColorType == info.colorType()) { 57 return false; 58 } 59 if (rowBytes < info.minRowBytes()) { 60 return false; 61 } 62 63 size_t size = info.getSafeSize(rowBytes); 64 if (0 == size) { 65 return false; 66 } 67 68 if (minSize) { 69 *minSize = size; 70 } 71 return true; 72 } 73 74 SkImage_Raster(const SkImageInfo&, sk_sp<SkData>, size_t rb, 75 uint32_t id = kNeedNewImageUniqueID); 76 ~SkImage_Raster() override; 77 78 SkImageInfo onImageInfo() const override { 79 return fBitmap.info(); 80 } 81 SkAlphaType onAlphaType() const override { 82 return fBitmap.alphaType(); 83 } 84 85 bool onReadPixels(const SkImageInfo&, void*, size_t, int srcX, int srcY, CachingHint) const override; 86 bool onPeekPixels(SkPixmap*) const override; 87 const SkBitmap* onPeekBitmap() const override { return &fBitmap; } 88 89#if SK_SUPPORT_GPU 90 sk_sp<GrTextureProxy> asTextureProxyRef(GrContext*, const GrSamplerParams&, 91 SkColorSpace*, sk_sp<SkColorSpace>*, 92 SkScalar scaleAdjust[2]) const override; 93#endif 94 95 bool getROPixels(SkBitmap*, SkColorSpace* dstColorSpace, CachingHint) const override; 96 sk_sp<SkImage> onMakeSubset(const SkIRect&) const override; 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 SkASSERT(bitmapMayBeMutable || fBitmap.isImmutable()); 109 } 110 111 sk_sp<SkImage> onMakeColorSpace(sk_sp<SkColorSpace>, SkColorType, 112 SkTransferFunctionBehavior) const override; 113 114 bool onIsValid(GrContext* context) const override { return true; } 115 116#if SK_SUPPORT_GPU 117 sk_sp<GrTextureProxy> refPinnedTextureProxy(uint32_t* uniqueID) const override; 118 bool onPinAsTexture(GrContext*) const override; 119 void onUnpinAsTexture(GrContext*) const override; 120#endif 121 122private: 123 SkBitmap fBitmap; 124 125#if SK_SUPPORT_GPU 126 mutable sk_sp<GrTextureProxy> fPinnedProxy; 127 mutable int32_t fPinnedCount = 0; 128 mutable uint32_t fPinnedUniqueID = 0; 129#endif 130 131 typedef SkImage_Base INHERITED; 132}; 133 134/////////////////////////////////////////////////////////////////////////////// 135 136static void release_data(void* addr, void* context) { 137 SkData* data = static_cast<SkData*>(context); 138 data->unref(); 139} 140 141SkImage_Raster::SkImage_Raster(const Info& info, sk_sp<SkData> data, size_t rowBytes, uint32_t id) 142 : INHERITED(info.width(), info.height(), id) 143{ 144 void* addr = const_cast<void*>(data->data()); 145 146 fBitmap.installPixels(info, addr, rowBytes, release_data, data.release()); 147 fBitmap.setImmutable(); 148} 149 150SkImage_Raster::~SkImage_Raster() { 151#if SK_SUPPORT_GPU 152 SkASSERT(nullptr == fPinnedProxy.get()); // want the caller to have manually unpinned 153#endif 154} 155 156bool SkImage_Raster::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, 157 int srcX, int srcY, CachingHint) const { 158 SkBitmap shallowCopy(fBitmap); 159 return shallowCopy.readPixels(dstInfo, dstPixels, dstRowBytes, srcX, srcY); 160} 161 162bool SkImage_Raster::onPeekPixels(SkPixmap* pm) const { 163 return fBitmap.peekPixels(pm); 164} 165 166bool SkImage_Raster::getROPixels(SkBitmap* dst, SkColorSpace* dstColorSpace, CachingHint) const { 167 *dst = fBitmap; 168 return true; 169} 170 171#if SK_SUPPORT_GPU 172sk_sp<GrTextureProxy> SkImage_Raster::asTextureProxyRef(GrContext* context, 173 const GrSamplerParams& params, 174 SkColorSpace* dstColorSpace, 175 sk_sp<SkColorSpace>* texColorSpace, 176 SkScalar scaleAdjust[2]) const { 177 if (!context) { 178 return nullptr; 179 } 180 181 if (texColorSpace) { 182 *texColorSpace = sk_ref_sp(fBitmap.colorSpace()); 183 } 184 185 uint32_t uniqueID; 186 sk_sp<GrTextureProxy> tex = this->refPinnedTextureProxy(&uniqueID); 187 if (tex) { 188 GrTextureAdjuster adjuster(context, fPinnedProxy, 189 fBitmap.alphaType(), fBitmap.bounds(), 190 fPinnedUniqueID, fBitmap.colorSpace()); 191 return adjuster.refTextureProxySafeForParams(params, nullptr, scaleAdjust); 192 } 193 194 return GrRefCachedBitmapTextureProxy(context, fBitmap, params, scaleAdjust); 195} 196#endif 197 198#if SK_SUPPORT_GPU 199 200sk_sp<GrTextureProxy> SkImage_Raster::refPinnedTextureProxy(uint32_t* uniqueID) const { 201 if (fPinnedProxy) { 202 SkASSERT(fPinnedCount > 0); 203 SkASSERT(fPinnedUniqueID != 0); 204 *uniqueID = fPinnedUniqueID; 205 return fPinnedProxy; 206 } 207 return nullptr; 208} 209 210bool SkImage_Raster::onPinAsTexture(GrContext* ctx) const { 211 if (fPinnedProxy) { 212 SkASSERT(fPinnedCount > 0); 213 SkASSERT(fPinnedUniqueID != 0); 214 } else { 215 SkASSERT(fPinnedCount == 0); 216 SkASSERT(fPinnedUniqueID == 0); 217 fPinnedProxy = GrRefCachedBitmapTextureProxy(ctx, fBitmap, 218 GrSamplerParams::ClampNoFilter(), nullptr); 219 if (!fPinnedProxy) { 220 return false; 221 } 222 fPinnedUniqueID = fBitmap.getGenerationID(); 223 } 224 // Note: we only increment if the texture was successfully pinned 225 ++fPinnedCount; 226 return true; 227} 228 229void SkImage_Raster::onUnpinAsTexture(GrContext* ctx) const { 230 // Note: we always decrement, even if fPinnedTexture is null 231 SkASSERT(fPinnedCount > 0); 232 SkASSERT(fPinnedUniqueID != 0); 233 234 if (0 == --fPinnedCount) { 235 fPinnedProxy.reset(nullptr); 236 fPinnedUniqueID = 0; 237 } 238} 239#endif 240 241sk_sp<SkImage> SkImage_Raster::onMakeSubset(const SkIRect& subset) const { 242 // TODO : could consider heurist of sharing pixels, if subset is pretty close to complete 243 244 SkImageInfo info = SkImageInfo::MakeN32(subset.width(), subset.height(), fBitmap.alphaType()); 245 auto surface(SkSurface::MakeRaster(info)); 246 if (!surface) { 247 return nullptr; 248 } 249 surface->getCanvas()->clear(0); 250 surface->getCanvas()->drawImage(this, SkIntToScalar(-subset.x()), SkIntToScalar(-subset.y()), 251 nullptr); 252 return surface->makeImageSnapshot(); 253} 254 255/////////////////////////////////////////////////////////////////////////////// 256 257sk_sp<SkImage> MakeRasterCopyPriv(const SkPixmap& pmap, uint32_t id) { 258 size_t size; 259 if (!SkImage_Raster::ValidArgs(pmap.info(), pmap.rowBytes(), &size) || !pmap.addr()) { 260 return nullptr; 261 } 262 263 // Here we actually make a copy of the caller's pixel data 264 sk_sp<SkData> data(SkData::MakeWithCopy(pmap.addr(), size)); 265 return sk_make_sp<SkImage_Raster>(pmap.info(), std::move(data), pmap.rowBytes(), id); 266} 267 268sk_sp<SkImage> SkImage::MakeRasterCopy(const SkPixmap& pmap) { 269 return MakeRasterCopyPriv(pmap, kNeedNewImageUniqueID); 270} 271 272sk_sp<SkImage> SkImage::MakeRasterData(const SkImageInfo& info, sk_sp<SkData> data, 273 size_t rowBytes) { 274 size_t size; 275 if (!SkImage_Raster::ValidArgs(info, rowBytes, &size) || !data) { 276 return nullptr; 277 } 278 279 // did they give us enough data? 280 if (data->size() < size) { 281 return nullptr; 282 } 283 284 return sk_make_sp<SkImage_Raster>(info, std::move(data), rowBytes); 285} 286 287sk_sp<SkImage> SkImage::MakeFromRaster(const SkPixmap& pmap, RasterReleaseProc proc, 288 ReleaseContext ctx) { 289 size_t size; 290 if (!SkImage_Raster::ValidArgs(pmap.info(), pmap.rowBytes(), &size) || !pmap.addr()) { 291 return nullptr; 292 } 293 294 sk_sp<SkData> data(SkData::MakeWithProc(pmap.addr(), size, proc, ctx)); 295 return sk_make_sp<SkImage_Raster>(pmap.info(), std::move(data), pmap.rowBytes()); 296} 297 298sk_sp<SkImage> SkMakeImageFromRasterBitmapPriv(const SkBitmap& bm, SkCopyPixelsMode cpm, 299 uint32_t idForCopy) { 300 if (kAlways_SkCopyPixelsMode == cpm || (!bm.isImmutable() && kNever_SkCopyPixelsMode != cpm)) { 301 SkPixmap pmap; 302 if (bm.peekPixels(&pmap)) { 303 return MakeRasterCopyPriv(pmap, idForCopy); 304 } else { 305 return sk_sp<SkImage>(); 306 } 307 } 308 309 return sk_make_sp<SkImage_Raster>(bm, kNever_SkCopyPixelsMode == cpm); 310} 311 312sk_sp<SkImage> SkMakeImageFromRasterBitmap(const SkBitmap& bm, SkCopyPixelsMode cpm) { 313 if (!SkImageInfoIsValidAllowNumericalCS(bm.info()) || bm.rowBytes() < bm.info().minRowBytes()) { 314 return nullptr; 315 } 316 317 return SkMakeImageFromRasterBitmapPriv(bm, cpm, kNeedNewImageUniqueID); 318} 319 320sk_sp<SkImage> SkMakeImageInColorSpace(const SkBitmap& bm, sk_sp<SkColorSpace> dstCS, uint32_t id, 321 SkCopyPixelsMode cpm) { 322 if (!SkImageInfoIsValidAllowNumericalCS(bm.info()) || !bm.getPixels() || 323 bm.rowBytes() < bm.info().minRowBytes() || !dstCS) { 324 return nullptr; 325 } 326 327 sk_sp<SkColorSpace> srcCS = bm.info().refColorSpace(); 328 if (!srcCS) { 329 // Treat nullptr as sRGB. 330 srcCS = SkColorSpace::MakeSRGB(); 331 } 332 333 sk_sp<SkImage> image = nullptr; 334 335 // For the Android use case, this is very likely to be true. 336 if (SkColorSpace::Equals(srcCS.get(), dstCS.get())) { 337 SkASSERT(kNeedNewImageUniqueID == id || bm.getGenerationID() == id); 338 image = SkMakeImageFromRasterBitmapPriv(bm, cpm, id); 339 } else { 340 image = SkImage::MakeFromGenerator(SkColorSpaceXformImageGenerator::Make(bm, dstCS, cpm, 341 id)); 342 } 343 344 // If the caller suplied an id, we must propagate that to the image we return 345 SkASSERT(kNeedNewImageUniqueID == id || image->uniqueID() == id); 346 return image; 347} 348 349const SkPixelRef* SkBitmapImageGetPixelRef(const SkImage* image) { 350 return ((const SkImage_Raster*)image)->getPixelRef(); 351} 352 353bool SkImage_Raster::onAsLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode mode) const { 354 if (kRO_LegacyBitmapMode == mode) { 355 // When we're a snapshot from a surface, our bitmap may not be marked immutable 356 // even though logically always we are, but in that case we can't physically share our 357 // pixelref since the caller might call setImmutable() themselves 358 // (thus changing our state). 359 if (fBitmap.isImmutable()) { 360 bitmap->setInfo(fBitmap.info(), fBitmap.rowBytes()); 361 bitmap->setPixelRef(sk_ref_sp(fBitmap.pixelRef()), 362 fBitmap.pixelRefOrigin().x(), 363 fBitmap.pixelRefOrigin().y()); 364 return true; 365 } 366 } 367 return this->INHERITED::onAsLegacyBitmap(bitmap, mode); 368} 369 370/////////////////////////////////////////////////////////////////////////////// 371 372sk_sp<SkImage> SkImage_Raster::onMakeColorSpace(sk_sp<SkColorSpace> target, 373 SkColorType targetColorType, 374 SkTransferFunctionBehavior premulBehavior) const { 375 SkPixmap src; 376 SkAssertResult(fBitmap.peekPixels(&src)); 377 378 // Treat nullptr srcs as sRGB. 379 if (!src.colorSpace()) { 380 if (target->isSRGB()) { 381 return sk_ref_sp(const_cast<SkImage*>((SkImage*)this)); 382 } 383 384 src.setColorSpace(SkColorSpace::MakeSRGB()); 385 } 386 387 SkImageInfo dstInfo = fBitmap.info().makeColorType(targetColorType).makeColorSpace(target); 388 SkBitmap dst; 389 dst.allocPixels(dstInfo); 390 391 SkAssertResult(dst.writePixels(src, 0, 0, premulBehavior)); 392 dst.setImmutable(); 393 return SkImage::MakeFromBitmap(dst); 394} 395