SkBitmapDevice.cpp revision 589a39eb81d25fa7af95e7366db17ac7a70a7d03
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 236void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, 237 const SkRect* src, const SkRect& dst, 238 const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) { 239 SkMatrix matrix; 240 SkRect bitmapBounds, tmpSrc, tmpDst; 241 SkBitmap tmpBitmap; 242 243 bitmapBounds.isetWH(bitmap.width(), bitmap.height()); 244 245 // Compute matrix from the two rectangles 246 if (src) { 247 tmpSrc = *src; 248 } else { 249 tmpSrc = bitmapBounds; 250 } 251 matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit); 252 253 LogDrawScaleFactor(SkMatrix::Concat(*draw.fMatrix, matrix), paint.getFilterQuality()); 254 255 const SkRect* dstPtr = &dst; 256 const SkBitmap* bitmapPtr = &bitmap; 257 258 // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if 259 // needed (if the src was clipped). No check needed if src==null. 260 if (src) { 261 if (!bitmapBounds.contains(*src)) { 262 if (!tmpSrc.intersect(bitmapBounds)) { 263 return; // nothing to draw 264 } 265 // recompute dst, based on the smaller tmpSrc 266 matrix.mapRect(&tmpDst, tmpSrc); 267 dstPtr = &tmpDst; 268 } 269 } 270 271 if (src && !src->contains(bitmapBounds) && 272 SkCanvas::kFast_SrcRectConstraint == constraint && 273 paint.getFilterQuality() != kNone_SkFilterQuality) { 274 // src is smaller than the bounds of the bitmap, and we are filtering, so we don't know 275 // how much more of the bitmap we need, so we can't use extractSubset or drawBitmap, 276 // but we must use a shader w/ dst bounds (which can access all of the bitmap needed). 277 goto USE_SHADER; 278 } 279 280 if (src) { 281 // since we may need to clamp to the borders of the src rect within 282 // the bitmap, we extract a subset. 283 const SkIRect srcIR = tmpSrc.roundOut(); 284 if(bitmap.pixelRef()->getTexture()) { 285 // Accelerated source canvas, don't use extractSubset but readPixels to get the subset. 286 // This way, the pixels are copied in CPU memory instead of GPU memory. 287 bitmap.pixelRef()->readPixels(&tmpBitmap, kN32_SkColorType, &srcIR); 288 } else { 289 if (!bitmap.extractSubset(&tmpBitmap, srcIR)) { 290 return; 291 } 292 } 293 bitmapPtr = &tmpBitmap; 294 295 // Since we did an extract, we need to adjust the matrix accordingly 296 SkScalar dx = 0, dy = 0; 297 if (srcIR.fLeft > 0) { 298 dx = SkIntToScalar(srcIR.fLeft); 299 } 300 if (srcIR.fTop > 0) { 301 dy = SkIntToScalar(srcIR.fTop); 302 } 303 if (dx || dy) { 304 matrix.preTranslate(dx, dy); 305 } 306 307 SkRect extractedBitmapBounds; 308 extractedBitmapBounds.isetWH(bitmapPtr->width(), bitmapPtr->height()); 309 if (extractedBitmapBounds == tmpSrc) { 310 // no fractional part in src, we can just call drawBitmap 311 goto USE_DRAWBITMAP; 312 } 313 } else { 314 USE_DRAWBITMAP: 315 // We can go faster by just calling drawBitmap, which will concat the 316 // matrix with the CTM, and try to call drawSprite if it can. If not, 317 // it will make a shader and call drawRect, as we do below. 318 draw.drawBitmap(*bitmapPtr, matrix, dstPtr, paint); 319 return; 320 } 321 322 USE_SHADER: 323 324 // Since the shader need only live for our stack-frame, pass in a custom allocator. This 325 // can save malloc calls, and signals to SkMakeBitmapShader to not try to copy the bitmap 326 // if its mutable, since that precaution is not needed (give the short lifetime of the shader). 327 SkTBlitterAllocator allocator; 328 // construct a shader, so we can call drawRect with the dst 329 auto s = SkMakeBitmapShader(*bitmapPtr, SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, 330 &matrix, kNever_SkCopyPixelsMode, &allocator); 331 if (!s) { 332 return; 333 } 334 // we deliberately add a ref, since the allocator wants to be the last owner 335 s.get()->ref(); 336 337 SkPaint paintWithShader(paint); 338 paintWithShader.setStyle(SkPaint::kFill_Style); 339 paintWithShader.setShader(s); 340 341 // Call ourself, in case the subclass wanted to share this setup code 342 // but handle the drawRect code themselves. 343 this->drawRect(draw, *dstPtr, paintWithShader); 344} 345 346void SkBitmapDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, 347 int x, int y, const SkPaint& paint) { 348 draw.drawSprite(bitmap, x, y, paint); 349} 350 351void SkBitmapDevice::drawText(const SkDraw& draw, const void* text, size_t len, 352 SkScalar x, SkScalar y, const SkPaint& paint) { 353 draw.drawText((const char*)text, len, x, y, paint); 354} 355 356void SkBitmapDevice::drawPosText(const SkDraw& draw, const void* text, size_t len, 357 const SkScalar xpos[], int scalarsPerPos, 358 const SkPoint& offset, const SkPaint& paint) { 359 draw.drawPosText((const char*)text, len, xpos, scalarsPerPos, offset, paint); 360} 361 362void SkBitmapDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode, 363 int vertexCount, 364 const SkPoint verts[], const SkPoint textures[], 365 const SkColor colors[], SkXfermode* xmode, 366 const uint16_t indices[], int indexCount, 367 const SkPaint& paint) { 368 draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode, 369 indices, indexCount, paint); 370} 371 372void SkBitmapDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device, 373 int x, int y, const SkPaint& paint) { 374 SkASSERT(!paint.getImageFilter()); 375 draw.drawSprite(static_cast<SkBitmapDevice*>(device)->fBitmap, x, y, paint); 376} 377 378/////////////////////////////////////////////////////////////////////////////// 379 380void SkBitmapDevice::drawSpecial(const SkDraw& draw, SkSpecialImage* srcImg, int x, int y, 381 const SkPaint& paint) { 382 SkASSERT(!srcImg->isTextureBacked()); 383 384 SkBitmap resultBM; 385 386 SkImageFilter* filter = paint.getImageFilter(); 387 if (filter) { 388 SkIPoint offset = SkIPoint::Make(0, 0); 389 SkMatrix matrix = *draw.fMatrix; 390 matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y)); 391 const SkIRect clipBounds = draw.fRC->getBounds().makeOffset(-x, -y); 392 SkAutoTUnref<SkImageFilterCache> cache(this->getImageFilterCache()); 393 SkImageFilter::Context ctx(matrix, clipBounds, cache.get()); 394 395 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg, ctx, &offset)); 396 if (resultImg) { 397 SkPaint tmpUnfiltered(paint); 398 tmpUnfiltered.setImageFilter(nullptr); 399 if (resultImg->getROPixels(&resultBM)) { 400 this->drawSprite(draw, resultBM, x + offset.x(), y + offset.y(), tmpUnfiltered); 401 } 402 } 403 } else { 404 if (srcImg->getROPixels(&resultBM)) { 405 this->drawSprite(draw, resultBM, x, y, paint); 406 } 407 } 408} 409 410sk_sp<SkSpecialImage> SkBitmapDevice::makeSpecial(const SkBitmap& bitmap) { 411 return SkSpecialImage::MakeFromRaster(bitmap.bounds(), bitmap); 412} 413 414sk_sp<SkSpecialImage> SkBitmapDevice::makeSpecial(const SkImage* image) { 415 return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(image->width(), image->height()), 416 image->makeNonTextureImage()); 417} 418 419sk_sp<SkSpecialImage> SkBitmapDevice::snapSpecial() { 420 return this->makeSpecial(fBitmap); 421} 422 423/////////////////////////////////////////////////////////////////////////////// 424 425sk_sp<SkSurface> SkBitmapDevice::makeSurface(const SkImageInfo& info, const SkSurfaceProps& props) { 426 return SkSurface::MakeRaster(info, &props); 427} 428 429SkImageFilterCache* SkBitmapDevice::getImageFilterCache() { 430 SkImageFilterCache* cache = SkImageFilterCache::Get(); 431 cache->ref(); 432 return cache; 433} 434 435/////////////////////////////////////////////////////////////////////////////// 436 437bool SkBitmapDevice::onShouldDisableLCD(const SkPaint& paint) const { 438 if (kN32_SkColorType != fBitmap.colorType() || 439 paint.getRasterizer() || 440 paint.getPathEffect() || 441 paint.isFakeBoldText() || 442 paint.getStyle() != SkPaint::kFill_Style || 443 !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode)) 444 { 445 return true; 446 } 447 return false; 448} 449