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