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 "SkBitmap.h" 9 #include "SkBitmapCache.h" 10 #include "SkCanvas.h" 11 #include "SkData.h" 12 #include "SkImageEncoder.h" 13 #include "SkImageGenerator.h" 14 #include "SkImagePriv.h" 15 #include "SkImageShader.h" 16 #include "SkImage_Base.h" 17 #include "SkNextID.h" 18 #include "SkPixelRef.h" 19 #include "SkPixelSerializer.h" 20 #include "SkReadPixelsRec.h" 21 #include "SkString.h" 22 #include "SkSurface.h" 23 24 #if SK_SUPPORT_GPU 25 #include "GrTexture.h" 26 #include "GrContext.h" 27 #include "SkImage_Gpu.h" 28 #endif 29 30 SkImage::SkImage(int width, int height, uint32_t uniqueID) 31 : fWidth(width) 32 , fHeight(height) 33 , fUniqueID(kNeedNewImageUniqueID == uniqueID ? SkNextID::ImageID() : uniqueID) 34 { 35 SkASSERT(width > 0); 36 SkASSERT(height > 0); 37 } 38 39 const void* SkImage::peekPixels(SkImageInfo* info, size_t* rowBytes) const { 40 SkImageInfo infoStorage; 41 size_t rowBytesStorage; 42 if (nullptr == info) { 43 info = &infoStorage; 44 } 45 if (nullptr == rowBytes) { 46 rowBytes = &rowBytesStorage; 47 } 48 return as_IB(this)->onPeekPixels(info, rowBytes); 49 } 50 51 bool SkImage::readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, 52 int srcX, int srcY, CachingHint chint) const { 53 SkReadPixelsRec rec(dstInfo, dstPixels, dstRowBytes, srcX, srcY); 54 if (!rec.trim(this->width(), this->height())) { 55 return false; 56 } 57 return as_IB(this)->onReadPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY, chint); 58 } 59 60 bool SkImage::scalePixels(const SkPixmap& dst, SkFilterQuality quality, CachingHint chint) const { 61 if (this->width() == dst.width() && this->height() == dst.height()) { 62 return this->readPixels(dst, 0, 0, chint); 63 } 64 65 // Idea: If/when SkImageGenerator supports a native-scaling API (where the generator itself 66 // can scale more efficiently) we should take advantage of it here. 67 // 68 SkBitmap bm; 69 if (as_IB(this)->getROPixels(&bm, chint)) { 70 bm.lockPixels(); 71 SkPixmap pmap; 72 // Note: By calling the pixmap scaler, we never cache the final result, so the chint 73 // is (currently) only being applied to the getROPixels. If we get a request to 74 // also attempt to cache the final (scaled) result, we would add that logic here. 75 // 76 return bm.peekPixels(&pmap) && pmap.scalePixels(dst, quality); 77 } 78 return false; 79 } 80 81 void SkImage::preroll(GrContext* ctx) const { 82 // For now, and to maintain parity w/ previous pixelref behavior, we just force the image 83 // to produce a cached raster-bitmap form, so that drawing to a raster canvas should be fast. 84 // 85 SkBitmap bm; 86 if (as_IB(this)->getROPixels(&bm)) { 87 bm.lockPixels(); 88 bm.unlockPixels(); 89 } 90 } 91 92 /////////////////////////////////////////////////////////////////////////////////////////////////// 93 94 SkShader* SkImage::newShader(SkShader::TileMode tileX, 95 SkShader::TileMode tileY, 96 const SkMatrix* localMatrix) const { 97 return SkImageShader::Create(this, tileX, tileY, localMatrix); 98 } 99 100 SkData* SkImage::encode(SkImageEncoder::Type type, int quality) const { 101 SkBitmap bm; 102 if (as_IB(this)->getROPixels(&bm)) { 103 return SkImageEncoder::EncodeData(bm, type, quality); 104 } 105 return nullptr; 106 } 107 108 SkData* SkImage::encode(SkPixelSerializer* serializer) const { 109 SkAutoTUnref<SkPixelSerializer> defaultSerializer; 110 SkPixelSerializer* effectiveSerializer = serializer; 111 if (!effectiveSerializer) { 112 defaultSerializer.reset(SkImageEncoder::CreatePixelSerializer()); 113 SkASSERT(defaultSerializer.get()); 114 effectiveSerializer = defaultSerializer.get(); 115 } 116 SkAutoTUnref<SkData> encoded(this->refEncoded()); 117 if (encoded && effectiveSerializer->useEncodedData(encoded->data(), encoded->size())) { 118 return encoded.detach(); 119 } 120 121 SkBitmap bm; 122 SkAutoPixmapUnlock apu; 123 if (as_IB(this)->getROPixels(&bm) && bm.requestLock(&apu)) { 124 return effectiveSerializer->encode(apu.pixmap()); 125 } 126 127 return nullptr; 128 } 129 130 SkData* SkImage::refEncoded() const { 131 GrContext* ctx = nullptr; // should we allow the caller to pass in a ctx? 132 return as_IB(this)->onRefEncoded(ctx); 133 } 134 135 SkImage* SkImage::NewFromEncoded(SkData* encoded, const SkIRect* subset) { 136 if (nullptr == encoded || 0 == encoded->size()) { 137 return nullptr; 138 } 139 SkImageGenerator* generator = SkImageGenerator::NewFromEncoded(encoded); 140 return generator ? SkImage::NewFromGenerator(generator, subset) : nullptr; 141 } 142 143 const char* SkImage::toString(SkString* str) const { 144 str->appendf("image: (id:%d (%d, %d) %s)", this->uniqueID(), this->width(), this->height(), 145 this->isOpaque() ? "opaque" : ""); 146 return str->c_str(); 147 } 148 149 SkImage* SkImage::newSubset(const SkIRect& subset) const { 150 if (subset.isEmpty()) { 151 return nullptr; 152 } 153 154 const SkIRect bounds = SkIRect::MakeWH(this->width(), this->height()); 155 if (!bounds.contains(subset)) { 156 return nullptr; 157 } 158 159 // optimization : return self if the subset == our bounds 160 if (bounds == subset) { 161 return SkRef(const_cast<SkImage*>(this)); 162 } 163 return as_IB(this)->onNewSubset(subset); 164 } 165 166 #if SK_SUPPORT_GPU 167 168 GrTexture* SkImage::getTexture() const { 169 return as_IB(this)->peekTexture(); 170 } 171 172 bool SkImage::isTextureBacked() const { return SkToBool(as_IB(this)->getTexture()); } 173 174 GrBackendObject SkImage::getTextureHandle(bool flushPendingGrContextIO) const { 175 GrTexture* texture = as_IB(this)->getTexture(); 176 if (texture) { 177 GrContext* context = texture->getContext(); 178 if (context) { 179 if (flushPendingGrContextIO) { 180 context->prepareSurfaceForExternalIO(texture); 181 } 182 } 183 return texture->getTextureHandle(); 184 } 185 return 0; 186 } 187 188 #else 189 190 GrTexture* SkImage::getTexture() const { return nullptr; } 191 192 bool SkImage::isTextureBacked() const { return false; } 193 194 GrBackendObject SkImage::getTextureHandle(bool) const { return 0; } 195 196 #endif 197 198 /////////////////////////////////////////////////////////////////////////////// 199 200 static bool raster_canvas_supports(const SkImageInfo& info) { 201 switch (info.colorType()) { 202 case kN32_SkColorType: 203 return kUnpremul_SkAlphaType != info.alphaType(); 204 case kRGB_565_SkColorType: 205 return true; 206 case kAlpha_8_SkColorType: 207 return true; 208 default: 209 break; 210 } 211 return false; 212 } 213 214 SkImage_Base::SkImage_Base(int width, int height, uint32_t uniqueID) 215 : INHERITED(width, height, uniqueID) 216 , fAddedToCache(false) 217 {} 218 219 SkImage_Base::~SkImage_Base() { 220 if (fAddedToCache.load()) { 221 SkNotifyBitmapGenIDIsStale(this->uniqueID()); 222 } 223 } 224 225 bool SkImage_Base::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, 226 int srcX, int srcY, CachingHint) const { 227 if (!raster_canvas_supports(dstInfo)) { 228 return false; 229 } 230 231 SkBitmap bm; 232 bm.installPixels(dstInfo, dstPixels, dstRowBytes); 233 SkCanvas canvas(bm); 234 235 SkPaint paint; 236 paint.setXfermodeMode(SkXfermode::kSrc_Mode); 237 canvas.drawImage(this, -SkIntToScalar(srcX), -SkIntToScalar(srcY), &paint); 238 239 return true; 240 } 241 242 /////////////////////////////////////////////////////////////////////////////////////////////////// 243 244 bool SkImage::peekPixels(SkPixmap* pmap) const { 245 SkImageInfo info; 246 size_t rowBytes; 247 const void* pixels = this->peekPixels(&info, &rowBytes); 248 if (pixels) { 249 if (pmap) { 250 pmap->reset(info, pixels, rowBytes); 251 } 252 return true; 253 } 254 return false; 255 } 256 257 bool SkImage::readPixels(const SkPixmap& pmap, int srcX, int srcY, CachingHint chint) const { 258 return this->readPixels(pmap.info(), pmap.writable_addr(), pmap.rowBytes(), srcX, srcY, chint); 259 } 260 261 #if SK_SUPPORT_GPU 262 #include "GrTextureToYUVPlanes.h" 263 #endif 264 265 #include "SkRGBAToYUV.h" 266 267 bool SkImage::readYUV8Planes(const SkISize sizes[3], void* const planes[3], 268 const size_t rowBytes[3], SkYUVColorSpace colorSpace) const { 269 #if SK_SUPPORT_GPU 270 if (GrTexture* texture = as_IB(this)->peekTexture()) { 271 if (GrTextureToYUVPlanes(texture, sizes, planes, rowBytes, colorSpace)) { 272 return true; 273 } 274 } 275 #endif 276 return SkRGBAToYUV(this, sizes, planes, rowBytes, colorSpace); 277 } 278 279 /////////////////////////////////////////////////////////////////////////////////////////////////// 280 281 SkImage* SkImage::NewFromBitmap(const SkBitmap& bm) { 282 SkPixelRef* pr = bm.pixelRef(); 283 if (nullptr == pr) { 284 return nullptr; 285 } 286 287 #if SK_SUPPORT_GPU 288 if (GrTexture* tex = pr->getTexture()) { 289 SkAutoTUnref<GrTexture> unrefCopy; 290 if (!bm.isImmutable()) { 291 tex = GrDeepCopyTexture(tex, SkBudgeted::kNo); 292 if (nullptr == tex) { 293 return nullptr; 294 } 295 unrefCopy.reset(tex); 296 } 297 const SkImageInfo info = bm.info(); 298 return new SkImage_Gpu(info.width(), info.height(), bm.getGenerationID(), info.alphaType(), 299 tex, SkBudgeted::kNo); 300 } 301 #endif 302 303 // This will check for immutable (share or copy) 304 return SkNewImageFromRasterBitmap(bm); 305 } 306 307 bool SkImage::asLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode mode) const { 308 return as_IB(this)->onAsLegacyBitmap(bitmap, mode); 309 } 310 311 bool SkImage_Base::onAsLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode mode) const { 312 // As the base-class, all we can do is make a copy (regardless of mode). 313 // Subclasses that want to be more optimal should override. 314 SkImageInfo info = SkImageInfo::MakeN32(this->width(), this->height(), 315 this->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType); 316 if (!bitmap->tryAllocPixels(info)) { 317 return false; 318 } 319 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), 0, 0)) { 320 bitmap->reset(); 321 return false; 322 } 323 324 if (kRO_LegacyBitmapMode == mode) { 325 bitmap->setImmutable(); 326 } 327 return true; 328 } 329 330 SkImage* SkImage::NewFromPicture(const SkPicture* picture, const SkISize& dimensions, 331 const SkMatrix* matrix, const SkPaint* paint) { 332 if (!picture) { 333 return nullptr; 334 } 335 return NewFromGenerator(SkImageGenerator::NewFromPicture(dimensions, picture, matrix, paint)); 336 } 337 338 bool SkImage::isLazyGenerated() const { 339 return as_IB(this)->onIsLazyGenerated(); 340 } 341 342 ////////////////////////////////////////////////////////////////////////////////////// 343 344 #if !SK_SUPPORT_GPU 345 346 SkImage* SkImage::NewFromTexture(GrContext*, const GrBackendTextureDesc&, SkAlphaType, 347 TextureReleaseProc, ReleaseContext) { 348 return nullptr; 349 } 350 351 SkImage* SkImage::NewFromAdoptedTexture(GrContext*, const GrBackendTextureDesc&, SkAlphaType) { 352 return nullptr; 353 } 354 355 SkImage* SkImage::NewFromTextureCopy(GrContext*, const GrBackendTextureDesc&, SkAlphaType) { 356 return nullptr; 357 } 358 359 SkImage* SkImage::newTextureImage(GrContext*) const { 360 return nullptr; 361 } 362 363 #endif 364