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