SkDevice.cpp revision 15e9d3e66e161ce23df30bc13f8a0c87d196b463
1 2/* 3 * Copyright 2011 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8#include "SkDevice.h" 9#include "SkDraw.h" 10#include "SkImageFilter.h" 11#include "SkMetaData.h" 12#include "SkRect.h" 13 14SK_DEFINE_INST_COUNT(SkDevice) 15 16/////////////////////////////////////////////////////////////////////////////// 17 18SkDevice::SkDevice(const SkBitmap& bitmap) : fBitmap(bitmap) { 19 fOrigin.setZero(); 20 fMetaData = NULL; 21} 22 23SkDevice::SkDevice(SkBitmap::Config config, int width, int height, bool isOpaque) { 24 fOrigin.setZero(); 25 fMetaData = NULL; 26 27 fBitmap.setConfig(config, width, height); 28 fBitmap.allocPixels(); 29 fBitmap.setIsOpaque(isOpaque); 30 if (!isOpaque) { 31 fBitmap.eraseColor(0); 32 } 33} 34 35SkDevice::~SkDevice() { 36 delete fMetaData; 37} 38 39SkDevice* SkDevice::createCompatibleDevice(SkBitmap::Config config, 40 int width, int height, 41 bool isOpaque) { 42 return this->onCreateCompatibleDevice(config, width, height, 43 isOpaque, kGeneral_Usage); 44} 45 46SkDevice* SkDevice::createCompatibleDeviceForSaveLayer(SkBitmap::Config config, 47 int width, int height, 48 bool isOpaque) { 49 return this->onCreateCompatibleDevice(config, width, height, 50 isOpaque, kSaveLayer_Usage); 51} 52 53SkDevice* SkDevice::onCreateCompatibleDevice(SkBitmap::Config config, 54 int width, int height, 55 bool isOpaque, 56 Usage usage) { 57 return SkNEW_ARGS(SkDevice,(config, width, height, isOpaque)); 58} 59 60SkMetaData& SkDevice::getMetaData() { 61 // metadata users are rare, so we lazily allocate it. If that changes we 62 // can decide to just make it a field in the device (rather than a ptr) 63 if (NULL == fMetaData) { 64 fMetaData = new SkMetaData; 65 } 66 return *fMetaData; 67} 68 69void SkDevice::lockPixels() { 70 if (fBitmap.lockPixelsAreWritable()) { 71 fBitmap.lockPixels(); 72 } 73} 74 75void SkDevice::unlockPixels() { 76 if (fBitmap.lockPixelsAreWritable()) { 77 fBitmap.unlockPixels(); 78 } 79} 80 81const SkBitmap& SkDevice::accessBitmap(bool changePixels) { 82 const SkBitmap& bitmap = this->onAccessBitmap(&fBitmap); 83 if (changePixels) { 84 bitmap.notifyPixelsChanged(); 85 } 86 return bitmap; 87} 88 89void SkDevice::getGlobalBounds(SkIRect* bounds) const { 90 if (bounds) { 91 bounds->setXYWH(fOrigin.x(), fOrigin.y(), 92 fBitmap.width(), fBitmap.height()); 93 } 94} 95 96void SkDevice::clear(SkColor color) { 97 fBitmap.eraseColor(color); 98} 99 100const SkBitmap& SkDevice::onAccessBitmap(SkBitmap* bitmap) {return *bitmap;} 101 102void SkDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& region, 103 const SkClipStack& clipStack) { 104} 105 106bool SkDevice::canHandleImageFilter(SkImageFilter*) { 107 return false; 108} 109 110bool SkDevice::filterImage(SkImageFilter* filter, const SkBitmap& src, 111 const SkMatrix& ctm, SkBitmap* result, 112 SkIPoint* offset) { 113 return false; 114} 115 116bool SkDevice::allowImageFilter(SkImageFilter*) { 117 return true; 118} 119 120/////////////////////////////////////////////////////////////////////////////// 121 122bool SkDevice::readPixels(SkBitmap* bitmap, int x, int y, 123 SkCanvas::Config8888 config8888) { 124 if (SkBitmap::kARGB_8888_Config != bitmap->config() || 125 NULL != bitmap->getTexture()) { 126 return false; 127 } 128 129 const SkBitmap& src = this->accessBitmap(false); 130 131 SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap->width(), 132 bitmap->height()); 133 SkIRect devbounds = SkIRect::MakeWH(src.width(), src.height()); 134 if (!srcRect.intersect(devbounds)) { 135 return false; 136 } 137 138 SkBitmap tmp; 139 SkBitmap* bmp; 140 if (bitmap->isNull()) { 141 tmp.setConfig(SkBitmap::kARGB_8888_Config, bitmap->width(), 142 bitmap->height()); 143 if (!tmp.allocPixels()) { 144 return false; 145 } 146 bmp = &tmp; 147 } else { 148 bmp = bitmap; 149 } 150 151 SkIRect subrect = srcRect; 152 subrect.offset(-x, -y); 153 SkBitmap bmpSubset; 154 bmp->extractSubset(&bmpSubset, subrect); 155 156 bool result = this->onReadPixels(bmpSubset, 157 srcRect.fLeft, 158 srcRect.fTop, 159 config8888); 160 if (result && bmp == &tmp) { 161 tmp.swap(*bitmap); 162 } 163 return result; 164} 165 166#ifdef SK_CPU_LENDIAN 167 #if 24 == SK_A32_SHIFT && 16 == SK_R32_SHIFT && \ 168 8 == SK_G32_SHIFT && 0 == SK_B32_SHIFT 169 const SkCanvas::Config8888 SkDevice::kPMColorAlias = 170 SkCanvas::kBGRA_Premul_Config8888; 171 #elif 24 == SK_A32_SHIFT && 0 == SK_R32_SHIFT && \ 172 8 == SK_G32_SHIFT && 16 == SK_B32_SHIFT 173 const SkCanvas::Config8888 SkDevice::kPMColorAlias = 174 SkCanvas::kRGBA_Premul_Config8888; 175 #else 176 const SkCanvas::Config8888 SkDevice::kPMColorAlias = 177 (SkCanvas::Config8888) -1; 178 #endif 179#else 180 #if 0 == SK_A32_SHIFT && 8 == SK_R32_SHIFT && \ 181 16 == SK_G32_SHIFT && 24 == SK_B32_SHIFT 182 const SkCanvas::Config8888 SkDevice::kPMColorAlias = 183 SkCanvas::kBGRA_Premul_Config8888; 184 #elif 0 == SK_A32_SHIFT && 24 == SK_R32_SHIFT && \ 185 16 == SK_G32_SHIFT && 8 == SK_B32_SHIFT 186 const SkCanvas::Config8888 SkDevice::kPMColorAlias = 187 SkCanvas::kRGBA_Premul_Config8888; 188 #else 189 const SkCanvas::Config8888 SkDevice::kPMColorAlias = 190 (SkCanvas::Config8888) -1; 191 #endif 192#endif 193 194#include <SkConfig8888.h> 195 196bool SkDevice::onReadPixels(const SkBitmap& bitmap, 197 int x, int y, 198 SkCanvas::Config8888 config8888) { 199 SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config()); 200 SkASSERT(!bitmap.isNull()); 201 SkASSERT(SkIRect::MakeWH(this->width(), this->height()).contains(SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height()))); 202 203 SkIRect srcRect = SkIRect::MakeXYWH(x, y, bitmap.width(), 204 bitmap.height()); 205 const SkBitmap& src = this->accessBitmap(false); 206 207 SkBitmap subset; 208 if (!src.extractSubset(&subset, srcRect)) { 209 return false; 210 } 211 if (SkBitmap::kARGB_8888_Config != subset.config()) { 212 // It'd be preferable to do this directly to bitmap. 213 subset.copyTo(&subset, SkBitmap::kARGB_8888_Config); 214 } 215 SkAutoLockPixels alp(bitmap); 216 uint32_t* bmpPixels = reinterpret_cast<uint32_t*>(bitmap.getPixels()); 217 SkCopyBitmapToConfig8888(bmpPixels, bitmap.rowBytes(), config8888, subset); 218 return true; 219} 220 221void SkDevice::writePixels(const SkBitmap& bitmap, 222 int x, int y, 223 SkCanvas::Config8888 config8888) { 224 if (bitmap.isNull() || bitmap.getTexture()) { 225 return; 226 } 227 const SkBitmap* sprite = &bitmap; 228 // check whether we have to handle a config8888 that doesn't match SkPMColor 229 if (SkBitmap::kARGB_8888_Config == bitmap.config() && 230 SkCanvas::kNative_Premul_Config8888 != config8888 && 231 kPMColorAlias != config8888) { 232 233 // We're going to have to convert from a config8888 to the native config 234 // First we clip to the device bounds. 235 SkBitmap dstBmp = this->accessBitmap(true); 236 SkIRect spriteRect = SkIRect::MakeXYWH(x, y, 237 bitmap.width(), bitmap.height()); 238 SkIRect devRect = SkIRect::MakeWH(dstBmp.width(), dstBmp.height()); 239 if (!spriteRect.intersect(devRect)) { 240 return; 241 } 242 243 // write directly to the device if it has pixels and is SkPMColor 244 bool drawSprite; 245 if (SkBitmap::kARGB_8888_Config == dstBmp.config() && !dstBmp.isNull()) { 246 // we can write directly to the dst when doing the conversion 247 dstBmp.extractSubset(&dstBmp, spriteRect); 248 drawSprite = false; 249 } else { 250 // we convert to a temporary bitmap and draw that as a sprite 251 dstBmp.setConfig(SkBitmap::kARGB_8888_Config, 252 spriteRect.width(), 253 spriteRect.height()); 254 if (!dstBmp.allocPixels()) { 255 return; 256 } 257 drawSprite = true; 258 } 259 260 // copy pixels to dstBmp and convert from config8888 to native config. 261 SkAutoLockPixels alp(bitmap); 262 uint32_t* srcPixels = bitmap.getAddr32(spriteRect.fLeft - x, 263 spriteRect.fTop - y); 264 SkCopyConfig8888ToBitmap(dstBmp, 265 srcPixels, 266 bitmap.rowBytes(), 267 config8888); 268 269 if (drawSprite) { 270 // we've clipped the sprite when we made a copy 271 x = spriteRect.fLeft; 272 y = spriteRect.fTop; 273 sprite = &dstBmp; 274 } else { 275 return; 276 } 277 } 278 279 SkPaint paint; 280 paint.setXfermodeMode(SkXfermode::kSrc_Mode); 281 SkCanvas canvas(this); 282 canvas.drawSprite(*sprite, x, y, &paint); 283} 284 285/////////////////////////////////////////////////////////////////////////////// 286 287void SkDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) { 288 draw.drawPaint(paint); 289} 290 291void SkDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count, 292 const SkPoint pts[], const SkPaint& paint) { 293 draw.drawPoints(mode, count, pts, paint); 294} 295 296void SkDevice::drawRect(const SkDraw& draw, const SkRect& r, 297 const SkPaint& paint) { 298 draw.drawRect(r, paint); 299} 300 301void SkDevice::drawPath(const SkDraw& draw, const SkPath& path, 302 const SkPaint& paint, const SkMatrix* prePathMatrix, 303 bool pathIsMutable) { 304 draw.drawPath(path, paint, prePathMatrix, pathIsMutable); 305} 306 307void SkDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap, 308 const SkIRect* srcRect, 309 const SkMatrix& matrix, const SkPaint& paint) { 310 SkBitmap tmp; // storage if we need a subset of bitmap 311 const SkBitmap* bitmapPtr = &bitmap; 312 313 if (srcRect) { 314 if (!bitmap.extractSubset(&tmp, *srcRect)) { 315 return; // extraction failed 316 } 317 bitmapPtr = &tmp; 318 } 319 draw.drawBitmap(*bitmapPtr, matrix, paint); 320} 321 322void SkDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, 323 int x, int y, const SkPaint& paint) { 324 draw.drawSprite(bitmap, x, y, paint); 325} 326 327void SkDevice::drawText(const SkDraw& draw, const void* text, size_t len, 328 SkScalar x, SkScalar y, const SkPaint& paint) { 329 draw.drawText((const char*)text, len, x, y, paint); 330} 331 332void SkDevice::drawPosText(const SkDraw& draw, const void* text, size_t len, 333 const SkScalar xpos[], SkScalar y, 334 int scalarsPerPos, const SkPaint& paint) { 335 draw.drawPosText((const char*)text, len, xpos, y, scalarsPerPos, paint); 336} 337 338void SkDevice::drawTextOnPath(const SkDraw& draw, const void* text, 339 size_t len, const SkPath& path, 340 const SkMatrix* matrix, 341 const SkPaint& paint) { 342 draw.drawTextOnPath((const char*)text, len, path, matrix, paint); 343} 344 345#ifdef SK_BUILD_FOR_ANDROID 346void SkDevice::drawPosTextOnPath(const SkDraw& draw, const void* text, size_t len, 347 const SkPoint pos[], const SkPaint& paint, 348 const SkPath& path, const SkMatrix* matrix) { 349 draw.drawPosTextOnPath((const char*)text, len, pos, paint, path, matrix); 350} 351#endif 352 353void SkDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode, 354 int vertexCount, 355 const SkPoint verts[], const SkPoint textures[], 356 const SkColor colors[], SkXfermode* xmode, 357 const uint16_t indices[], int indexCount, 358 const SkPaint& paint) { 359 draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode, 360 indices, indexCount, paint); 361} 362 363void SkDevice::drawDevice(const SkDraw& draw, SkDevice* device, 364 int x, int y, const SkPaint& paint) { 365 const SkBitmap& src = device->accessBitmap(false); 366 draw.drawSprite(src, x, y, paint); 367} 368 369/////////////////////////////////////////////////////////////////////////////// 370 371bool SkDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) { 372 if (!paint.isLCDRenderText() || !paint.isAntiAlias()) { 373 // we're cool with the paint as is 374 return false; 375 } 376 377 if (SkBitmap::kARGB_8888_Config != fBitmap.config() || 378 paint.getRasterizer() || 379 paint.getPathEffect() || 380 paint.isFakeBoldText() || 381 paint.getStyle() != SkPaint::kFill_Style || 382 !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode)) { 383 // turn off lcd 384 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag; 385 flags->fHinting = paint.getHinting(); 386 return true; 387 } 388 // we're cool with the paint as is 389 return false; 390} 391 392