OLD | NEW |
(Empty) | |
| 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 |
| 14 SK_DEFINE_INST_COUNT(SkBitmapDevice) |
| 15 |
| 16 #define CHECK_FOR_NODRAW_ANNOTATION(paint) \ |
| 17 do { if (paint.isNoDrawAnnotation()) { return; } } while (0) |
| 18 |
| 19 SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap) |
| 20 : fBitmap(bitmap) { |
| 21 SkASSERT(SkBitmap::kARGB_4444_Config != bitmap.config()); |
| 22 } |
| 23 |
| 24 SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkDeviceProperties&
deviceProperties) |
| 25 : SkBaseDevice(deviceProperties) |
| 26 , fBitmap(bitmap) { |
| 27 } |
| 28 |
| 29 SkBitmapDevice::SkBitmapDevice(SkBitmap::Config config, int width, int height, b
ool isOpaque) { |
| 30 fBitmap.setConfig(config, width, height); |
| 31 fBitmap.allocPixels(); |
| 32 fBitmap.setIsOpaque(isOpaque); |
| 33 if (!isOpaque) { |
| 34 fBitmap.eraseColor(SK_ColorTRANSPARENT); |
| 35 } |
| 36 } |
| 37 |
| 38 SkBitmapDevice::SkBitmapDevice(SkBitmap::Config config, int width, int height, b
ool isOpaque, |
| 39 const SkDeviceProperties& deviceProperties) |
| 40 : SkBaseDevice(deviceProperties) { |
| 41 |
| 42 fBitmap.setConfig(config, width, height); |
| 43 fBitmap.allocPixels(); |
| 44 fBitmap.setIsOpaque(isOpaque); |
| 45 if (!isOpaque) { |
| 46 fBitmap.eraseColor(SK_ColorTRANSPARENT); |
| 47 } |
| 48 } |
| 49 |
| 50 SkBitmapDevice::~SkBitmapDevice() { |
| 51 } |
| 52 |
| 53 void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) { |
| 54 SkASSERT(bm.width() == fBitmap.width()); |
| 55 SkASSERT(bm.height() == fBitmap.height()); |
| 56 fBitmap = bm; // intent is to use bm's pixelRef (and rowbytes/config) |
| 57 fBitmap.lockPixels(); |
| 58 } |
| 59 |
| 60 SkBaseDevice* SkBitmapDevice::onCreateCompatibleDevice(SkBitmap::Config config, |
| 61 int width, int height, |
| 62 bool isOpaque, |
| 63 Usage usage) { |
| 64 return SkNEW_ARGS(SkBitmapDevice,(config, width, height, isOpaque, |
| 65 this->getDeviceProperties())); |
| 66 } |
| 67 |
| 68 void SkBitmapDevice::lockPixels() { |
| 69 if (fBitmap.lockPixelsAreWritable()) { |
| 70 fBitmap.lockPixels(); |
| 71 } |
| 72 } |
| 73 |
| 74 void SkBitmapDevice::unlockPixels() { |
| 75 if (fBitmap.lockPixelsAreWritable()) { |
| 76 fBitmap.unlockPixels(); |
| 77 } |
| 78 } |
| 79 |
| 80 void SkBitmapDevice::getGlobalBounds(SkIRect* bounds) const { |
| 81 if (NULL != bounds) { |
| 82 const SkIPoint& origin = this->getOrigin(); |
| 83 bounds->setXYWH(origin.x(), origin.y(), |
| 84 fBitmap.width(), fBitmap.height()); |
| 85 } |
| 86 } |
| 87 |
| 88 void SkBitmapDevice::clear(SkColor color) { |
| 89 fBitmap.eraseColor(color); |
| 90 } |
| 91 |
| 92 const SkBitmap& SkBitmapDevice::onAccessBitmap() { |
| 93 return fBitmap; |
| 94 } |
| 95 |
| 96 bool SkBitmapDevice::canHandleImageFilter(SkImageFilter*) { |
| 97 return false; |
| 98 } |
| 99 |
| 100 bool SkBitmapDevice::filterImage(SkImageFilter* filter, const SkBitmap& src, |
| 101 const SkMatrix& ctm, SkBitmap* result, |
| 102 SkIPoint* offset) { |
| 103 return false; |
| 104 } |
| 105 |
| 106 bool SkBitmapDevice::allowImageFilter(SkImageFilter*) { |
| 107 return true; |
| 108 } |
| 109 |
| 110 bool SkBitmapDevice::onReadPixels(const SkBitmap& bitmap, |
| 111 int x, int y, |
| 112 SkCanvas::Config8888 config8888) { |
| 113 SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config()); |
| 114 SkASSERT(!bitmap.isNull()); |
| 115 SkASSERT(SkIRect::MakeWH(this->width(), this->height()).contains(SkIRect::Ma
keXYWH(x, y, |
| 116 bitmap
.width(), |
| 117 bitmap
.height()))); |
| 118 |
| 119 SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height()); |
| 120 const SkBitmap& src = this->accessBitmap(false); |
| 121 |
| 122 SkBitmap subset; |
| 123 if (!src.extractSubset(&subset, srcRect)) { |
| 124 return false; |
| 125 } |
| 126 if (SkBitmap::kARGB_8888_Config != subset.config()) { |
| 127 // It'd be preferable to do this directly to bitmap. |
| 128 subset.copyTo(&subset, SkBitmap::kARGB_8888_Config); |
| 129 } |
| 130 SkAutoLockPixels alp(bitmap); |
| 131 uint32_t* bmpPixels = reinterpret_cast<uint32_t*>(bitmap.getPixels()); |
| 132 SkCopyBitmapToConfig8888(bmpPixels, bitmap.rowBytes(), config8888, subset); |
| 133 return true; |
| 134 } |
| 135 |
| 136 void SkBitmapDevice::writePixels(const SkBitmap& bitmap, |
| 137 int x, int y, |
| 138 SkCanvas::Config8888 config8888) { |
| 139 if (bitmap.isNull() || bitmap.getTexture()) { |
| 140 return; |
| 141 } |
| 142 const SkBitmap* sprite = &bitmap; |
| 143 // check whether we have to handle a config8888 that doesn't match SkPMColor |
| 144 if (SkBitmap::kARGB_8888_Config == bitmap.config() && |
| 145 SkCanvas::kNative_Premul_Config8888 != config8888 && |
| 146 kPMColorAlias != config8888) { |
| 147 |
| 148 // We're going to have to convert from a config8888 to the native config |
| 149 // First we clip to the device bounds. |
| 150 SkBitmap dstBmp = this->accessBitmap(true); |
| 151 SkIRect spriteRect = SkIRect::MakeXYWH(x, y, |
| 152 bitmap.width(), bitmap.height()); |
| 153 SkIRect devRect = SkIRect::MakeWH(dstBmp.width(), dstBmp.height()); |
| 154 if (!spriteRect.intersect(devRect)) { |
| 155 return; |
| 156 } |
| 157 |
| 158 // write directly to the device if it has pixels and is SkPMColor |
| 159 bool drawSprite; |
| 160 if (SkBitmap::kARGB_8888_Config == dstBmp.config() && !dstBmp.isNull())
{ |
| 161 // we can write directly to the dst when doing the conversion |
| 162 dstBmp.extractSubset(&dstBmp, spriteRect); |
| 163 drawSprite = false; |
| 164 } else { |
| 165 // we convert to a temporary bitmap and draw that as a sprite |
| 166 dstBmp.setConfig(SkBitmap::kARGB_8888_Config, |
| 167 spriteRect.width(), |
| 168 spriteRect.height()); |
| 169 if (!dstBmp.allocPixels()) { |
| 170 return; |
| 171 } |
| 172 drawSprite = true; |
| 173 } |
| 174 |
| 175 // copy pixels to dstBmp and convert from config8888 to native config. |
| 176 SkAutoLockPixels alp(bitmap); |
| 177 uint32_t* srcPixels = bitmap.getAddr32(spriteRect.fLeft - x, |
| 178 spriteRect.fTop - y); |
| 179 SkCopyConfig8888ToBitmap(dstBmp, |
| 180 srcPixels, |
| 181 bitmap.rowBytes(), |
| 182 config8888); |
| 183 |
| 184 if (drawSprite) { |
| 185 // we've clipped the sprite when we made a copy |
| 186 x = spriteRect.fLeft; |
| 187 y = spriteRect.fTop; |
| 188 sprite = &dstBmp; |
| 189 } else { |
| 190 return; |
| 191 } |
| 192 } |
| 193 |
| 194 SkPaint paint; |
| 195 paint.setXfermodeMode(SkXfermode::kSrc_Mode); |
| 196 SkRasterClip clip(SkIRect::MakeWH(fBitmap.width(), fBitmap.height())); |
| 197 SkDraw draw; |
| 198 draw.fRC = &clip; |
| 199 draw.fClip = &clip.bwRgn(); |
| 200 draw.fBitmap = &fBitmap; // canvas should have already called accessBitmap |
| 201 draw.fMatrix = &SkMatrix::I(); |
| 202 this->drawSprite(draw, *sprite, x, y, paint); |
| 203 } |
| 204 |
| 205 /////////////////////////////////////////////////////////////////////////////// |
| 206 |
| 207 void SkBitmapDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) { |
| 208 draw.drawPaint(paint); |
| 209 } |
| 210 |
| 211 void SkBitmapDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, si
ze_t count, |
| 212 const SkPoint pts[], const SkPaint& paint) { |
| 213 CHECK_FOR_NODRAW_ANNOTATION(paint); |
| 214 draw.drawPoints(mode, count, pts, paint); |
| 215 } |
| 216 |
| 217 void SkBitmapDevice::drawRect(const SkDraw& draw, const SkRect& r, const SkPaint
& paint) { |
| 218 CHECK_FOR_NODRAW_ANNOTATION(paint); |
| 219 draw.drawRect(r, paint); |
| 220 } |
| 221 |
| 222 void SkBitmapDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPa
int& paint) { |
| 223 CHECK_FOR_NODRAW_ANNOTATION(paint); |
| 224 |
| 225 SkPath path; |
| 226 path.addOval(oval); |
| 227 // call the VIRTUAL version, so any subclasses who do handle drawPath aren't |
| 228 // required to override drawOval. |
| 229 this->drawPath(draw, path, paint, NULL, true); |
| 230 } |
| 231 |
| 232 void SkBitmapDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, const S
kPaint& paint) { |
| 233 CHECK_FOR_NODRAW_ANNOTATION(paint); |
| 234 |
| 235 SkPath path; |
| 236 path.addRRect(rrect); |
| 237 // call the VIRTUAL version, so any subclasses who do handle drawPath aren't |
| 238 // required to override drawRRect. |
| 239 this->drawPath(draw, path, paint, NULL, true); |
| 240 } |
| 241 |
| 242 void SkBitmapDevice::drawPath(const SkDraw& draw, const SkPath& path, |
| 243 const SkPaint& paint, const SkMatrix* prePathMatri
x, |
| 244 bool pathIsMutable) { |
| 245 CHECK_FOR_NODRAW_ANNOTATION(paint); |
| 246 draw.drawPath(path, paint, prePathMatrix, pathIsMutable); |
| 247 } |
| 248 |
| 249 void SkBitmapDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap, |
| 250 const SkMatrix& matrix, const SkPaint& paint) { |
| 251 draw.drawBitmap(bitmap, matrix, paint); |
| 252 } |
| 253 |
| 254 void SkBitmapDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, |
| 255 const SkRect* src, const SkRect& dst, |
| 256 const SkPaint& paint, |
| 257 SkCanvas::DrawBitmapRectFlags flags) { |
| 258 SkMatrix matrix; |
| 259 SkRect bitmapBounds, tmpSrc, tmpDst; |
| 260 SkBitmap tmpBitmap; |
| 261 |
| 262 bitmapBounds.isetWH(bitmap.width(), bitmap.height()); |
| 263 |
| 264 // Compute matrix from the two rectangles |
| 265 if (src) { |
| 266 tmpSrc = *src; |
| 267 } else { |
| 268 tmpSrc = bitmapBounds; |
| 269 } |
| 270 matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit); |
| 271 |
| 272 const SkRect* dstPtr = &dst; |
| 273 const SkBitmap* bitmapPtr = &bitmap; |
| 274 |
| 275 // clip the tmpSrc to the bounds of the bitmap, and recompute dstRect if |
| 276 // needed (if the src was clipped). No check needed if src==null. |
| 277 if (src) { |
| 278 if (!bitmapBounds.contains(*src)) { |
| 279 if (!tmpSrc.intersect(bitmapBounds)) { |
| 280 return; // nothing to draw |
| 281 } |
| 282 // recompute dst, based on the smaller tmpSrc |
| 283 matrix.mapRect(&tmpDst, tmpSrc); |
| 284 dstPtr = &tmpDst; |
| 285 } |
| 286 |
| 287 // since we may need to clamp to the borders of the src rect within |
| 288 // the bitmap, we extract a subset. |
| 289 SkIRect srcIR; |
| 290 tmpSrc.roundOut(&srcIR); |
| 291 if (!bitmap.extractSubset(&tmpBitmap, srcIR)) { |
| 292 return; |
| 293 } |
| 294 bitmapPtr = &tmpBitmap; |
| 295 |
| 296 // Since we did an extract, we need to adjust the matrix accordingly |
| 297 SkScalar dx = 0, dy = 0; |
| 298 if (srcIR.fLeft > 0) { |
| 299 dx = SkIntToScalar(srcIR.fLeft); |
| 300 } |
| 301 if (srcIR.fTop > 0) { |
| 302 dy = SkIntToScalar(srcIR.fTop); |
| 303 } |
| 304 if (dx || dy) { |
| 305 matrix.preTranslate(dx, dy); |
| 306 } |
| 307 |
| 308 SkRect extractedBitmapBounds; |
| 309 extractedBitmapBounds.isetWH(bitmapPtr->width(), bitmapPtr->height()); |
| 310 if (extractedBitmapBounds == tmpSrc) { |
| 311 // no fractional part in src, we can just call drawBitmap |
| 312 goto USE_DRAWBITMAP; |
| 313 } |
| 314 } else { |
| 315 USE_DRAWBITMAP: |
| 316 // We can go faster by just calling drawBitmap, which will concat the |
| 317 // matrix with the CTM, and try to call drawSprite if it can. If not, |
| 318 // it will make a shader and call drawRect, as we do below. |
| 319 this->drawBitmap(draw, *bitmapPtr, matrix, paint); |
| 320 return; |
| 321 } |
| 322 |
| 323 // construct a shader, so we can call drawRect with the dst |
| 324 SkShader* s = SkShader::CreateBitmapShader(*bitmapPtr, |
| 325 SkShader::kClamp_TileMode, |
| 326 SkShader::kClamp_TileMode); |
| 327 if (NULL == s) { |
| 328 return; |
| 329 } |
| 330 s->setLocalMatrix(matrix); |
| 331 |
| 332 SkPaint paintWithShader(paint); |
| 333 paintWithShader.setStyle(SkPaint::kFill_Style); |
| 334 paintWithShader.setShader(s)->unref(); |
| 335 |
| 336 // Call ourself, in case the subclass wanted to share this setup code |
| 337 // but handle the drawRect code themselves. |
| 338 this->drawRect(draw, *dstPtr, paintWithShader); |
| 339 } |
| 340 |
| 341 void SkBitmapDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, |
| 342 int x, int y, const SkPaint& paint) { |
| 343 draw.drawSprite(bitmap, x, y, paint); |
| 344 } |
| 345 |
| 346 void SkBitmapDevice::drawText(const SkDraw& draw, const void* text, size_t len, |
| 347 SkScalar x, SkScalar y, const SkPaint& paint) { |
| 348 draw.drawText((const char*)text, len, x, y, paint); |
| 349 } |
| 350 |
| 351 void SkBitmapDevice::drawPosText(const SkDraw& draw, const void* text, size_t le
n, |
| 352 const SkScalar xpos[], SkScalar y, |
| 353 int scalarsPerPos, const SkPaint& paint) { |
| 354 draw.drawPosText((const char*)text, len, xpos, y, scalarsPerPos, paint); |
| 355 } |
| 356 |
| 357 void SkBitmapDevice::drawTextOnPath(const SkDraw& draw, const void* text, |
| 358 size_t len, const SkPath& path, |
| 359 const SkMatrix* matrix, |
| 360 const SkPaint& paint) { |
| 361 draw.drawTextOnPath((const char*)text, len, path, matrix, paint); |
| 362 } |
| 363 |
| 364 #ifdef SK_BUILD_FOR_ANDROID |
| 365 void SkBitmapDevice::drawPosTextOnPath(const SkDraw& draw, const void* text, siz
e_t len, |
| 366 const SkPoint pos[], const SkPaint& paint
, |
| 367 const SkPath& path, const SkMatrix* matri
x) { |
| 368 draw.drawPosTextOnPath((const char*)text, len, pos, paint, path, matrix); |
| 369 } |
| 370 #endif |
| 371 |
| 372 void SkBitmapDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode
, |
| 373 int vertexCount, |
| 374 const SkPoint verts[], const SkPoint textures[
], |
| 375 const SkColor colors[], SkXfermode* xmode, |
| 376 const uint16_t indices[], int indexCount, |
| 377 const SkPaint& paint) { |
| 378 draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode, |
| 379 indices, indexCount, paint); |
| 380 } |
| 381 |
| 382 void SkBitmapDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device, |
| 383 int x, int y, const SkPaint& paint) { |
| 384 const SkBitmap& src = device->accessBitmap(false); |
| 385 draw.drawSprite(src, x, y, paint); |
| 386 } |
| 387 |
| 388 /////////////////////////////////////////////////////////////////////////////// |
| 389 |
| 390 bool SkBitmapDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) { |
| 391 if (!paint.isLCDRenderText() || !paint.isAntiAlias()) { |
| 392 // we're cool with the paint as is |
| 393 return false; |
| 394 } |
| 395 |
| 396 if (SkBitmap::kARGB_8888_Config != fBitmap.config() || |
| 397 paint.getRasterizer() || |
| 398 paint.getPathEffect() || |
| 399 paint.isFakeBoldText() || |
| 400 paint.getStyle() != SkPaint::kFill_Style || |
| 401 !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode)) { |
| 402 // turn off lcd |
| 403 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag; |
| 404 flags->fHinting = paint.getHinting(); |
| 405 return true; |
| 406 } |
| 407 // we're cool with the paint as is |
| 408 return false; |
| 409 } |
| 410 |
OLD | NEW |