SkBitmapDevice.cpp revision 07764cefbb18041a77897df3453903b0a2016583
1/* 2 * Copyright 2013 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 "SkBitmapDevice.h" 9#include "SkConfig8888.h" 10#include "SkDraw.h" 11#include "SkImageFilter.h" 12#include "SkImageFilterCache.h" 13#include "SkMallocPixelRef.h" 14#include "SkMatrix.h" 15#include "SkPaint.h" 16#include "SkPath.h" 17#include "SkPixelRef.h" 18#include "SkPixmap.h" 19#include "SkRasterClip.h" 20#include "SkShader.h" 21#include "SkSpecialImage.h" 22#include "SkSurface.h" 23 24class SkColorTable; 25 26static bool valid_for_bitmap_device(const SkImageInfo& info, 27 SkAlphaType* newAlphaType) { 28 if (info.width() < 0 || info.height() < 0) { 29 return false; 30 } 31 32 // TODO: can we stop supporting kUnknown in SkBitmkapDevice? 33 if (kUnknown_SkColorType == info.colorType()) { 34 if (newAlphaType) { 35 *newAlphaType = kUnknown_SkAlphaType; 36 } 37 return true; 38 } 39 40 switch (info.alphaType()) { 41 case kPremul_SkAlphaType: 42 case kOpaque_SkAlphaType: 43 break; 44 default: 45 return false; 46 } 47 48 SkAlphaType canonicalAlphaType = info.alphaType(); 49 50 switch (info.colorType()) { 51 case kAlpha_8_SkColorType: 52 break; 53 case kRGB_565_SkColorType: 54 canonicalAlphaType = kOpaque_SkAlphaType; 55 break; 56 case kN32_SkColorType: 57 break; 58 case kRGBA_F16_SkColorType: 59 break; 60 default: 61 return false; 62 } 63 64 if (newAlphaType) { 65 *newAlphaType = canonicalAlphaType; 66 } 67 return true; 68} 69 70SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap) 71 : INHERITED(bitmap.info(), SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType)) 72 , fBitmap(bitmap) 73{ 74 SkASSERT(valid_for_bitmap_device(bitmap.info(), nullptr)); 75 fBitmap.lockPixels(); 76} 77 78SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& info) { 79 return Create(info, SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType)); 80} 81 82SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkSurfaceProps& surfaceProps) 83 : INHERITED(bitmap.info(), surfaceProps) 84 , fBitmap(bitmap) 85{ 86 SkASSERT(valid_for_bitmap_device(bitmap.info(), nullptr)); 87 fBitmap.lockPixels(); 88} 89 90SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo, 91 const SkSurfaceProps& surfaceProps) { 92 SkAlphaType newAT = origInfo.alphaType(); 93 if (!valid_for_bitmap_device(origInfo, &newAT)) { 94 return nullptr; 95 } 96 97 const SkImageInfo info = origInfo.makeAlphaType(newAT); 98 SkBitmap bitmap; 99 100 if (kUnknown_SkColorType == info.colorType()) { 101 if (!bitmap.setInfo(info)) { 102 return nullptr; 103 } 104 } else if (info.isOpaque()) { 105 // If this bitmap is opaque, we don't have any sensible default color, 106 // so we just return uninitialized pixels. 107 if (!bitmap.tryAllocPixels(info)) { 108 return nullptr; 109 } 110 } else { 111 // This bitmap has transparency, so we'll zero the pixels (to transparent). 112 // We use a ZeroedPRFactory as a faster alloc-then-eraseColor(SK_ColorTRANSPARENT). 113 SkMallocPixelRef::ZeroedPRFactory factory; 114 if (!bitmap.tryAllocPixels(info, &factory, nullptr/*color table*/)) { 115 return nullptr; 116 } 117 } 118 119 return new SkBitmapDevice(bitmap, surfaceProps); 120} 121 122void SkBitmapDevice::setNewSize(const SkISize& size) { 123 SkASSERT(!fBitmap.pixelRef()); 124 fBitmap.setInfo(fBitmap.info().makeWH(size.fWidth, size.fHeight)); 125 this->privateResize(fBitmap.info().width(), fBitmap.info().height()); 126} 127 128void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) { 129 SkASSERT(bm.width() == fBitmap.width()); 130 SkASSERT(bm.height() == fBitmap.height()); 131 fBitmap = bm; // intent is to use bm's pixelRef (and rowbytes/config) 132 fBitmap.lockPixels(); 133 this->privateResize(fBitmap.info().width(), fBitmap.info().height()); 134} 135 136SkBaseDevice* SkBitmapDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint*) { 137 const SkSurfaceProps surfaceProps(this->surfaceProps().flags(), cinfo.fPixelGeometry); 138 return SkBitmapDevice::Create(cinfo.fInfo, surfaceProps); 139} 140 141const SkBitmap& SkBitmapDevice::onAccessBitmap() { 142 return fBitmap; 143} 144 145bool SkBitmapDevice::onAccessPixels(SkPixmap* pmap) { 146 if (this->onPeekPixels(pmap)) { 147 fBitmap.notifyPixelsChanged(); 148 return true; 149 } 150 return false; 151} 152 153bool SkBitmapDevice::onPeekPixels(SkPixmap* pmap) { 154 const SkImageInfo info = fBitmap.info(); 155 if (fBitmap.getPixels() && (kUnknown_SkColorType != info.colorType())) { 156 SkColorTable* ctable = nullptr; 157 pmap->reset(fBitmap.info(), fBitmap.getPixels(), fBitmap.rowBytes(), ctable); 158 return true; 159 } 160 return false; 161} 162 163bool SkBitmapDevice::onWritePixels(const SkImageInfo& srcInfo, const void* srcPixels, 164 size_t srcRowBytes, int x, int y) { 165 // since we don't stop creating un-pixeled devices yet, check for no pixels here 166 if (nullptr == fBitmap.getPixels()) { 167 return false; 168 } 169 170 const SkImageInfo dstInfo = fBitmap.info().makeWH(srcInfo.width(), srcInfo.height()); 171 172 void* dstPixels = fBitmap.getAddr(x, y); 173 size_t dstRowBytes = fBitmap.rowBytes(); 174 175 if (SkPixelInfo::CopyPixels(dstInfo, dstPixels, dstRowBytes, srcInfo, srcPixels, srcRowBytes)) { 176 fBitmap.notifyPixelsChanged(); 177 return true; 178 } 179 return false; 180} 181 182bool SkBitmapDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, 183 int x, int y) { 184 return fBitmap.readPixels(dstInfo, dstPixels, dstRowBytes, x, y); 185} 186 187/////////////////////////////////////////////////////////////////////////////// 188 189void SkBitmapDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) { 190 draw.drawPaint(paint); 191} 192 193void SkBitmapDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count, 194 const SkPoint pts[], const SkPaint& paint) { 195 draw.drawPoints(mode, count, pts, paint); 196} 197 198void SkBitmapDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& paint) { 199 draw.drawRect(r, paint); 200} 201 202void SkBitmapDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) { 203 SkPath path; 204 path.addOval(oval); 205 // call the VIRTUAL version, so any subclasses who do handle drawPath aren't 206 // required to override drawOval. 207 this->drawPath(draw, path, paint, nullptr, true); 208} 209 210void SkBitmapDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, const SkPaint& paint) { 211#ifdef SK_IGNORE_BLURRED_RRECT_OPT 212 SkPath path; 213 214 path.addRRect(rrect); 215 // call the VIRTUAL version, so any subclasses who do handle drawPath aren't 216 // required to override drawRRect. 217 this->drawPath(draw, path, paint, nullptr, true); 218#else 219 draw.drawRRect(rrect, paint); 220#endif 221} 222 223void SkBitmapDevice::drawPath(const SkDraw& draw, const SkPath& path, 224 const SkPaint& paint, const SkMatrix* prePathMatrix, 225 bool pathIsMutable) { 226 draw.drawPath(path, paint, prePathMatrix, pathIsMutable); 227} 228 229void SkBitmapDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap, 230 const SkMatrix& matrix, const SkPaint& paint) { 231 LogDrawScaleFactor(SkMatrix::Concat(*draw.fMatrix, matrix), paint.getFilterQuality()); 232 draw.drawBitmap(bitmap, matrix, nullptr, paint); 233} 234 235static inline bool CanApplyDstMatrixAsCTM(const SkMatrix& m, const SkPaint& paint) { 236 if (!paint.getMaskFilter()) { 237 return true; 238 } 239 240 // Some mask filters parameters (sigma) depend on the CTM/scale. 241 return m.getType() <= SkMatrix::kTranslate_Mask; 242} 243 244void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, 245 const SkRect* src, const SkRect& dst, 246 const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) { 247 SkMatrix matrix; 248 SkRect bitmapBounds, tmpSrc, tmpDst; 249 SkBitmap tmpBitmap; 250 251 bitmapBounds.isetWH(bitmap.width(), bitmap.height()); 252 253 // Compute matrix from the two rectangles 254 if (src) { 255 tmpSrc = *src; 256 } else { 257 tmpSrc = bitmapBounds; 258 } 259 matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit); 260 261 LogDrawScaleFactor(SkMatrix::Concat(*draw.fMatrix, matrix), paint.getFilterQuality()); 262 263 const SkRect* dstPtr = &dst; 264 const SkBitmap* bitmapPtr = &bitmap; 265 266 // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if 267 // needed (if the src was clipped). No check needed if src==null. 268 if (src) { 269 if (!bitmapBounds.contains(*src)) { 270 if (!tmpSrc.intersect(bitmapBounds)) { 271 return; // nothing to draw 272 } 273 // recompute dst, based on the smaller tmpSrc 274 matrix.mapRect(&tmpDst, tmpSrc); 275 dstPtr = &tmpDst; 276 } 277 } 278 279 if (src && !src->contains(bitmapBounds) && 280 SkCanvas::kFast_SrcRectConstraint == constraint && 281 paint.getFilterQuality() != kNone_SkFilterQuality) { 282 // src is smaller than the bounds of the bitmap, and we are filtering, so we don't know 283 // how much more of the bitmap we need, so we can't use extractSubset or drawBitmap, 284 // but we must use a shader w/ dst bounds (which can access all of the bitmap needed). 285 goto USE_SHADER; 286 } 287 288 if (src) { 289 // since we may need to clamp to the borders of the src rect within 290 // the bitmap, we extract a subset. 291 const SkIRect srcIR = tmpSrc.roundOut(); 292 if (!bitmap.extractSubset(&tmpBitmap, srcIR)) { 293 return; 294 } 295 bitmapPtr = &tmpBitmap; 296 297 // Since we did an extract, we need to adjust the matrix accordingly 298 SkScalar dx = 0, dy = 0; 299 if (srcIR.fLeft > 0) { 300 dx = SkIntToScalar(srcIR.fLeft); 301 } 302 if (srcIR.fTop > 0) { 303 dy = SkIntToScalar(srcIR.fTop); 304 } 305 if (dx || dy) { 306 matrix.preTranslate(dx, dy); 307 } 308 309 SkRect extractedBitmapBounds; 310 extractedBitmapBounds.isetWH(bitmapPtr->width(), bitmapPtr->height()); 311 if (extractedBitmapBounds == tmpSrc) { 312 // no fractional part in src, we can just call drawBitmap 313 goto USE_DRAWBITMAP; 314 } 315 } else { 316 USE_DRAWBITMAP: 317 // We can go faster by just calling drawBitmap, which will concat the 318 // matrix with the CTM, and try to call drawSprite if it can. If not, 319 // it will make a shader and call drawRect, as we do below. 320 if (CanApplyDstMatrixAsCTM(matrix, paint)) { 321 draw.drawBitmap(*bitmapPtr, matrix, dstPtr, paint); 322 return; 323 } 324 } 325 326 USE_SHADER: 327 328 // Since the shader need only live for our stack-frame, pass in a custom allocator. This 329 // can save malloc calls, and signals to SkMakeBitmapShader to not try to copy the bitmap 330 // if its mutable, since that precaution is not needed (give the short lifetime of the shader). 331 SkTBlitterAllocator allocator; 332 // construct a shader, so we can call drawRect with the dst 333 auto s = SkMakeBitmapShader(*bitmapPtr, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, 334 &matrix, kNever_SkCopyPixelsMode, &allocator); 335 if (!s) { 336 return; 337 } 338 // we deliberately add a ref, since the allocator wants to be the last owner 339 s.get()->ref(); 340 341 SkPaint paintWithShader(paint); 342 paintWithShader.setStyle(SkPaint::kFill_Style); 343 paintWithShader.setShader(s); 344 345 // Call ourself, in case the subclass wanted to share this setup code 346 // but handle the drawRect code themselves. 347 this->drawRect(draw, *dstPtr, paintWithShader); 348} 349 350void SkBitmapDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, 351 int x, int y, const SkPaint& paint) { 352 draw.drawSprite(bitmap, x, y, paint); 353} 354 355void SkBitmapDevice::drawText(const SkDraw& draw, const void* text, size_t len, 356 SkScalar x, SkScalar y, const SkPaint& paint) { 357 draw.drawText((const char*)text, len, x, y, paint); 358} 359 360void SkBitmapDevice::drawPosText(const SkDraw& draw, const void* text, size_t len, 361 const SkScalar xpos[], int scalarsPerPos, 362 const SkPoint& offset, const SkPaint& paint) { 363 draw.drawPosText((const char*)text, len, xpos, scalarsPerPos, offset, paint); 364} 365 366void SkBitmapDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode, 367 int vertexCount, 368 const SkPoint verts[], const SkPoint textures[], 369 const SkColor colors[], SkBlendMode bmode, 370 const uint16_t indices[], int indexCount, 371 const SkPaint& paint) { 372 draw.drawVertices(vmode, vertexCount, verts, textures, colors, bmode, 373 indices, indexCount, paint); 374} 375 376void SkBitmapDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device, 377 int x, int y, const SkPaint& paint) { 378 SkASSERT(!paint.getImageFilter()); 379 draw.drawSprite(static_cast<SkBitmapDevice*>(device)->fBitmap, x, y, paint); 380} 381 382/////////////////////////////////////////////////////////////////////////////// 383 384void SkBitmapDevice::drawSpecial(const SkDraw& draw, SkSpecialImage* srcImg, int x, int y, 385 const SkPaint& paint) { 386 SkASSERT(!srcImg->isTextureBacked()); 387 388 SkBitmap resultBM; 389 390 SkImageFilter* filter = paint.getImageFilter(); 391 if (filter) { 392 SkIPoint offset = SkIPoint::Make(0, 0); 393 SkMatrix matrix = *draw.fMatrix; 394 matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y)); 395 const SkIRect clipBounds = draw.fRC->getBounds().makeOffset(-x, -y); 396 sk_sp<SkImageFilterCache> cache(this->getImageFilterCache()); 397 SkImageFilter::OutputProperties outputProperties(fBitmap.colorSpace()); 398 SkImageFilter::Context ctx(matrix, clipBounds, cache.get(), outputProperties); 399 400 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg, ctx, &offset)); 401 if (resultImg) { 402 SkPaint tmpUnfiltered(paint); 403 tmpUnfiltered.setImageFilter(nullptr); 404 if (resultImg->getROPixels(&resultBM)) { 405 this->drawSprite(draw, resultBM, x + offset.x(), y + offset.y(), tmpUnfiltered); 406 } 407 } 408 } else { 409 if (srcImg->getROPixels(&resultBM)) { 410 this->drawSprite(draw, resultBM, x, y, paint); 411 } 412 } 413} 414 415sk_sp<SkSpecialImage> SkBitmapDevice::makeSpecial(const SkBitmap& bitmap) { 416 return SkSpecialImage::MakeFromRaster(bitmap.bounds(), bitmap); 417} 418 419sk_sp<SkSpecialImage> SkBitmapDevice::makeSpecial(const SkImage* image) { 420 // This is called when we're about to draw the special-ized version of image to *this* device, 421 // so we can use our own presense/absence of a color space to decide how to decode the image. 422 SkDestinationSurfaceColorMode decodeColorMode = fBitmap.colorSpace() 423 ? SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware 424 : SkDestinationSurfaceColorMode::kLegacy; 425 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image->height()), 426 image->makeNonTextureImage(), decodeColorMode); 427} 428 429sk_sp<SkSpecialImage> SkBitmapDevice::snapSpecial() { 430 return this->makeSpecial(fBitmap); 431} 432 433/////////////////////////////////////////////////////////////////////////////// 434 435sk_sp<SkSurface> SkBitmapDevice::makeSurface(const SkImageInfo& info, const SkSurfaceProps& props) { 436 return SkSurface::MakeRaster(info, &props); 437} 438 439SkImageFilterCache* SkBitmapDevice::getImageFilterCache() { 440 SkImageFilterCache* cache = SkImageFilterCache::Get(); 441 cache->ref(); 442 return cache; 443} 444 445/////////////////////////////////////////////////////////////////////////////// 446 447bool SkBitmapDevice::onShouldDisableLCD(const SkPaint& paint) const { 448 if (kN32_SkColorType != fBitmap.colorType() || 449 paint.getRasterizer() || 450 paint.getPathEffect() || 451 paint.isFakeBoldText() || 452 paint.getStyle() != SkPaint::kFill_Style || 453 !paint.isSrcOver()) 454 { 455 return true; 456 } 457 return false; 458} 459