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