SkBitmapDevice.cpp revision 99330ba6227137866a0dbd63478d36f335203ebd
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 "SkDraw.h" 10#include "SkImageFilter.h" 11#include "SkImageFilterCache.h" 12#include "SkMallocPixelRef.h" 13#include "SkMatrix.h" 14#include "SkPaint.h" 15#include "SkPath.h" 16#include "SkPixelRef.h" 17#include "SkPixmap.h" 18#include "SkRasterClip.h" 19#include "SkRasterHandleAllocator.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 , fRCStack(bitmap.width(), bitmap.height()) 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 SkRasterHandleAllocator::Handle hndl) 85 : INHERITED(bitmap.info(), surfaceProps) 86 , fBitmap(bitmap) 87 , fRasterHandle(hndl) 88 , fRCStack(bitmap.width(), bitmap.height()) 89{ 90 SkASSERT(valid_for_bitmap_device(bitmap.info(), nullptr)); 91 fBitmap.lockPixels(); 92} 93 94SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo, 95 const SkSurfaceProps& surfaceProps, 96 SkRasterHandleAllocator* allocator) { 97 SkAlphaType newAT = origInfo.alphaType(); 98 if (!valid_for_bitmap_device(origInfo, &newAT)) { 99 return nullptr; 100 } 101 102 SkRasterHandleAllocator::Handle hndl = nullptr; 103 const SkImageInfo info = origInfo.makeAlphaType(newAT); 104 SkBitmap bitmap; 105 106 if (kUnknown_SkColorType == info.colorType()) { 107 if (!bitmap.setInfo(info)) { 108 return nullptr; 109 } 110 } else if (allocator) { 111 hndl = allocator->allocBitmap(info, &bitmap); 112 if (!hndl) { 113 return nullptr; 114 } 115 } else if (info.isOpaque()) { 116 // If this bitmap is opaque, we don't have any sensible default color, 117 // so we just return uninitialized pixels. 118 if (!bitmap.tryAllocPixels(info)) { 119 return nullptr; 120 } 121 } else { 122 // This bitmap has transparency, so we'll zero the pixels (to transparent). 123 // We use a ZeroedPRFactory as a faster alloc-then-eraseColor(SK_ColorTRANSPARENT). 124 SkMallocPixelRef::ZeroedPRFactory factory; 125 if (!bitmap.tryAllocPixels(info, &factory, nullptr/*color table*/)) { 126 return nullptr; 127 } 128 } 129 130 return new SkBitmapDevice(bitmap, surfaceProps, hndl); 131} 132 133void SkBitmapDevice::setNewSize(const SkISize& size) { 134 SkASSERT(!fBitmap.pixelRef()); 135 fBitmap.setInfo(fBitmap.info().makeWH(size.fWidth, size.fHeight)); 136 this->privateResize(fBitmap.info().width(), fBitmap.info().height()); 137 138 fRCStack.setNewSize(size.fWidth, size.fHeight); 139} 140 141void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) { 142 SkASSERT(bm.width() == fBitmap.width()); 143 SkASSERT(bm.height() == fBitmap.height()); 144 fBitmap = bm; // intent is to use bm's pixelRef (and rowbytes/config) 145 fBitmap.lockPixels(); 146 this->privateResize(fBitmap.info().width(), fBitmap.info().height()); 147} 148 149SkBaseDevice* SkBitmapDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint*) { 150 const SkSurfaceProps surfaceProps(this->surfaceProps().flags(), cinfo.fPixelGeometry); 151 return SkBitmapDevice::Create(cinfo.fInfo, surfaceProps, cinfo.fAllocator); 152} 153 154bool SkBitmapDevice::onAccessPixels(SkPixmap* pmap) { 155 if (this->onPeekPixels(pmap)) { 156 fBitmap.notifyPixelsChanged(); 157 return true; 158 } 159 return false; 160} 161 162bool SkBitmapDevice::onPeekPixels(SkPixmap* pmap) { 163 const SkImageInfo info = fBitmap.info(); 164 if (fBitmap.getPixels() && (kUnknown_SkColorType != info.colorType())) { 165 SkColorTable* ctable = nullptr; 166 pmap->reset(fBitmap.info(), fBitmap.getPixels(), fBitmap.rowBytes(), ctable); 167 return true; 168 } 169 return false; 170} 171 172bool SkBitmapDevice::onWritePixels(const SkImageInfo& srcInfo, const void* srcPixels, 173 size_t srcRowBytes, int x, int y) { 174 // since we don't stop creating un-pixeled devices yet, check for no pixels here 175 if (nullptr == fBitmap.getPixels()) { 176 return false; 177 } 178 179 if (fBitmap.writePixels(SkPixmap(srcInfo, srcPixels, srcRowBytes), x, y)) { 180 fBitmap.notifyPixelsChanged(); 181 return true; 182 } 183 return false; 184} 185 186bool SkBitmapDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, 187 int x, int y) { 188 return fBitmap.readPixels(dstInfo, dstPixels, dstRowBytes, x, y); 189} 190 191/////////////////////////////////////////////////////////////////////////////// 192 193#ifdef SK_USE_DEVICE_CLIPPING 194class ModifiedDraw : public SkDraw { 195public: 196 ModifiedDraw(const SkMatrix& devCTM, const SkRasterClip& rc, SkISize rcs, 197 const SkDraw& draw) : SkDraw(draw) { 198#ifdef SK_DEBUG 199 SkISize dvs = { draw.fDevice->width(), draw.fDevice->height() }; 200 SkASSERT(dvs == rcs); 201 SkASSERT(devCTM == *draw.fMatrix); 202#endif 203 fRC = &rc; 204 } 205}; 206#define PREPARE_DRAW(draw) ModifiedDraw(this->ctm(), fRCStack.rc(), fRCStack.getRootSize(), draw) 207#else 208#define PREPARE_DRAW(draw) draw 209#endif 210 211void SkBitmapDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) { 212 PREPARE_DRAW(draw).drawPaint(paint); 213} 214 215void SkBitmapDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count, 216 const SkPoint pts[], const SkPaint& paint) { 217 PREPARE_DRAW(draw).drawPoints(mode, count, pts, paint, nullptr); 218} 219 220void SkBitmapDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& paint) { 221 PREPARE_DRAW(draw).drawRect(r, paint); 222} 223 224void SkBitmapDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) { 225 SkPath path; 226 path.addOval(oval); 227 // call the VIRTUAL version, so any subclasses who do handle drawPath aren't 228 // required to override drawOval. 229 this->drawPath(draw, path, paint, nullptr, true); 230} 231 232void SkBitmapDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, const SkPaint& paint) { 233#ifdef SK_IGNORE_BLURRED_RRECT_OPT 234 SkPath path; 235 236 path.addRRect(rrect); 237 // call the VIRTUAL version, so any subclasses who do handle drawPath aren't 238 // required to override drawRRect. 239 this->drawPath(draw, path, paint, nullptr, true); 240#else 241 PREPARE_DRAW(draw).drawRRect(rrect, paint); 242#endif 243} 244 245void SkBitmapDevice::drawPath(const SkDraw& draw, const SkPath& path, 246 const SkPaint& paint, const SkMatrix* prePathMatrix, 247 bool pathIsMutable) { 248 PREPARE_DRAW(draw).drawPath(path, paint, prePathMatrix, pathIsMutable); 249} 250 251void SkBitmapDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap, 252 const SkMatrix& matrix, const SkPaint& paint) { 253 LogDrawScaleFactor(SkMatrix::Concat(*draw.fMatrix, matrix), paint.getFilterQuality()); 254 PREPARE_DRAW(draw).drawBitmap(bitmap, matrix, nullptr, paint); 255} 256 257static inline bool CanApplyDstMatrixAsCTM(const SkMatrix& m, const SkPaint& paint) { 258 if (!paint.getMaskFilter()) { 259 return true; 260 } 261 262 // Some mask filters parameters (sigma) depend on the CTM/scale. 263 return m.getType() <= SkMatrix::kTranslate_Mask; 264} 265 266void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, 267 const SkRect* src, const SkRect& dst, 268 const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) { 269 SkMatrix matrix; 270 SkRect bitmapBounds, tmpSrc, tmpDst; 271 SkBitmap tmpBitmap; 272 273 bitmapBounds.isetWH(bitmap.width(), bitmap.height()); 274 275 // Compute matrix from the two rectangles 276 if (src) { 277 tmpSrc = *src; 278 } else { 279 tmpSrc = bitmapBounds; 280 } 281 matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit); 282 283 LogDrawScaleFactor(SkMatrix::Concat(*draw.fMatrix, matrix), paint.getFilterQuality()); 284 285 const SkRect* dstPtr = &dst; 286 const SkBitmap* bitmapPtr = &bitmap; 287 288 // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if 289 // needed (if the src was clipped). No check needed if src==null. 290 if (src) { 291 if (!bitmapBounds.contains(*src)) { 292 if (!tmpSrc.intersect(bitmapBounds)) { 293 return; // nothing to draw 294 } 295 // recompute dst, based on the smaller tmpSrc 296 matrix.mapRect(&tmpDst, tmpSrc); 297 dstPtr = &tmpDst; 298 } 299 } 300 301 if (src && !src->contains(bitmapBounds) && 302 SkCanvas::kFast_SrcRectConstraint == constraint && 303 paint.getFilterQuality() != kNone_SkFilterQuality) { 304 // src is smaller than the bounds of the bitmap, and we are filtering, so we don't know 305 // how much more of the bitmap we need, so we can't use extractSubset or drawBitmap, 306 // but we must use a shader w/ dst bounds (which can access all of the bitmap needed). 307 goto USE_SHADER; 308 } 309 310 if (src) { 311 // since we may need to clamp to the borders of the src rect within 312 // the bitmap, we extract a subset. 313 const SkIRect srcIR = tmpSrc.roundOut(); 314 if (!bitmap.extractSubset(&tmpBitmap, srcIR)) { 315 return; 316 } 317 bitmapPtr = &tmpBitmap; 318 319 // Since we did an extract, we need to adjust the matrix accordingly 320 SkScalar dx = 0, dy = 0; 321 if (srcIR.fLeft > 0) { 322 dx = SkIntToScalar(srcIR.fLeft); 323 } 324 if (srcIR.fTop > 0) { 325 dy = SkIntToScalar(srcIR.fTop); 326 } 327 if (dx || dy) { 328 matrix.preTranslate(dx, dy); 329 } 330 331 SkRect extractedBitmapBounds; 332 extractedBitmapBounds.isetWH(bitmapPtr->width(), bitmapPtr->height()); 333 if (extractedBitmapBounds == tmpSrc) { 334 // no fractional part in src, we can just call drawBitmap 335 goto USE_DRAWBITMAP; 336 } 337 } else { 338 USE_DRAWBITMAP: 339 // We can go faster by just calling drawBitmap, which will concat the 340 // matrix with the CTM, and try to call drawSprite if it can. If not, 341 // it will make a shader and call drawRect, as we do below. 342 if (CanApplyDstMatrixAsCTM(matrix, paint)) { 343 PREPARE_DRAW(draw).drawBitmap(*bitmapPtr, matrix, dstPtr, paint); 344 return; 345 } 346 } 347 348 USE_SHADER: 349 350 // TODO(herb): Move this over to SkArenaAlloc when arena alloc has a facility to return sk_sps. 351 // Since the shader need only live for our stack-frame, pass in a custom allocator. This 352 // can save malloc calls, and signals to SkMakeBitmapShader to not try to copy the bitmap 353 // if its mutable, since that precaution is not needed (give the short lifetime of the shader). 354 355 // construct a shader, so we can call drawRect with the dst 356 auto s = SkMakeBitmapShader(*bitmapPtr, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, 357 &matrix, kNever_SkCopyPixelsMode); 358 if (!s) { 359 return; 360 } 361 362 SkPaint paintWithShader(paint); 363 paintWithShader.setStyle(SkPaint::kFill_Style); 364 paintWithShader.setShader(s); 365 366 // Call ourself, in case the subclass wanted to share this setup code 367 // but handle the drawRect code themselves. 368 this->drawRect(draw, *dstPtr, paintWithShader); 369} 370 371void SkBitmapDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, 372 int x, int y, const SkPaint& paint) { 373 PREPARE_DRAW(draw).drawSprite(bitmap, x, y, paint); 374} 375 376void SkBitmapDevice::drawText(const SkDraw& draw, const void* text, size_t len, 377 SkScalar x, SkScalar y, const SkPaint& paint) { 378 PREPARE_DRAW(draw).drawText((const char*)text, len, x, y, paint, &fSurfaceProps); 379} 380 381void SkBitmapDevice::drawPosText(const SkDraw& draw, const void* text, size_t len, 382 const SkScalar xpos[], int scalarsPerPos, 383 const SkPoint& offset, const SkPaint& paint) { 384 PREPARE_DRAW(draw).drawPosText((const char*)text, len, xpos, scalarsPerPos, offset, 385 paint, &fSurfaceProps); 386} 387 388void SkBitmapDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode, 389 int vertexCount, 390 const SkPoint verts[], const SkPoint textures[], 391 const SkColor colors[], SkBlendMode bmode, 392 const uint16_t indices[], int indexCount, 393 const SkPaint& paint) { 394 PREPARE_DRAW(draw).drawVertices(vmode, vertexCount, verts, textures, colors, bmode, 395 indices, indexCount, paint); 396} 397 398void SkBitmapDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device, 399 int x, int y, const SkPaint& paint) { 400 SkASSERT(!paint.getImageFilter()); 401 PREPARE_DRAW(draw).drawSprite(static_cast<SkBitmapDevice*>(device)->fBitmap, x, y, paint); 402} 403 404/////////////////////////////////////////////////////////////////////////////// 405 406void SkBitmapDevice::drawSpecial(const SkDraw& draw, SkSpecialImage* srcImg, int x, int y, 407 const SkPaint& paint) { 408 SkASSERT(!srcImg->isTextureBacked()); 409 410 SkBitmap resultBM; 411 412 SkImageFilter* filter = paint.getImageFilter(); 413 if (filter) { 414 SkIPoint offset = SkIPoint::Make(0, 0); 415 SkMatrix matrix = *draw.fMatrix; 416 matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y)); 417 const SkIRect clipBounds = draw.fRC->getBounds().makeOffset(-x, -y); 418 sk_sp<SkImageFilterCache> cache(this->getImageFilterCache()); 419 SkImageFilter::OutputProperties outputProperties(fBitmap.colorSpace()); 420 SkImageFilter::Context ctx(matrix, clipBounds, cache.get(), outputProperties); 421 422 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg, ctx, &offset)); 423 if (resultImg) { 424 SkPaint tmpUnfiltered(paint); 425 tmpUnfiltered.setImageFilter(nullptr); 426 if (resultImg->getROPixels(&resultBM)) { 427 this->drawSprite(draw, resultBM, x + offset.x(), y + offset.y(), tmpUnfiltered); 428 } 429 } 430 } else { 431 if (srcImg->getROPixels(&resultBM)) { 432 this->drawSprite(draw, resultBM, x, y, paint); 433 } 434 } 435} 436 437sk_sp<SkSpecialImage> SkBitmapDevice::makeSpecial(const SkBitmap& bitmap) { 438 return SkSpecialImage::MakeFromRaster(bitmap.bounds(), bitmap); 439} 440 441sk_sp<SkSpecialImage> SkBitmapDevice::makeSpecial(const SkImage* image) { 442 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image->height()), 443 image->makeNonTextureImage(), fBitmap.colorSpace()); 444} 445 446sk_sp<SkSpecialImage> SkBitmapDevice::snapSpecial() { 447 return this->makeSpecial(fBitmap); 448} 449 450/////////////////////////////////////////////////////////////////////////////// 451 452sk_sp<SkSurface> SkBitmapDevice::makeSurface(const SkImageInfo& info, const SkSurfaceProps& props) { 453 return SkSurface::MakeRaster(info, &props); 454} 455 456SkImageFilterCache* SkBitmapDevice::getImageFilterCache() { 457 SkImageFilterCache* cache = SkImageFilterCache::Get(); 458 cache->ref(); 459 return cache; 460} 461 462/////////////////////////////////////////////////////////////////////////////////////////////////// 463 464bool SkBitmapDevice::onShouldDisableLCD(const SkPaint& paint) const { 465 if (kN32_SkColorType != fBitmap.colorType() || 466 paint.getRasterizer() || 467 paint.getPathEffect() || 468 paint.isFakeBoldText() || 469 paint.getStyle() != SkPaint::kFill_Style || 470 !paint.isSrcOver()) 471 { 472 return true; 473 } 474 return false; 475} 476 477/////////////////////////////////////////////////////////////////////////////////////////////////// 478 479void SkBitmapDevice::onSave() { 480 fRCStack.save(); 481} 482 483void SkBitmapDevice::onRestore() { 484 fRCStack.restore(); 485} 486 487void SkBitmapDevice::onClipRect(const SkRect& rect, SkClipOp op, bool aa) { 488 fRCStack.clipRect(this->ctm(), rect, op, aa); 489} 490 491void SkBitmapDevice::onClipRRect(const SkRRect& rrect, SkClipOp op, bool aa) { 492 fRCStack.clipRRect(this->ctm(), rrect, op, aa); 493} 494 495void SkBitmapDevice::onClipPath(const SkPath& path, SkClipOp op, bool aa) { 496 fRCStack.clipPath(this->ctm(), path, op, aa); 497} 498 499void SkBitmapDevice::onClipRegion(const SkRegion& rgn, SkClipOp op) { 500 SkIPoint origin = this->getOrigin(); 501 SkRegion tmp; 502 const SkRegion* ptr = &rgn; 503 if (origin.fX | origin.fY) { 504 // translate from "global/canvas" coordinates to relative to this device 505 rgn.translate(-origin.fX, -origin.fY, &tmp); 506 ptr = &tmp; 507 } 508 fRCStack.clipRegion(*ptr, op); 509} 510 511void SkBitmapDevice::onSetDeviceClipRestriction(SkIRect* mutableClipRestriction) { 512 fRCStack.setDeviceClipRestriction(mutableClipRestriction); 513 if (!mutableClipRestriction->isEmpty()) { 514 SkRegion rgn(*mutableClipRestriction); 515 fRCStack.clipRegion(rgn, SkClipOp::kIntersect); 516 } 517} 518 519void SkBitmapDevice::validateDevBounds(const SkIRect& drawClipBounds) { 520#ifdef SK_DEBUG 521 const SkIRect& stackBounds = fRCStack.rc().getBounds(); 522 SkASSERT(drawClipBounds == stackBounds); 523#endif 524} 525