SkBitmapDevice.cpp revision 231f6b81c22001cac4ea87ea412c4d6fd10ffb8a
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 18static bool valid_for_bitmap_device(const SkImageInfo& info, 19 SkAlphaType* newAlphaType) { 20 if (info.width() < 0 || info.height() < 0) { 21 return false; 22 } 23 24 // TODO: can we stop supporting kUnknown in SkBitmkapDevice? 25 if (kUnknown_SkColorType == info.colorType()) { 26 if (newAlphaType) { 27 *newAlphaType = kIgnore_SkAlphaType; 28 } 29 return true; 30 } 31 32 switch (info.alphaType()) { 33 case kPremul_SkAlphaType: 34 case kOpaque_SkAlphaType: 35 break; 36 default: 37 return false; 38 } 39 40 SkAlphaType canonicalAlphaType = info.alphaType(); 41 42 switch (info.colorType()) { 43 case kAlpha_8_SkColorType: 44 break; 45 case kRGB_565_SkColorType: 46 canonicalAlphaType = kOpaque_SkAlphaType; 47 break; 48 case kPMColor_SkColorType: 49 break; 50 default: 51 return false; 52 } 53 54 if (newAlphaType) { 55 *newAlphaType = canonicalAlphaType; 56 } 57 return true; 58} 59 60SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap) : fBitmap(bitmap) { 61 SkASSERT(valid_for_bitmap_device(bitmap.info(), NULL)); 62} 63 64SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkDeviceProperties& deviceProperties) 65 : SkBaseDevice(deviceProperties) 66 , fBitmap(bitmap) 67{ 68 SkASSERT(valid_for_bitmap_device(bitmap.info(), NULL)); 69} 70 71#ifdef SK_SUPPORT_LEGACY_COMPATIBLEDEVICE_CONFIG 72void SkBitmapDevice::init(SkBitmap::Config config, int width, int height, bool isOpaque) { 73 fBitmap.setConfig(config, width, height, 0, isOpaque ? 74 kOpaque_SkAlphaType : kPremul_SkAlphaType); 75 76 if (SkBitmap::kNo_Config != config) { 77 if (!fBitmap.allocPixels()) { 78 // indicate failure by zeroing our bitmap 79 fBitmap.setConfig(config, 0, 0, 0, isOpaque ? 80 kOpaque_SkAlphaType : kPremul_SkAlphaType); 81 } else if (!isOpaque) { 82 fBitmap.eraseColor(SK_ColorTRANSPARENT); 83 } 84 } 85} 86 87SkBitmapDevice::SkBitmapDevice(SkBitmap::Config config, int width, int height, bool isOpaque) { 88 this->init(config, width, height, isOpaque); 89} 90 91SkBitmapDevice::SkBitmapDevice(SkBitmap::Config config, int width, int height, bool isOpaque, 92 const SkDeviceProperties& deviceProperties) 93 : SkBaseDevice(deviceProperties) 94{ 95 this->init(config, width, height, isOpaque); 96} 97#endif 98SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo, 99 const SkDeviceProperties* props) { 100 SkImageInfo info = origInfo; 101 if (!valid_for_bitmap_device(info, &info.fAlphaType)) { 102 return NULL; 103 } 104 105 SkBitmap bitmap; 106 107 if (kUnknown_SkColorType == info.colorType()) { 108 if (!bitmap.setConfig(info)) { 109 return NULL; 110 } 111 } else { 112 if (!bitmap.allocPixels(info)) { 113 return NULL; 114 } 115 if (!bitmap.info().isOpaque()) { 116 bitmap.eraseColor(SK_ColorTRANSPARENT); 117 } 118 } 119 120 if (props) { 121 return SkNEW_ARGS(SkBitmapDevice, (bitmap, *props)); 122 } else { 123 return SkNEW_ARGS(SkBitmapDevice, (bitmap)); 124 } 125} 126 127SkImageInfo SkBitmapDevice::imageInfo() const { 128 return fBitmap.info(); 129} 130 131void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) { 132 SkASSERT(bm.width() == fBitmap.width()); 133 SkASSERT(bm.height() == fBitmap.height()); 134 fBitmap = bm; // intent is to use bm's pixelRef (and rowbytes/config) 135 fBitmap.lockPixels(); 136} 137 138SkBaseDevice* SkBitmapDevice::onCreateDevice(const SkImageInfo& info, Usage usage) { 139 return SkBitmapDevice::Create(info, &this->getDeviceProperties()); 140} 141 142void SkBitmapDevice::lockPixels() { 143 if (fBitmap.lockPixelsAreWritable()) { 144 fBitmap.lockPixels(); 145 } 146} 147 148void SkBitmapDevice::unlockPixels() { 149 if (fBitmap.lockPixelsAreWritable()) { 150 fBitmap.unlockPixels(); 151 } 152} 153 154void SkBitmapDevice::clear(SkColor color) { 155 fBitmap.eraseColor(color); 156} 157 158const SkBitmap& SkBitmapDevice::onAccessBitmap() { 159 return fBitmap; 160} 161 162bool SkBitmapDevice::canHandleImageFilter(const SkImageFilter*) { 163 return false; 164} 165 166bool SkBitmapDevice::filterImage(const SkImageFilter* filter, const SkBitmap& src, 167 const SkImageFilter::Context& ctx, SkBitmap* result, 168 SkIPoint* offset) { 169 return false; 170} 171 172bool SkBitmapDevice::allowImageFilter(const SkImageFilter*) { 173 return true; 174} 175 176#ifdef SK_SUPPORT_LEGACY_READPIXELSCONFIG 177bool SkBitmapDevice::onReadPixels(const SkBitmap& bitmap, 178 int x, int y, 179 SkCanvas::Config8888 config8888) { 180 SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config()); 181 SkASSERT(!bitmap.isNull()); 182 SkASSERT(SkIRect::MakeWH(this->width(), this->height()).contains(SkIRect::MakeXYWH(x, y, 183 bitmap.width(), 184 bitmap.height()))); 185 186 SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height()); 187 const SkBitmap& src = this->accessBitmap(false); 188 189 SkBitmap subset; 190 if (!src.extractSubset(&subset, srcRect)) { 191 return false; 192 } 193 if (kPMColor_SkColorType != subset.colorType()) { 194 // It'd be preferable to do this directly to bitmap. 195 subset.copyTo(&subset, kPMColor_SkColorType); 196 } 197 SkAutoLockPixels alp(bitmap); 198 uint32_t* bmpPixels = reinterpret_cast<uint32_t*>(bitmap.getPixels()); 199 SkCopyBitmapToConfig8888(bmpPixels, bitmap.rowBytes(), config8888, subset); 200 return true; 201} 202#endif 203 204void* SkBitmapDevice::onAccessPixels(SkImageInfo* info, size_t* rowBytes) { 205 if (fBitmap.getPixels()) { 206 *info = fBitmap.info(); 207 *rowBytes = fBitmap.rowBytes(); 208 return fBitmap.getPixels(); 209 } 210 return NULL; 211} 212 213static void rect_memcpy(void* dst, size_t dstRB, const void* src, size_t srcRB, size_t bytesPerRow, 214 int rowCount) { 215 SkASSERT(bytesPerRow <= srcRB); 216 SkASSERT(bytesPerRow <= dstRB); 217 for (int i = 0; i < rowCount; ++i) { 218 memcpy(dst, src, bytesPerRow); 219 dst = (char*)dst + dstRB; 220 src = (const char*)src + srcRB; 221 } 222} 223 224static bool info2config8888(const SkImageInfo& info, SkCanvas::Config8888* config) { 225 bool pre; 226 switch (info.alphaType()) { 227 case kPremul_SkAlphaType: 228 case kOpaque_SkAlphaType: 229 pre = true; 230 break; 231 case kUnpremul_SkAlphaType: 232 pre = false; 233 break; 234 default: 235 return false; 236 } 237 switch (info.colorType()) { 238 case kRGBA_8888_SkColorType: 239 *config = pre ? SkCanvas::kRGBA_Premul_Config8888 : SkCanvas::kRGBA_Unpremul_Config8888; 240 return true; 241 case kBGRA_8888_SkColorType: 242 *config = pre ? SkCanvas::kBGRA_Premul_Config8888 : SkCanvas::kBGRA_Unpremul_Config8888; 243 return true; 244 default: 245 return false; 246 } 247} 248 249// TODO: make this guy real, and not rely on legacy config8888 utility 250#include "SkConfig8888.h" 251static bool copy_pixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, 252 const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRowBytes) { 253 if (srcInfo.dimensions() != dstInfo.dimensions()) { 254 return false; 255 } 256 if (4 == srcInfo.bytesPerPixel() && 4 == dstInfo.bytesPerPixel()) { 257 SkCanvas::Config8888 srcConfig, dstConfig; 258 if (!info2config8888(srcInfo, &srcConfig) || !info2config8888(dstInfo, &dstConfig)) { 259 return false; 260 } 261 SkConvertConfig8888Pixels((uint32_t*)dstPixels, dstRowBytes, dstConfig, 262 (const uint32_t*)srcPixels, srcRowBytes, srcConfig, 263 srcInfo.width(), srcInfo.height()); 264 return true; 265 } 266 if (srcInfo.colorType() == dstInfo.colorType()) { 267 switch (srcInfo.colorType()) { 268 case kRGB_565_SkColorType: 269 case kAlpha_8_SkColorType: 270 break; 271 case kARGB_4444_SkColorType: 272 if (srcInfo.alphaType() != dstInfo.alphaType()) { 273 return false; 274 } 275 break; 276 default: 277 return false; 278 } 279 rect_memcpy(dstPixels, dstRowBytes, srcPixels, srcRowBytes, 280 srcInfo.width() * srcInfo.bytesPerPixel(), srcInfo.height()); 281 } 282 // TODO: add support for more conversions as needed 283 return false; 284} 285 286bool SkBitmapDevice::onWritePixels(const SkImageInfo& srcInfo, const void* srcPixels, 287 size_t srcRowBytes, int x, int y) { 288 // since we don't stop creating un-pixeled devices yet, check for no pixels here 289 if (NULL == fBitmap.getPixels()) { 290 return false; 291 } 292 293 SkImageInfo dstInfo = fBitmap.info(); 294 dstInfo.fWidth = srcInfo.width(); 295 dstInfo.fHeight = srcInfo.height(); 296 297 void* dstPixels = fBitmap.getAddr(x, y); 298 size_t dstRowBytes = fBitmap.rowBytes(); 299 300 if (copy_pixels(dstInfo, dstPixels, dstRowBytes, srcInfo, srcPixels, srcRowBytes)) { 301 fBitmap.notifyPixelsChanged(); 302 return true; 303 } 304 return false; 305} 306 307bool SkBitmapDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, 308 int x, int y) { 309 // since we don't stop creating un-pixeled devices yet, check for no pixels here 310 if (NULL == fBitmap.getPixels()) { 311 return false; 312 } 313 314 SkImageInfo srcInfo = fBitmap.info(); 315 316 // perhaps can relax these in the future 317 if (4 != dstInfo.bytesPerPixel()) { 318 return false; 319 } 320 if (4 != srcInfo.bytesPerPixel()) { 321 return false; 322 } 323 324 srcInfo.fWidth = dstInfo.width(); 325 srcInfo.fHeight = dstInfo.height(); 326 327 const void* srcPixels = fBitmap.getAddr(x, y); 328 const size_t srcRowBytes = fBitmap.rowBytes(); 329 330 return copy_pixels(dstInfo, dstPixels, dstRowBytes, srcInfo, srcPixels, srcRowBytes); 331} 332 333/////////////////////////////////////////////////////////////////////////////// 334 335void SkBitmapDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) { 336 draw.drawPaint(paint); 337} 338 339void SkBitmapDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count, 340 const SkPoint pts[], const SkPaint& paint) { 341 CHECK_FOR_ANNOTATION(paint); 342 draw.drawPoints(mode, count, pts, paint); 343} 344 345void SkBitmapDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& paint) { 346 CHECK_FOR_ANNOTATION(paint); 347 draw.drawRect(r, paint); 348} 349 350void SkBitmapDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) { 351 CHECK_FOR_ANNOTATION(paint); 352 353 SkPath path; 354 path.addOval(oval); 355 // call the VIRTUAL version, so any subclasses who do handle drawPath aren't 356 // required to override drawOval. 357 this->drawPath(draw, path, paint, NULL, true); 358} 359 360void SkBitmapDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, const SkPaint& paint) { 361 CHECK_FOR_ANNOTATION(paint); 362 363#ifdef SK_IGNORE_BLURRED_RRECT_OPT 364 SkPath path; 365 366 path.addRRect(rrect); 367 // call the VIRTUAL version, so any subclasses who do handle drawPath aren't 368 // required to override drawRRect. 369 this->drawPath(draw, path, paint, NULL, true); 370#else 371 draw.drawRRect(rrect, paint); 372#endif 373} 374 375void SkBitmapDevice::drawPath(const SkDraw& draw, const SkPath& path, 376 const SkPaint& paint, const SkMatrix* prePathMatrix, 377 bool pathIsMutable) { 378 CHECK_FOR_ANNOTATION(paint); 379 draw.drawPath(path, paint, prePathMatrix, pathIsMutable); 380} 381 382void SkBitmapDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap, 383 const SkMatrix& matrix, const SkPaint& paint) { 384 draw.drawBitmap(bitmap, matrix, paint); 385} 386 387void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, 388 const SkRect* src, const SkRect& dst, 389 const SkPaint& paint, 390 SkCanvas::DrawBitmapRectFlags flags) { 391 SkMatrix matrix; 392 SkRect bitmapBounds, tmpSrc, tmpDst; 393 SkBitmap tmpBitmap; 394 395 bitmapBounds.isetWH(bitmap.width(), bitmap.height()); 396 397 // Compute matrix from the two rectangles 398 if (src) { 399 tmpSrc = *src; 400 } else { 401 tmpSrc = bitmapBounds; 402 } 403 matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit); 404 405 const SkRect* dstPtr = &dst; 406 const SkBitmap* bitmapPtr = &bitmap; 407 408 // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if 409 // needed (if the src was clipped). No check needed if src==null. 410 if (src) { 411 if (!bitmapBounds.contains(*src)) { 412 if (!tmpSrc.intersect(bitmapBounds)) { 413 return; // nothing to draw 414 } 415 // recompute dst, based on the smaller tmpSrc 416 matrix.mapRect(&tmpDst, tmpSrc); 417 dstPtr = &tmpDst; 418 } 419 420 // since we may need to clamp to the borders of the src rect within 421 // the bitmap, we extract a subset. 422 SkIRect srcIR; 423 tmpSrc.roundOut(&srcIR); 424 if (!bitmap.extractSubset(&tmpBitmap, srcIR)) { 425 return; 426 } 427 bitmapPtr = &tmpBitmap; 428 429 // Since we did an extract, we need to adjust the matrix accordingly 430 SkScalar dx = 0, dy = 0; 431 if (srcIR.fLeft > 0) { 432 dx = SkIntToScalar(srcIR.fLeft); 433 } 434 if (srcIR.fTop > 0) { 435 dy = SkIntToScalar(srcIR.fTop); 436 } 437 if (dx || dy) { 438 matrix.preTranslate(dx, dy); 439 } 440 441 SkRect extractedBitmapBounds; 442 extractedBitmapBounds.isetWH(bitmapPtr->width(), bitmapPtr->height()); 443 if (extractedBitmapBounds == tmpSrc) { 444 // no fractional part in src, we can just call drawBitmap 445 goto USE_DRAWBITMAP; 446 } 447 } else { 448 USE_DRAWBITMAP: 449 // We can go faster by just calling drawBitmap, which will concat the 450 // matrix with the CTM, and try to call drawSprite if it can. If not, 451 // it will make a shader and call drawRect, as we do below. 452 this->drawBitmap(draw, *bitmapPtr, matrix, paint); 453 return; 454 } 455 456 // construct a shader, so we can call drawRect with the dst 457 SkShader* s = SkShader::CreateBitmapShader(*bitmapPtr, 458 SkShader::kClamp_TileMode, 459 SkShader::kClamp_TileMode); 460 if (NULL == s) { 461 return; 462 } 463 s->setLocalMatrix(matrix); 464 465 SkPaint paintWithShader(paint); 466 paintWithShader.setStyle(SkPaint::kFill_Style); 467 paintWithShader.setShader(s)->unref(); 468 469 // Call ourself, in case the subclass wanted to share this setup code 470 // but handle the drawRect code themselves. 471 this->drawRect(draw, *dstPtr, paintWithShader); 472} 473 474void SkBitmapDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, 475 int x, int y, const SkPaint& paint) { 476 draw.drawSprite(bitmap, x, y, paint); 477} 478 479void SkBitmapDevice::drawText(const SkDraw& draw, const void* text, size_t len, 480 SkScalar x, SkScalar y, const SkPaint& paint) { 481 draw.drawText((const char*)text, len, x, y, paint); 482} 483 484void SkBitmapDevice::drawPosText(const SkDraw& draw, const void* text, size_t len, 485 const SkScalar xpos[], SkScalar y, 486 int scalarsPerPos, const SkPaint& paint) { 487 draw.drawPosText((const char*)text, len, xpos, y, scalarsPerPos, paint); 488} 489 490void SkBitmapDevice::drawTextOnPath(const SkDraw& draw, const void* text, 491 size_t len, const SkPath& path, 492 const SkMatrix* matrix, 493 const SkPaint& paint) { 494 draw.drawTextOnPath((const char*)text, len, path, matrix, paint); 495} 496 497void SkBitmapDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode, 498 int vertexCount, 499 const SkPoint verts[], const SkPoint textures[], 500 const SkColor colors[], SkXfermode* xmode, 501 const uint16_t indices[], int indexCount, 502 const SkPaint& paint) { 503 draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode, 504 indices, indexCount, paint); 505} 506 507void SkBitmapDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device, 508 int x, int y, const SkPaint& paint) { 509 const SkBitmap& src = device->accessBitmap(false); 510 draw.drawSprite(src, x, y, paint); 511} 512 513SkSurface* SkBitmapDevice::newSurface(const SkImageInfo& info) { 514 return SkSurface::NewRaster(info); 515} 516 517const void* SkBitmapDevice::peekPixels(SkImageInfo* info, size_t* rowBytes) { 518 if (fBitmap.getPixels() && fBitmap.asImageInfo(info)) { 519 if (rowBytes) { 520 *rowBytes = fBitmap.rowBytes(); 521 } 522 return fBitmap.getPixels(); 523 } 524 return NULL; 525} 526 527/////////////////////////////////////////////////////////////////////////////// 528 529bool SkBitmapDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) { 530 if (!paint.isLCDRenderText() || !paint.isAntiAlias()) { 531 // we're cool with the paint as is 532 return false; 533 } 534 535 if (SkBitmap::kARGB_8888_Config != fBitmap.config() || 536 paint.getRasterizer() || 537 paint.getPathEffect() || 538 paint.isFakeBoldText() || 539 paint.getStyle() != SkPaint::kFill_Style || 540 !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode)) { 541 // turn off lcd 542 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag; 543 flags->fHinting = paint.getHinting(); 544 return true; 545 } 546 // we're cool with the paint as is 547 return false; 548} 549