SkBitmapDevice.cpp revision 76f10a3bd936af7dbe2b5873d5a7eedd73cdc5da
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 "SkRasterClip.h" 12#include "SkShader.h" 13#include "SkSurface.h" 14 15#define CHECK_FOR_ANNOTATION(paint) \ 16 do { if (paint.getAnnotation()) { return; } } while (0) 17 18SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap) 19 : fBitmap(bitmap) { 20 SkASSERT(SkBitmap::kARGB_4444_Config != bitmap.config()); 21} 22 23SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkDeviceProperties& deviceProperties) 24 : SkBaseDevice(deviceProperties) 25 , fBitmap(bitmap) { 26} 27 28void SkBitmapDevice::init(SkBitmap::Config config, int width, int height, bool isOpaque) { 29 fBitmap.setConfig(config, width, height, 0, isOpaque ? 30 kOpaque_SkAlphaType : kPremul_SkAlphaType); 31 32 if (SkBitmap::kNo_Config != config) { 33 if (!fBitmap.allocPixels()) { 34 // indicate failure by zeroing our bitmap 35 fBitmap.setConfig(config, 0, 0, 0, isOpaque ? 36 kOpaque_SkAlphaType : kPremul_SkAlphaType); 37 } else if (!isOpaque) { 38 fBitmap.eraseColor(SK_ColorTRANSPARENT); 39 } 40 } 41} 42 43SkBitmapDevice::SkBitmapDevice(SkBitmap::Config config, int width, int height, bool isOpaque) { 44 this->init(config, width, height, isOpaque); 45} 46 47SkBitmapDevice::SkBitmapDevice(SkBitmap::Config config, int width, int height, bool isOpaque, 48 const SkDeviceProperties& deviceProperties) 49 : SkBaseDevice(deviceProperties) 50{ 51 this->init(config, width, height, isOpaque); 52} 53 54SkBitmapDevice::~SkBitmapDevice() { 55} 56 57void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) { 58 SkASSERT(bm.width() == fBitmap.width()); 59 SkASSERT(bm.height() == fBitmap.height()); 60 fBitmap = bm; // intent is to use bm's pixelRef (and rowbytes/config) 61 fBitmap.lockPixels(); 62} 63 64SkBaseDevice* SkBitmapDevice::onCreateCompatibleDevice(SkBitmap::Config config, 65 int width, int height, 66 bool isOpaque, 67 Usage usage) { 68 SkBitmapDevice* device = SkNEW_ARGS(SkBitmapDevice,(config, width, height, 69 isOpaque, this->getDeviceProperties())); 70 // Check if allocation failed and delete device if it did fail 71 if ((device->width() != width) || (device->height() != height)) { 72 SkDELETE(device); 73 device = NULL; 74 } 75 return device; 76} 77 78void SkBitmapDevice::lockPixels() { 79 if (fBitmap.lockPixelsAreWritable()) { 80 fBitmap.lockPixels(); 81 } 82} 83 84void SkBitmapDevice::unlockPixels() { 85 if (fBitmap.lockPixelsAreWritable()) { 86 fBitmap.unlockPixels(); 87 } 88} 89 90void SkBitmapDevice::clear(SkColor color) { 91 fBitmap.eraseColor(color); 92} 93 94const SkBitmap& SkBitmapDevice::onAccessBitmap() { 95 return fBitmap; 96} 97 98bool SkBitmapDevice::canHandleImageFilter(SkImageFilter*) { 99 return false; 100} 101 102bool SkBitmapDevice::filterImage(SkImageFilter* filter, const SkBitmap& src, 103 const SkMatrix& ctm, SkBitmap* result, 104 SkIPoint* offset) { 105 return false; 106} 107 108bool SkBitmapDevice::allowImageFilter(SkImageFilter*) { 109 return true; 110} 111 112bool SkBitmapDevice::onReadPixels(const SkBitmap& bitmap, 113 int x, int y, 114 SkCanvas::Config8888 config8888) { 115 SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config()); 116 SkASSERT(!bitmap.isNull()); 117 SkASSERT(SkIRect::MakeWH(this->width(), this->height()).contains(SkIRect::MakeXYWH(x, y, 118 bitmap.width(), 119 bitmap.height()))); 120 121 SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height()); 122 const SkBitmap& src = this->accessBitmap(false); 123 124 SkBitmap subset; 125 if (!src.extractSubset(&subset, srcRect)) { 126 return false; 127 } 128 if (SkBitmap::kARGB_8888_Config != subset.config()) { 129 // It'd be preferable to do this directly to bitmap. 130 subset.copyTo(&subset, SkBitmap::kARGB_8888_Config); 131 } 132 SkAutoLockPixels alp(bitmap); 133 uint32_t* bmpPixels = reinterpret_cast<uint32_t*>(bitmap.getPixels()); 134 SkCopyBitmapToConfig8888(bmpPixels, bitmap.rowBytes(), config8888, subset); 135 return true; 136} 137 138void SkBitmapDevice::writePixels(const SkBitmap& bitmap, 139 int x, int y, 140 SkCanvas::Config8888 config8888) { 141 if (bitmap.isNull() || bitmap.getTexture()) { 142 return; 143 } 144 const SkBitmap* sprite = &bitmap; 145 // check whether we have to handle a config8888 that doesn't match SkPMColor 146 if (SkBitmap::kARGB_8888_Config == bitmap.config() && 147 SkCanvas::kNative_Premul_Config8888 != config8888 && 148 kPMColorAlias != config8888) { 149 150 // We're going to have to convert from a config8888 to the native config 151 // First we clip to the device bounds. 152 SkBitmap dstBmp = this->accessBitmap(true); 153 SkIRect spriteRect = SkIRect::MakeXYWH(x, y, 154 bitmap.width(), bitmap.height()); 155 SkIRect devRect = SkIRect::MakeWH(dstBmp.width(), dstBmp.height()); 156 if (!spriteRect.intersect(devRect)) { 157 return; 158 } 159 160 // write directly to the device if it has pixels and is SkPMColor 161 bool drawSprite; 162 if (SkBitmap::kARGB_8888_Config == dstBmp.config() && !dstBmp.isNull()) { 163 // we can write directly to the dst when doing the conversion 164 dstBmp.extractSubset(&dstBmp, spriteRect); 165 drawSprite = false; 166 } else { 167 // we convert to a temporary bitmap and draw that as a sprite 168 if (!dstBmp.allocPixels(SkImageInfo::MakeN32Premul(spriteRect.width(), 169 spriteRect.height()))) { 170 return; 171 } 172 drawSprite = true; 173 } 174 175 // copy pixels to dstBmp and convert from config8888 to native config. 176 SkAutoLockPixels alp(bitmap); 177 uint32_t* srcPixels = bitmap.getAddr32(spriteRect.fLeft - x, 178 spriteRect.fTop - y); 179 SkCopyConfig8888ToBitmap(dstBmp, 180 srcPixels, 181 bitmap.rowBytes(), 182 config8888); 183 184 if (drawSprite) { 185 // we've clipped the sprite when we made a copy 186 x = spriteRect.fLeft; 187 y = spriteRect.fTop; 188 sprite = &dstBmp; 189 } else { 190 return; 191 } 192 } 193 194 SkPaint paint; 195 paint.setXfermodeMode(SkXfermode::kSrc_Mode); 196 SkRasterClip clip(SkIRect::MakeWH(fBitmap.width(), fBitmap.height())); 197 SkDraw draw; 198 draw.fRC = &clip; 199 draw.fClip = &clip.bwRgn(); 200 draw.fBitmap = &fBitmap; // canvas should have already called accessBitmap 201 draw.fMatrix = &SkMatrix::I(); 202 this->drawSprite(draw, *sprite, x, y, paint); 203} 204 205/////////////////////////////////////////////////////////////////////////////// 206 207void SkBitmapDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) { 208 draw.drawPaint(paint); 209} 210 211void SkBitmapDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count, 212 const SkPoint pts[], const SkPaint& paint) { 213 CHECK_FOR_ANNOTATION(paint); 214 draw.drawPoints(mode, count, pts, paint); 215} 216 217void SkBitmapDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& paint) { 218 CHECK_FOR_ANNOTATION(paint); 219 draw.drawRect(r, paint); 220} 221 222void SkBitmapDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) { 223 CHECK_FOR_ANNOTATION(paint); 224 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, NULL, true); 230} 231 232void SkBitmapDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, const SkPaint& paint) { 233 CHECK_FOR_ANNOTATION(paint); 234 235#ifdef SK_IGNORE_BLURRED_RRECT_OPT 236 SkPath path; 237 238 path.addRRect(rrect); 239 // call the VIRTUAL version, so any subclasses who do handle drawPath aren't 240 // required to override drawRRect. 241 this->drawPath(draw, path, paint, NULL, true); 242#else 243 draw.drawRRect(rrect, paint); 244#endif 245} 246 247void SkBitmapDevice::drawPath(const SkDraw& draw, const SkPath& path, 248 const SkPaint& paint, const SkMatrix* prePathMatrix, 249 bool pathIsMutable) { 250 CHECK_FOR_ANNOTATION(paint); 251 draw.drawPath(path, paint, prePathMatrix, pathIsMutable); 252} 253 254void SkBitmapDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap, 255 const SkMatrix& matrix, const SkPaint& paint) { 256 draw.drawBitmap(bitmap, matrix, paint); 257} 258 259void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, 260 const SkRect* src, const SkRect& dst, 261 const SkPaint& paint, 262 SkCanvas::DrawBitmapRectFlags flags) { 263 SkMatrix matrix; 264 SkRect bitmapBounds, tmpSrc, tmpDst; 265 SkBitmap tmpBitmap; 266 267 bitmapBounds.isetWH(bitmap.width(), bitmap.height()); 268 269 // Compute matrix from the two rectangles 270 if (src) { 271 tmpSrc = *src; 272 } else { 273 tmpSrc = bitmapBounds; 274 } 275 matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit); 276 277 const SkRect* dstPtr = &dst; 278 const SkBitmap* bitmapPtr = &bitmap; 279 280 // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if 281 // needed (if the src was clipped). No check needed if src==null. 282 if (src) { 283 if (!bitmapBounds.contains(*src)) { 284 if (!tmpSrc.intersect(bitmapBounds)) { 285 return; // nothing to draw 286 } 287 // recompute dst, based on the smaller tmpSrc 288 matrix.mapRect(&tmpDst, tmpSrc); 289 dstPtr = &tmpDst; 290 } 291 292 // since we may need to clamp to the borders of the src rect within 293 // the bitmap, we extract a subset. 294 SkIRect srcIR; 295 tmpSrc.roundOut(&srcIR); 296 if (!bitmap.extractSubset(&tmpBitmap, srcIR)) { 297 return; 298 } 299 bitmapPtr = &tmpBitmap; 300 301 // Since we did an extract, we need to adjust the matrix accordingly 302 SkScalar dx = 0, dy = 0; 303 if (srcIR.fLeft > 0) { 304 dx = SkIntToScalar(srcIR.fLeft); 305 } 306 if (srcIR.fTop > 0) { 307 dy = SkIntToScalar(srcIR.fTop); 308 } 309 if (dx || dy) { 310 matrix.preTranslate(dx, dy); 311 } 312 313 SkRect extractedBitmapBounds; 314 extractedBitmapBounds.isetWH(bitmapPtr->width(), bitmapPtr->height()); 315 if (extractedBitmapBounds == tmpSrc) { 316 // no fractional part in src, we can just call drawBitmap 317 goto USE_DRAWBITMAP; 318 } 319 } else { 320 USE_DRAWBITMAP: 321 // We can go faster by just calling drawBitmap, which will concat the 322 // matrix with the CTM, and try to call drawSprite if it can. If not, 323 // it will make a shader and call drawRect, as we do below. 324 this->drawBitmap(draw, *bitmapPtr, matrix, paint); 325 return; 326 } 327 328 // construct a shader, so we can call drawRect with the dst 329 SkShader* s = SkShader::CreateBitmapShader(*bitmapPtr, 330 SkShader::kClamp_TileMode, 331 SkShader::kClamp_TileMode); 332 if (NULL == s) { 333 return; 334 } 335 s->setLocalMatrix(matrix); 336 337 SkPaint paintWithShader(paint); 338 paintWithShader.setStyle(SkPaint::kFill_Style); 339 paintWithShader.setShader(s)->unref(); 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[], SkScalar y, 358 int scalarsPerPos, const SkPaint& paint) { 359 draw.drawPosText((const char*)text, len, xpos, y, scalarsPerPos, paint); 360} 361 362void SkBitmapDevice::drawTextOnPath(const SkDraw& draw, const void* text, 363 size_t len, const SkPath& path, 364 const SkMatrix* matrix, 365 const SkPaint& paint) { 366 draw.drawTextOnPath((const char*)text, len, path, matrix, paint); 367} 368 369void SkBitmapDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode, 370 int vertexCount, 371 const SkPoint verts[], const SkPoint textures[], 372 const SkColor colors[], SkXfermode* xmode, 373 const uint16_t indices[], int indexCount, 374 const SkPaint& paint) { 375 draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode, 376 indices, indexCount, paint); 377} 378 379void SkBitmapDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device, 380 int x, int y, const SkPaint& paint) { 381 const SkBitmap& src = device->accessBitmap(false); 382 draw.drawSprite(src, x, y, paint); 383} 384 385SkSurface* SkBitmapDevice::newSurface(const SkImageInfo& info) { 386 return SkSurface::NewRaster(info); 387} 388 389/////////////////////////////////////////////////////////////////////////////// 390 391bool SkBitmapDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) { 392 if (!paint.isLCDRenderText() || !paint.isAntiAlias()) { 393 // we're cool with the paint as is 394 return false; 395 } 396 397 if (SkBitmap::kARGB_8888_Config != fBitmap.config() || 398 paint.getRasterizer() || 399 paint.getPathEffect() || 400 paint.isFakeBoldText() || 401 paint.getStyle() != SkPaint::kFill_Style || 402 !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode)) { 403 // turn off lcd 404 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag; 405 flags->fHinting = paint.getHinting(); 406 return true; 407 } 408 // we're cool with the paint as is 409 return false; 410} 411