SkBitmapDevice.cpp revision 3375c8047e7f10e6bf9a2ce1c2e8b0df08c56024
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 kN32_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 71SkBitmapDevice* SkBitmapDevice::Create(const SkImageInfo& origInfo, 72 const SkDeviceProperties* props) { 73 SkAlphaType newAT = origInfo.alphaType(); 74 if (!valid_for_bitmap_device(origInfo, &newAT)) { 75 return NULL; 76 } 77 78 const SkImageInfo info = origInfo.makeAlphaType(newAT); 79 SkBitmap bitmap; 80 81 if (kUnknown_SkColorType == info.colorType()) { 82 if (!bitmap.setInfo(info)) { 83 return NULL; 84 } 85 } else { 86 if (!bitmap.tryAllocPixels(info)) { 87 return NULL; 88 } 89 if (!bitmap.info().isOpaque()) { 90 bitmap.eraseColor(SK_ColorTRANSPARENT); 91 } 92 } 93 94 if (props) { 95 return SkNEW_ARGS(SkBitmapDevice, (bitmap, *props)); 96 } else { 97 return SkNEW_ARGS(SkBitmapDevice, (bitmap)); 98 } 99} 100 101SkImageInfo SkBitmapDevice::imageInfo() const { 102 return fBitmap.info(); 103} 104 105void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) { 106 SkASSERT(bm.width() == fBitmap.width()); 107 SkASSERT(bm.height() == fBitmap.height()); 108 fBitmap = bm; // intent is to use bm's pixelRef (and rowbytes/config) 109 fBitmap.lockPixels(); 110} 111 112SkBaseDevice* SkBitmapDevice::onCreateDevice(const SkImageInfo& info, Usage usage) { 113 return SkBitmapDevice::Create(info, &this->getDeviceProperties()); 114} 115 116void SkBitmapDevice::lockPixels() { 117 if (fBitmap.lockPixelsAreWritable()) { 118 fBitmap.lockPixels(); 119 } 120} 121 122void SkBitmapDevice::unlockPixels() { 123 if (fBitmap.lockPixelsAreWritable()) { 124 fBitmap.unlockPixels(); 125 } 126} 127 128void SkBitmapDevice::clear(SkColor color) { 129 fBitmap.eraseColor(color); 130} 131 132const SkBitmap& SkBitmapDevice::onAccessBitmap() { 133 return fBitmap; 134} 135 136void* SkBitmapDevice::onAccessPixels(SkImageInfo* info, size_t* rowBytes) { 137 if (fBitmap.getPixels()) { 138 *info = fBitmap.info(); 139 *rowBytes = fBitmap.rowBytes(); 140 return fBitmap.getPixels(); 141 } 142 return NULL; 143} 144 145#include "SkConfig8888.h" 146 147bool SkBitmapDevice::onWritePixels(const SkImageInfo& srcInfo, const void* srcPixels, 148 size_t srcRowBytes, int x, int y) { 149 // since we don't stop creating un-pixeled devices yet, check for no pixels here 150 if (NULL == fBitmap.getPixels()) { 151 return false; 152 } 153 154 const SkImageInfo dstInfo = fBitmap.info().makeWH(srcInfo.width(), srcInfo.height()); 155 156 void* dstPixels = fBitmap.getAddr(x, y); 157 size_t dstRowBytes = fBitmap.rowBytes(); 158 159 if (SkPixelInfo::CopyPixels(dstInfo, dstPixels, dstRowBytes, srcInfo, srcPixels, srcRowBytes)) { 160 fBitmap.notifyPixelsChanged(); 161 return true; 162 } 163 return false; 164} 165 166bool SkBitmapDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, 167 int x, int y) { 168 return fBitmap.readPixels(dstInfo, dstPixels, dstRowBytes, x, y); 169} 170 171/////////////////////////////////////////////////////////////////////////////// 172 173void SkBitmapDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) { 174 draw.drawPaint(paint); 175} 176 177void SkBitmapDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count, 178 const SkPoint pts[], const SkPaint& paint) { 179 CHECK_FOR_ANNOTATION(paint); 180 draw.drawPoints(mode, count, pts, paint); 181} 182 183void SkBitmapDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& paint) { 184 CHECK_FOR_ANNOTATION(paint); 185 draw.drawRect(r, paint); 186} 187 188void SkBitmapDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) { 189 CHECK_FOR_ANNOTATION(paint); 190 191 SkPath path; 192 path.addOval(oval); 193 // call the VIRTUAL version, so any subclasses who do handle drawPath aren't 194 // required to override drawOval. 195 this->drawPath(draw, path, paint, NULL, true); 196} 197 198void SkBitmapDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, const SkPaint& paint) { 199 CHECK_FOR_ANNOTATION(paint); 200 201#ifdef SK_IGNORE_BLURRED_RRECT_OPT 202 SkPath path; 203 204 path.addRRect(rrect); 205 // call the VIRTUAL version, so any subclasses who do handle drawPath aren't 206 // required to override drawRRect. 207 this->drawPath(draw, path, paint, NULL, true); 208#else 209 draw.drawRRect(rrect, paint); 210#endif 211} 212 213void SkBitmapDevice::drawPath(const SkDraw& draw, const SkPath& path, 214 const SkPaint& paint, const SkMatrix* prePathMatrix, 215 bool pathIsMutable) { 216 CHECK_FOR_ANNOTATION(paint); 217 draw.drawPath(path, paint, prePathMatrix, pathIsMutable); 218} 219 220void SkBitmapDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap, 221 const SkMatrix& matrix, const SkPaint& paint) { 222 draw.drawBitmap(bitmap, matrix, paint); 223} 224 225void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, 226 const SkRect* src, const SkRect& dst, 227 const SkPaint& paint, 228 SkCanvas::DrawBitmapRectFlags flags) { 229 SkMatrix matrix; 230 SkRect bitmapBounds, tmpSrc, tmpDst; 231 SkBitmap tmpBitmap; 232 233 bitmapBounds.isetWH(bitmap.width(), bitmap.height()); 234 235 // Compute matrix from the two rectangles 236 if (src) { 237 tmpSrc = *src; 238 } else { 239 tmpSrc = bitmapBounds; 240 } 241 matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit); 242 243 const SkRect* dstPtr = &dst; 244 const SkBitmap* bitmapPtr = &bitmap; 245 246 // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if 247 // needed (if the src was clipped). No check needed if src==null. 248 if (src) { 249 if (!bitmapBounds.contains(*src)) { 250 if (!tmpSrc.intersect(bitmapBounds)) { 251 return; // nothing to draw 252 } 253 // recompute dst, based on the smaller tmpSrc 254 matrix.mapRect(&tmpDst, tmpSrc); 255 dstPtr = &tmpDst; 256 } 257 258 // since we may need to clamp to the borders of the src rect within 259 // the bitmap, we extract a subset. 260 SkIRect srcIR; 261 tmpSrc.roundOut(&srcIR); 262 if (!bitmap.extractSubset(&tmpBitmap, srcIR)) { 263 return; 264 } 265 bitmapPtr = &tmpBitmap; 266 267 // Since we did an extract, we need to adjust the matrix accordingly 268 SkScalar dx = 0, dy = 0; 269 if (srcIR.fLeft > 0) { 270 dx = SkIntToScalar(srcIR.fLeft); 271 } 272 if (srcIR.fTop > 0) { 273 dy = SkIntToScalar(srcIR.fTop); 274 } 275 if (dx || dy) { 276 matrix.preTranslate(dx, dy); 277 } 278 279 SkRect extractedBitmapBounds; 280 extractedBitmapBounds.isetWH(bitmapPtr->width(), bitmapPtr->height()); 281 if (extractedBitmapBounds == tmpSrc) { 282 // no fractional part in src, we can just call drawBitmap 283 goto USE_DRAWBITMAP; 284 } 285 } else { 286 USE_DRAWBITMAP: 287 // We can go faster by just calling drawBitmap, which will concat the 288 // matrix with the CTM, and try to call drawSprite if it can. If not, 289 // it will make a shader and call drawRect, as we do below. 290 this->drawBitmap(draw, *bitmapPtr, matrix, paint); 291 return; 292 } 293 294 // construct a shader, so we can call drawRect with the dst 295 SkShader* s = SkShader::CreateBitmapShader(*bitmapPtr, 296 SkShader::kClamp_TileMode, 297 SkShader::kClamp_TileMode, 298 &matrix); 299 if (NULL == s) { 300 return; 301 } 302 303 SkPaint paintWithShader(paint); 304 paintWithShader.setStyle(SkPaint::kFill_Style); 305 paintWithShader.setShader(s)->unref(); 306 307 // Call ourself, in case the subclass wanted to share this setup code 308 // but handle the drawRect code themselves. 309 this->drawRect(draw, *dstPtr, paintWithShader); 310} 311 312void SkBitmapDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, 313 int x, int y, const SkPaint& paint) { 314 draw.drawSprite(bitmap, x, y, paint); 315} 316 317void SkBitmapDevice::drawText(const SkDraw& draw, const void* text, size_t len, 318 SkScalar x, SkScalar y, const SkPaint& paint) { 319 draw.drawText((const char*)text, len, x, y, paint); 320} 321 322void SkBitmapDevice::drawPosText(const SkDraw& draw, const void* text, size_t len, 323 const SkScalar xpos[], SkScalar y, 324 int scalarsPerPos, const SkPaint& paint) { 325 draw.drawPosText((const char*)text, len, xpos, y, scalarsPerPos, paint); 326} 327 328void SkBitmapDevice::drawTextOnPath(const SkDraw& draw, const void* text, 329 size_t len, const SkPath& path, 330 const SkMatrix* matrix, 331 const SkPaint& paint) { 332 draw.drawTextOnPath((const char*)text, len, path, matrix, paint); 333} 334 335void SkBitmapDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode, 336 int vertexCount, 337 const SkPoint verts[], const SkPoint textures[], 338 const SkColor colors[], SkXfermode* xmode, 339 const uint16_t indices[], int indexCount, 340 const SkPaint& paint) { 341 draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode, 342 indices, indexCount, paint); 343} 344 345void SkBitmapDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device, 346 int x, int y, const SkPaint& paint) { 347 const SkBitmap& src = device->accessBitmap(false); 348 draw.drawSprite(src, x, y, paint); 349} 350 351SkSurface* SkBitmapDevice::newSurface(const SkImageInfo& info) { 352 return SkSurface::NewRaster(info); 353} 354 355const void* SkBitmapDevice::peekPixels(SkImageInfo* info, size_t* rowBytes) { 356 const SkImageInfo bmInfo = fBitmap.info(); 357 if (fBitmap.getPixels() && (kUnknown_SkColorType != bmInfo.colorType())) { 358 if (info) { 359 *info = bmInfo; 360 } 361 if (rowBytes) { 362 *rowBytes = fBitmap.rowBytes(); 363 } 364 return fBitmap.getPixels(); 365 } 366 return NULL; 367} 368 369SkImageFilter::Cache* SkBitmapDevice::getImageFilterCache() { 370 SkImageFilter::Cache* cache = SkImageFilter::Cache::Get(); 371 cache->ref(); 372 return cache; 373} 374 375/////////////////////////////////////////////////////////////////////////////// 376 377bool SkBitmapDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) { 378 if (!paint.isLCDRenderText() || !paint.isAntiAlias()) { 379 // we're cool with the paint as is 380 return false; 381 } 382 383 if (kN32_SkColorType != fBitmap.colorType() || 384 paint.getRasterizer() || 385 paint.getPathEffect() || 386 paint.isFakeBoldText() || 387 paint.getStyle() != SkPaint::kFill_Style || 388 !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode)) { 389 // turn off lcd, but turn on kGenA8 390 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag; 391 flags->fFlags |= SkPaint::kGenA8FromLCD_Flag; 392 return true; 393 } 394 // we're cool with the paint as is 395 return false; 396} 397