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 #if 0 65 SkBitmapDevice::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 73 SkBitmapDevice* 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 103 SkImageInfo SkBitmapDevice::imageInfo() const { 104 return fBitmap.info(); 105 } 106 107 void 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 114 SkBaseDevice* SkBitmapDevice::onCreateDevice(const SkImageInfo& info, Usage usage) { 115 return SkBitmapDevice::Create(info);// &this->getDeviceProperties()); 116 } 117 118 void SkBitmapDevice::lockPixels() { 119 if (fBitmap.lockPixelsAreWritable()) { 120 fBitmap.lockPixels(); 121 } 122 } 123 124 void SkBitmapDevice::unlockPixels() { 125 if (fBitmap.lockPixelsAreWritable()) { 126 fBitmap.unlockPixels(); 127 } 128 } 129 130 void SkBitmapDevice::clear(SkColor color) { 131 fBitmap.eraseColor(color); 132 } 133 134 const SkBitmap& SkBitmapDevice::onAccessBitmap() { 135 return fBitmap; 136 } 137 138 void* 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 150 bool 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 169 bool 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 176 void SkBitmapDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) { 177 draw.drawPaint(paint); 178 } 179 180 void 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 186 void SkBitmapDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint& paint) { 187 CHECK_FOR_ANNOTATION(paint); 188 draw.drawRect(r, paint); 189 } 190 191 void 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 201 void 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 216 void 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 223 void SkBitmapDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap, 224 const SkMatrix& matrix, const SkPaint& paint) { 225 draw.drawBitmap(bitmap, matrix, paint); 226 } 227 228 void 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 321 void 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 326 void 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 331 void 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 337 void 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 344 void 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 354 void 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 360 SkSurface* SkBitmapDevice::newSurface(const SkImageInfo& info, const SkSurfaceProps& props) { 361 return SkSurface::NewRaster(info, &props); 362 } 363 364 const 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 378 SkImageFilter::Cache* SkBitmapDevice::getImageFilterCache() { 379 SkImageFilter::Cache* cache = SkImageFilter::Cache::Get(); 380 cache->ref(); 381 return cache; 382 } 383 384 /////////////////////////////////////////////////////////////////////////////// 385 386 bool 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