SkBitmapDevice.cpp revision 2b57b7f7a7fc97db57f190b5a8ebcf68e177ee2d
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 "SkRasterHandleAllocator.h" 21#include "SkShader.h" 22#include "SkSpecialImage.h" 23#include "SkSurface.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 SkRasterHandleAllocator::Handle hndl) 85 : INHERITED(bitmap.info(), surfaceProps) 86 , fBitmap(bitmap) 87 , fRasterHandle(hndl) 88{ 89 SkASSERT(valid_for_bitmap_device(bitmap.info(), nullptr)); 90 fBitmap.lockPixels(); 91} 92 93SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo, 94 const SkSurfaceProps& surfaceProps, 95 SkRasterHandleAllocator* allocator) { 96 SkAlphaType newAT = origInfo.alphaType(); 97 if (!valid_for_bitmap_device(origInfo, &newAT)) { 98 return nullptr; 99 } 100 101 SkRasterHandleAllocator::Handle hndl = nullptr; 102 const SkImageInfo info = origInfo.makeAlphaType(newAT); 103 SkBitmap bitmap; 104 105 if (kUnknown_SkColorType == info.colorType()) { 106 if (!bitmap.setInfo(info)) { 107 return nullptr; 108 } 109 } else if (allocator) { 110 hndl = allocator->allocBitmap(info, &bitmap); 111 if (!hndl) { 112 return nullptr; 113 } 114 } else if (info.isOpaque()) { 115 // If this bitmap is opaque, we don't have any sensible default color, 116 // so we just return uninitialized pixels. 117 if (!bitmap.tryAllocPixels(info)) { 118 return nullptr; 119 } 120 } else { 121 // This bitmap has transparency, so we'll zero the pixels (to transparent). 122 // We use a ZeroedPRFactory as a faster alloc-then-eraseColor(SK_ColorTRANSPARENT). 123 SkMallocPixelRef::ZeroedPRFactory factory; 124 if (!bitmap.tryAllocPixels(info, &factory, nullptr/*color table*/)) { 125 return nullptr; 126 } 127 } 128 129 return new SkBitmapDevice(bitmap, surfaceProps, hndl); 130} 131 132void SkBitmapDevice::setNewSize(const SkISize& size) { 133 SkASSERT(!fBitmap.pixelRef()); 134 fBitmap.setInfo(fBitmap.info().makeWH(size.fWidth, size.fHeight)); 135 this->privateResize(fBitmap.info().width(), fBitmap.info().height()); 136} 137 138void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) { 139 SkASSERT(bm.width() == fBitmap.width()); 140 SkASSERT(bm.height() == fBitmap.height()); 141 fBitmap = bm; // intent is to use bm's pixelRef (and rowbytes/config) 142 fBitmap.lockPixels(); 143 this->privateResize(fBitmap.info().width(), fBitmap.info().height()); 144} 145 146SkBaseDevice* SkBitmapDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint*) { 147 const SkSurfaceProps surfaceProps(this->surfaceProps().flags(), cinfo.fPixelGeometry); 148 return SkBitmapDevice::Create(cinfo.fInfo, surfaceProps, cinfo.fAllocator); 149} 150 151bool SkBitmapDevice::onAccessPixels(SkPixmap* pmap) { 152 if (this->onPeekPixels(pmap)) { 153 fBitmap.notifyPixelsChanged(); 154 return true; 155 } 156 return false; 157} 158 159bool SkBitmapDevice::onPeekPixels(SkPixmap* pmap) { 160 const SkImageInfo info = fBitmap.info(); 161 if (fBitmap.getPixels() && (kUnknown_SkColorType != info.colorType())) { 162 SkColorTable* ctable = nullptr; 163 pmap->reset(fBitmap.info(), fBitmap.getPixels(), fBitmap.rowBytes(), ctable); 164 return true; 165 } 166 return false; 167} 168 169bool SkBitmapDevice::onWritePixels(const SkImageInfo& srcInfo, const void* srcPixels, 170 size_t srcRowBytes, int x, int y) { 171 // since we don't stop creating un-pixeled devices yet, check for no pixels here 172 if (nullptr == fBitmap.getPixels()) { 173 return false; 174 } 175 176 if (fBitmap.writePixels(SkPixmap(srcInfo, srcPixels, srcRowBytes), x, y)) { 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 // TODO(herb): Move this over to SkArenaAlloc when arena alloc has a facility to return sk_sps. 330 // Since the shader need only live for our stack-frame, pass in a custom allocator. This 331 // can save malloc calls, and signals to SkMakeBitmapShader to not try to copy the bitmap 332 // if its mutable, since that precaution is not needed (give the short lifetime of the shader). 333 SkTBlitterAllocator allocator; 334 // construct a shader, so we can call drawRect with the dst 335 auto s = SkMakeBitmapShader(*bitmapPtr, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, 336 &matrix, kNever_SkCopyPixelsMode, &allocator); 337 if (!s) { 338 return; 339 } 340 // we deliberately add a ref, since the allocator wants to be the last owner 341 s.get()->ref(); 342 343 SkPaint paintWithShader(paint); 344 paintWithShader.setStyle(SkPaint::kFill_Style); 345 paintWithShader.setShader(s); 346 347 // Call ourself, in case the subclass wanted to share this setup code 348 // but handle the drawRect code themselves. 349 this->drawRect(draw, *dstPtr, paintWithShader); 350} 351 352void SkBitmapDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, 353 int x, int y, const SkPaint& paint) { 354 draw.drawSprite(bitmap, x, y, paint); 355} 356 357void SkBitmapDevice::drawText(const SkDraw& draw, const void* text, size_t len, 358 SkScalar x, SkScalar y, const SkPaint& paint) { 359 draw.drawText((const char*)text, len, x, y, paint); 360} 361 362void SkBitmapDevice::drawPosText(const SkDraw& draw, const void* text, size_t len, 363 const SkScalar xpos[], int scalarsPerPos, 364 const SkPoint& offset, const SkPaint& paint) { 365 draw.drawPosText((const char*)text, len, xpos, scalarsPerPos, offset, paint); 366} 367 368void SkBitmapDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode, 369 int vertexCount, 370 const SkPoint verts[], const SkPoint textures[], 371 const SkColor colors[], SkBlendMode bmode, 372 const uint16_t indices[], int indexCount, 373 const SkPaint& paint) { 374 draw.drawVertices(vmode, vertexCount, verts, textures, colors, bmode, 375 indices, indexCount, paint); 376} 377 378void SkBitmapDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device, 379 int x, int y, const SkPaint& paint) { 380 SkASSERT(!paint.getImageFilter()); 381 draw.drawSprite(static_cast<SkBitmapDevice*>(device)->fBitmap, x, y, paint); 382} 383 384/////////////////////////////////////////////////////////////////////////////// 385 386void SkBitmapDevice::drawSpecial(const SkDraw& draw, SkSpecialImage* srcImg, int x, int y, 387 const SkPaint& paint) { 388 SkASSERT(!srcImg->isTextureBacked()); 389 390 SkBitmap resultBM; 391 392 SkImageFilter* filter = paint.getImageFilter(); 393 if (filter) { 394 SkIPoint offset = SkIPoint::Make(0, 0); 395 SkMatrix matrix = *draw.fMatrix; 396 matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y)); 397 const SkIRect clipBounds = draw.fRC->getBounds().makeOffset(-x, -y); 398 sk_sp<SkImageFilterCache> cache(this->getImageFilterCache()); 399 SkImageFilter::OutputProperties outputProperties(fBitmap.colorSpace()); 400 SkImageFilter::Context ctx(matrix, clipBounds, cache.get(), outputProperties); 401 402 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg, ctx, &offset)); 403 if (resultImg) { 404 SkPaint tmpUnfiltered(paint); 405 tmpUnfiltered.setImageFilter(nullptr); 406 if (resultImg->getROPixels(&resultBM)) { 407 this->drawSprite(draw, resultBM, x + offset.x(), y + offset.y(), tmpUnfiltered); 408 } 409 } 410 } else { 411 if (srcImg->getROPixels(&resultBM)) { 412 this->drawSprite(draw, resultBM, x, y, paint); 413 } 414 } 415} 416 417sk_sp<SkSpecialImage> SkBitmapDevice::makeSpecial(const SkBitmap& bitmap) { 418 return SkSpecialImage::MakeFromRaster(bitmap.bounds(), bitmap); 419} 420 421sk_sp<SkSpecialImage> SkBitmapDevice::makeSpecial(const SkImage* image) { 422 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image->height()), 423 image->makeNonTextureImage(), fBitmap.colorSpace()); 424} 425 426sk_sp<SkSpecialImage> SkBitmapDevice::snapSpecial() { 427 return this->makeSpecial(fBitmap); 428} 429 430/////////////////////////////////////////////////////////////////////////////// 431 432sk_sp<SkSurface> SkBitmapDevice::makeSurface(const SkImageInfo& info, const SkSurfaceProps& props) { 433 return SkSurface::MakeRaster(info, &props); 434} 435 436SkImageFilterCache* SkBitmapDevice::getImageFilterCache() { 437 SkImageFilterCache* cache = SkImageFilterCache::Get(); 438 cache->ref(); 439 return cache; 440} 441 442/////////////////////////////////////////////////////////////////////////////// 443 444bool SkBitmapDevice::onShouldDisableLCD(const SkPaint& paint) const { 445 if (kN32_SkColorType != fBitmap.colorType() || 446 paint.getRasterizer() || 447 paint.getPathEffect() || 448 paint.isFakeBoldText() || 449 paint.getStyle() != SkPaint::kFill_Style || 450 !paint.isSrcOver()) 451 { 452 return true; 453 } 454 return false; 455} 456