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