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