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