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 "SkColorSpaceXformPriv.h" 14 #include "SkColorTable.h" 15 #include "SkData.h" 16 #include "SkImagePriv.h" 17 #include "SkPixelRef.h" 18 #include "SkSurface.h" 19 #include "SkTLazy.h" 20 #include "SkUnPreMultiplyPriv.h" 21 22 #if SK_SUPPORT_GPU 23 #include "GrContext.h" 24 #include "GrTextureAdjuster.h" 25 #include "SkGr.h" 26 #endif 27 28 // fixes https://bug.skia.org/5096 29 static bool is_not_subset(const SkBitmap& bm) { 30 SkASSERT(bm.pixelRef()); 31 SkISize dim = bm.pixelRef()->info().dimensions(); 32 SkASSERT(dim != bm.dimensions() || bm.pixelRefOrigin().isZero()); 33 return dim == bm.dimensions(); 34 } 35 36 class SkImage_Raster : public SkImage_Base { 37 public: 38 static bool ValidArgs(const Info& info, size_t rowBytes, bool hasColorTable, 39 size_t* minSize) { 40 const int maxDimension = SK_MaxS32 >> 2; 41 42 if (info.width() <= 0 || info.height() <= 0) { 43 return false; 44 } 45 if (info.width() > maxDimension || info.height() > maxDimension) { 46 return false; 47 } 48 if ((unsigned)info.colorType() > (unsigned)kLastEnum_SkColorType) { 49 return false; 50 } 51 if ((unsigned)info.alphaType() > (unsigned)kLastEnum_SkAlphaType) { 52 return false; 53 } 54 55 if (kUnknown_SkColorType == info.colorType()) { 56 return false; 57 } 58 59 const bool needsCT = kIndex_8_SkColorType == info.colorType(); 60 if (needsCT != hasColorTable) { 61 return false; 62 } 63 64 if (rowBytes < info.minRowBytes()) { 65 return false; 66 } 67 68 size_t size = info.getSafeSize(rowBytes); 69 if (0 == 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, SkColorTable*); 80 ~SkImage_Raster() override; 81 82 SkImageInfo onImageInfo() const override { 83 return fBitmap.info(); 84 } 85 SkAlphaType onAlphaType() const override { 86 return fBitmap.alphaType(); 87 } 88 89 bool onReadPixels(const SkImageInfo&, void*, size_t, int srcX, int srcY, CachingHint) const override; 90 bool onPeekPixels(SkPixmap*) const override; 91 const SkBitmap* onPeekBitmap() const override { return &fBitmap; } 92 93 #if SK_SUPPORT_GPU 94 sk_sp<GrTextureProxy> asTextureProxyRef(GrContext*, const GrSamplerParams&, 95 SkColorSpace*, sk_sp<SkColorSpace>*, 96 SkScalar scaleAdjust[2]) const override; 97 #endif 98 99 bool getROPixels(SkBitmap*, SkColorSpace* dstColorSpace, CachingHint) const override; 100 sk_sp<SkImage> onMakeSubset(const SkIRect&) const override; 101 102 SkPixelRef* getPixelRef() const { return fBitmap.pixelRef(); } 103 104 bool onAsLegacyBitmap(SkBitmap*, LegacyBitmapMode) const override; 105 106 SkImage_Raster(const SkBitmap& bm, bool bitmapMayBeMutable = false) 107 : INHERITED(bm.width(), bm.height(), 108 is_not_subset(bm) ? bm.getGenerationID() 109 : (uint32_t)kNeedNewImageUniqueID) 110 , fBitmap(bm) 111 { 112 if (bm.pixelRef()->isPreLocked()) { 113 // we only preemptively lock if there is no chance of triggering something expensive 114 // like a lazy decode or imagegenerator. PreLocked means it is flat pixels already. 115 fBitmap.lockPixels(); 116 } 117 SkASSERT(bitmapMayBeMutable || fBitmap.isImmutable()); 118 } 119 120 bool onIsLazyGenerated() const override { 121 return fBitmap.pixelRef() && fBitmap.pixelRef()->isLazyGenerated(); 122 } 123 124 sk_sp<SkImage> onMakeColorSpace(sk_sp<SkColorSpace>) const override; 125 126 #if SK_SUPPORT_GPU 127 sk_sp<GrTextureProxy> refPinnedTextureProxy(uint32_t* uniqueID) const override; 128 bool onPinAsTexture(GrContext*) const override; 129 void onUnpinAsTexture(GrContext*) const override; 130 #endif 131 132 private: 133 SkBitmap fBitmap; 134 135 #if SK_SUPPORT_GPU 136 mutable sk_sp<GrTextureProxy> fPinnedProxy; 137 mutable int32_t fPinnedCount = 0; 138 mutable uint32_t fPinnedUniqueID = 0; 139 #endif 140 141 typedef SkImage_Base INHERITED; 142 }; 143 144 /////////////////////////////////////////////////////////////////////////////// 145 146 static void release_data(void* addr, void* context) { 147 SkData* data = static_cast<SkData*>(context); 148 data->unref(); 149 } 150 151 SkImage_Raster::SkImage_Raster(const Info& info, sk_sp<SkData> data, size_t rowBytes, 152 SkColorTable* ctable) 153 : INHERITED(info.width(), info.height(), kNeedNewImageUniqueID) 154 { 155 void* addr = const_cast<void*>(data->data()); 156 157 fBitmap.installPixels(info, addr, rowBytes, ctable, release_data, data.release()); 158 fBitmap.setImmutable(); 159 fBitmap.lockPixels(); 160 } 161 162 SkImage_Raster::~SkImage_Raster() { 163 #if SK_SUPPORT_GPU 164 SkASSERT(nullptr == fPinnedProxy.get()); // want the caller to have manually unpinned 165 #endif 166 } 167 168 bool SkImage_Raster::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, 169 int srcX, int srcY, CachingHint) const { 170 SkBitmap shallowCopy(fBitmap); 171 return shallowCopy.readPixels(dstInfo, dstPixels, dstRowBytes, srcX, srcY); 172 } 173 174 bool SkImage_Raster::onPeekPixels(SkPixmap* pm) const { 175 return fBitmap.peekPixels(pm); 176 } 177 178 bool SkImage_Raster::getROPixels(SkBitmap* dst, SkColorSpace* dstColorSpace, CachingHint) const { 179 *dst = fBitmap; 180 return true; 181 } 182 183 #if SK_SUPPORT_GPU 184 sk_sp<GrTextureProxy> SkImage_Raster::asTextureProxyRef(GrContext* context, 185 const GrSamplerParams& params, 186 SkColorSpace* dstColorSpace, 187 sk_sp<SkColorSpace>* texColorSpace, 188 SkScalar scaleAdjust[2]) const { 189 if (!context) { 190 return nullptr; 191 } 192 193 if (texColorSpace) { 194 *texColorSpace = sk_ref_sp(fBitmap.colorSpace()); 195 } 196 197 uint32_t uniqueID; 198 sk_sp<GrTextureProxy> tex = this->refPinnedTextureProxy(&uniqueID); 199 if (tex) { 200 GrTextureAdjuster adjuster(context, fPinnedProxy, 201 fBitmap.alphaType(), fBitmap.bounds(), 202 fPinnedUniqueID, fBitmap.colorSpace()); 203 return adjuster.refTextureProxySafeForParams(params, nullptr, scaleAdjust); 204 } 205 206 return GrRefCachedBitmapTextureProxy(context, fBitmap, params, scaleAdjust); 207 } 208 #endif 209 210 #if SK_SUPPORT_GPU 211 212 sk_sp<GrTextureProxy> SkImage_Raster::refPinnedTextureProxy(uint32_t* uniqueID) const { 213 if (fPinnedProxy) { 214 SkASSERT(fPinnedCount > 0); 215 SkASSERT(fPinnedUniqueID != 0); 216 *uniqueID = fPinnedUniqueID; 217 return fPinnedProxy; 218 } 219 return nullptr; 220 } 221 222 bool SkImage_Raster::onPinAsTexture(GrContext* ctx) const { 223 if (fPinnedProxy) { 224 SkASSERT(fPinnedCount > 0); 225 SkASSERT(fPinnedUniqueID != 0); 226 } else { 227 SkASSERT(fPinnedCount == 0); 228 SkASSERT(fPinnedUniqueID == 0); 229 fPinnedProxy = GrRefCachedBitmapTextureProxy(ctx, fBitmap, 230 GrSamplerParams::ClampNoFilter(), nullptr); 231 if (!fPinnedProxy) { 232 return false; 233 } 234 fPinnedUniqueID = fBitmap.getGenerationID(); 235 } 236 // Note: we only increment if the texture was successfully pinned 237 ++fPinnedCount; 238 return true; 239 } 240 241 void SkImage_Raster::onUnpinAsTexture(GrContext* ctx) const { 242 // Note: we always decrement, even if fPinnedTexture is null 243 SkASSERT(fPinnedCount > 0); 244 SkASSERT(fPinnedUniqueID != 0); 245 246 if (0 == --fPinnedCount) { 247 fPinnedProxy.reset(nullptr); 248 fPinnedUniqueID = 0; 249 } 250 } 251 #endif 252 253 sk_sp<SkImage> SkImage_Raster::onMakeSubset(const SkIRect& subset) const { 254 // TODO : could consider heurist of sharing pixels, if subset is pretty close to complete 255 256 SkImageInfo info = SkImageInfo::MakeN32(subset.width(), subset.height(), fBitmap.alphaType()); 257 auto surface(SkSurface::MakeRaster(info)); 258 if (!surface) { 259 return nullptr; 260 } 261 surface->getCanvas()->clear(0); 262 surface->getCanvas()->drawImage(this, SkIntToScalar(-subset.x()), SkIntToScalar(-subset.y()), 263 nullptr); 264 return surface->makeImageSnapshot(); 265 } 266 267 /////////////////////////////////////////////////////////////////////////////// 268 269 sk_sp<SkImage> SkImage::MakeRasterCopy(const SkPixmap& pmap) { 270 size_t size; 271 if (!SkImage_Raster::ValidArgs(pmap.info(), pmap.rowBytes(), 272 pmap.ctable() != nullptr, &size) || !pmap.addr()) { 273 return nullptr; 274 } 275 276 // Here we actually make a copy of the caller's pixel data 277 sk_sp<SkData> data(SkData::MakeWithCopy(pmap.addr(), size)); 278 return sk_make_sp<SkImage_Raster>(pmap.info(), std::move(data), pmap.rowBytes(), pmap.ctable()); 279 } 280 281 282 sk_sp<SkImage> SkImage::MakeRasterData(const SkImageInfo& info, sk_sp<SkData> data, 283 size_t rowBytes) { 284 size_t size; 285 if (!SkImage_Raster::ValidArgs(info, rowBytes, false, &size) || !data) { 286 return nullptr; 287 } 288 289 // did they give us enough data? 290 if (data->size() < size) { 291 return nullptr; 292 } 293 294 SkColorTable* ctable = nullptr; 295 return sk_make_sp<SkImage_Raster>(info, std::move(data), rowBytes, ctable); 296 } 297 298 sk_sp<SkImage> SkImage::MakeFromRaster(const SkPixmap& pmap, RasterReleaseProc proc, 299 ReleaseContext ctx) { 300 size_t size; 301 if (!SkImage_Raster::ValidArgs(pmap.info(), pmap.rowBytes(), pmap.ctable(), &size) || 302 !pmap.addr()) 303 { 304 return nullptr; 305 } 306 307 sk_sp<SkData> data(SkData::MakeWithProc(pmap.addr(), size, proc, ctx)); 308 return sk_make_sp<SkImage_Raster>(pmap.info(), std::move(data), pmap.rowBytes(), pmap.ctable()); 309 } 310 311 sk_sp<SkImage> SkMakeImageFromRasterBitmap(const SkBitmap& bm, SkCopyPixelsMode cpm) { 312 bool hasColorTable = false; 313 if (kIndex_8_SkColorType == bm.colorType()) { 314 SkAutoLockPixels autoLockPixels(bm); 315 hasColorTable = bm.getColorTable() != nullptr; 316 } 317 318 if (!SkImage_Raster::ValidArgs(bm.info(), bm.rowBytes(), hasColorTable, nullptr)) { 319 return nullptr; 320 } 321 322 if (kAlways_SkCopyPixelsMode == cpm || (!bm.isImmutable() && kNever_SkCopyPixelsMode != cpm)) { 323 SkBitmap tmp(bm); 324 tmp.lockPixels(); 325 SkPixmap pmap; 326 if (tmp.getPixels() && tmp.peekPixels(&pmap)) { 327 return SkImage::MakeRasterCopy(pmap); 328 } 329 } else { 330 return sk_make_sp<SkImage_Raster>(bm, kNever_SkCopyPixelsMode == cpm); 331 } 332 return sk_sp<SkImage>(); 333 } 334 335 const SkPixelRef* SkBitmapImageGetPixelRef(const SkImage* image) { 336 return ((const SkImage_Raster*)image)->getPixelRef(); 337 } 338 339 bool SkImage_Raster::onAsLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode mode) const { 340 if (kRO_LegacyBitmapMode == mode) { 341 // When we're a snapshot from a surface, our bitmap may not be marked immutable 342 // even though logically always we are, but in that case we can't physically share our 343 // pixelref since the caller might call setImmutable() themselves 344 // (thus changing our state). 345 if (fBitmap.isImmutable()) { 346 bitmap->setInfo(fBitmap.info(), fBitmap.rowBytes()); 347 bitmap->setPixelRef(sk_ref_sp(fBitmap.pixelRef()), 348 fBitmap.pixelRefOrigin().x(), 349 fBitmap.pixelRefOrigin().y()); 350 return true; 351 } 352 } 353 return this->INHERITED::onAsLegacyBitmap(bitmap, mode); 354 } 355 356 /////////////////////////////////////////////////////////////////////////////// 357 358 static inline void do_color_xform_non_linear_blending(SkBitmap* dst, const SkPixmap& src) { 359 SkDEBUGCODE(SkColorSpaceTransferFn fn;); 360 SkASSERT(dst->colorSpace()->isNumericalTransferFn(&fn) && 361 src.colorSpace()->isNumericalTransferFn(&fn)); 362 363 void* dstPixels = dst->getPixels(); 364 const void* srcPixels = src.addr(); 365 size_t dstRowBytes = dst->rowBytes(); 366 size_t srcRowBytes = src.rowBytes(); 367 if (kN32_SkColorType != src.colorType()) { 368 SkAssertResult(src.readPixels(src.info().makeColorType(kN32_SkColorType), dstPixels, 369 dstRowBytes, 0, 0)); 370 371 srcPixels = dstPixels; 372 srcRowBytes = dstRowBytes; 373 } 374 375 std::unique_ptr<SkColorSpaceXform> xform = SkColorSpaceXform_Base::New( 376 src.colorSpace(), dst->colorSpace(), SkTransferFunctionBehavior::kIgnore); 377 378 void* dstRow = dstPixels; 379 const void* srcRow = srcPixels; 380 for (int y = 0; y < dst->height(); y++) { 381 // This function assumes non-linear blending. Which means that we must start by 382 // unpremultiplying in the gamma encoded space. 383 const void* tmpRow = srcRow; 384 if (kPremul_SkAlphaType == src.alphaType()) { 385 SkUnpremultiplyRow<false>((uint32_t*) dstRow, (const uint32_t*) srcRow, dst->width()); 386 tmpRow = dstRow; 387 } 388 389 SkColorSpaceXform::ColorFormat fmt = select_xform_format(kN32_SkColorType); 390 SkAssertResult(xform->apply(fmt, dstRow, fmt, tmpRow, dst->width(), dst->alphaType())); 391 392 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); 393 srcRow = SkTAddOffset<const void>(srcRow, srcRowBytes); 394 } 395 } 396 397 sk_sp<SkImage> SkImage_Raster::onMakeColorSpace(sk_sp<SkColorSpace> target) const { 398 // Force the color type of the new image to be kN32_SkColorType. 399 // (1) This means we lose precision on F16 images. This is necessary while this function is 400 // used to pre-transform inputs to a legacy canvas. Legacy canvases do not handle F16. 401 // (2) kIndex8 and kGray8 must be expanded in order perform a color space transformation. 402 // (3) Seems reasonable to expand k565 and k4444. It's nice to avoid these color types for 403 // clients who opt into color space support. 404 SkImageInfo dstInfo = fBitmap.info().makeColorType(kN32_SkColorType).makeColorSpace(target); 405 SkBitmap dst; 406 dst.allocPixels(dstInfo); 407 408 SkPixmap src; 409 SkTLazy<SkBitmap> tmp; 410 if (!fBitmap.peekPixels(&src)) { 411 tmp.init(fBitmap); 412 tmp.get()->lockPixels(); 413 SkAssertResult(tmp.get()->peekPixels(&src)); 414 } 415 416 // Treat nullptr srcs as sRGB. 417 if (!src.colorSpace()) { 418 src.setColorSpace(SkColorSpace::MakeSRGB()); 419 } 420 421 do_color_xform_non_linear_blending(&dst, src); 422 dst.setImmutable(); 423 return SkImage::MakeFromBitmap(dst); 424 } 425