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