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