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 16 SkDevice::SkDevice(const SkBitmap& bitmap) : fBitmap(bitmap) { 17 fOrigin.setZero(); 18 fMetaData = NULL; 19 } 20 21 SkDevice::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 33 SkDevice::~SkDevice() { 34 delete fMetaData; 35 } 36 37 SkDevice* 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 44 SkDevice* 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 51 SkDevice* 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 58 SkMetaData& 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 67 void SkDevice::lockPixels() { 68 if (fBitmap.lockPixelsAreWritable()) { 69 fBitmap.lockPixels(); 70 } 71 } 72 73 void SkDevice::unlockPixels() { 74 if (fBitmap.lockPixelsAreWritable()) { 75 fBitmap.unlockPixels(); 76 } 77 } 78 79 const SkBitmap& SkDevice::accessBitmap(bool changePixels) { 80 const SkBitmap& bitmap = this->onAccessBitmap(&fBitmap); 81 if (changePixels) { 82 bitmap.notifyPixelsChanged(); 83 } 84 return bitmap; 85 } 86 87 void SkDevice::getGlobalBounds(SkIRect* bounds) const { 88 if (bounds) { 89 bounds->setXYWH(fOrigin.x(), fOrigin.y(), 90 fBitmap.width(), fBitmap.height()); 91 } 92 } 93 94 void SkDevice::clear(SkColor color) { 95 fBitmap.eraseColor(color); 96 } 97 98 const SkBitmap& SkDevice::onAccessBitmap(SkBitmap* bitmap) {return *bitmap;} 99 100 void SkDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& region, 101 const SkClipStack& clipStack) { 102 } 103 104 bool SkDevice::filterImage(SkImageFilter*, const SkBitmap& src, 105 const SkMatrix& ctm, 106 SkBitmap* result, SkIPoint* offset) { 107 return false; 108 } 109 110 bool SkDevice::allowImageFilter(SkImageFilter*) { 111 return true; 112 } 113 114 /////////////////////////////////////////////////////////////////////////////// 115 116 bool 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 190 bool 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 SkCopyBitmapToConfig8888(bmpPixels, bitmap.rowBytes(), config8888, subset); 212 return true; 213 } 214 215 void SkDevice::writePixels(const SkBitmap& bitmap, 216 int x, int y, 217 SkCanvas::Config8888 config8888) { 218 if (bitmap.isNull() || bitmap.getTexture()) { 219 return; 220 } 221 const SkBitmap* sprite = &bitmap; 222 // check whether we have to handle a config8888 that doesn't match SkPMColor 223 if (SkBitmap::kARGB_8888_Config == bitmap.config() && 224 SkCanvas::kNative_Premul_Config8888 != config8888 && 225 kPMColorAlias != config8888) { 226 227 // We're going to have to convert from a config8888 to the native config 228 // First we clip to the device bounds. 229 SkBitmap dstBmp = this->accessBitmap(true); 230 SkIRect spriteRect = SkIRect::MakeXYWH(x, y, 231 bitmap.width(), bitmap.height()); 232 SkIRect devRect = SkIRect::MakeWH(dstBmp.width(), dstBmp.height()); 233 if (!spriteRect.intersect(devRect)) { 234 return; 235 } 236 237 // write directly to the device if it has pixels and is SkPMColor 238 bool drawSprite; 239 if (SkBitmap::kARGB_8888_Config == dstBmp.config() && !dstBmp.isNull()) { 240 // we can write directly to the dst when doing the conversion 241 dstBmp.extractSubset(&dstBmp, spriteRect); 242 drawSprite = false; 243 } else { 244 // we convert to a temporary bitmap and draw that as a sprite 245 dstBmp.setConfig(SkBitmap::kARGB_8888_Config, 246 spriteRect.width(), 247 spriteRect.height()); 248 if (!dstBmp.allocPixels()) { 249 return; 250 } 251 drawSprite = true; 252 } 253 254 // copy pixels to dstBmp and convert from config8888 to native config. 255 SkAutoLockPixels alp(bitmap); 256 uint32_t* srcPixels = bitmap.getAddr32(spriteRect.fLeft - x, 257 spriteRect.fTop - y); 258 SkCopyConfig8888ToBitmap(dstBmp, 259 srcPixels, 260 bitmap.rowBytes(), 261 config8888); 262 263 if (drawSprite) { 264 // we've clipped the sprite when we made a copy 265 x = spriteRect.fLeft; 266 y = spriteRect.fTop; 267 sprite = &dstBmp; 268 } else { 269 return; 270 } 271 } 272 273 SkPaint paint; 274 paint.setXfermodeMode(SkXfermode::kSrc_Mode); 275 SkCanvas canvas(this); 276 canvas.drawSprite(*sprite, x, y, &paint); 277 } 278 279 /////////////////////////////////////////////////////////////////////////////// 280 281 void SkDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) { 282 draw.drawPaint(paint); 283 } 284 285 void SkDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count, 286 const SkPoint pts[], const SkPaint& paint) { 287 draw.drawPoints(mode, count, pts, paint); 288 } 289 290 void SkDevice::drawRect(const SkDraw& draw, const SkRect& r, 291 const SkPaint& paint) { 292 draw.drawRect(r, paint); 293 } 294 295 void SkDevice::drawPath(const SkDraw& draw, const SkPath& path, 296 const SkPaint& paint, const SkMatrix* prePathMatrix, 297 bool pathIsMutable) { 298 draw.drawPath(path, paint, prePathMatrix, pathIsMutable); 299 } 300 301 void SkDevice::drawBitmap(const SkDraw& draw, const SkBitmap& bitmap, 302 const SkIRect* srcRect, 303 const SkMatrix& matrix, const SkPaint& paint) { 304 SkBitmap tmp; // storage if we need a subset of bitmap 305 const SkBitmap* bitmapPtr = &bitmap; 306 307 if (srcRect) { 308 if (!bitmap.extractSubset(&tmp, *srcRect)) { 309 return; // extraction failed 310 } 311 bitmapPtr = &tmp; 312 } 313 draw.drawBitmap(*bitmapPtr, matrix, paint); 314 } 315 316 void SkDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, 317 int x, int y, const SkPaint& paint) { 318 draw.drawSprite(bitmap, x, y, paint); 319 } 320 321 void SkDevice::drawText(const SkDraw& draw, const void* text, size_t len, 322 SkScalar x, SkScalar y, const SkPaint& paint) { 323 draw.drawText((const char*)text, len, x, y, paint); 324 } 325 326 void SkDevice::drawPosText(const SkDraw& draw, const void* text, size_t len, 327 const SkScalar xpos[], SkScalar y, 328 int scalarsPerPos, const SkPaint& paint) { 329 draw.drawPosText((const char*)text, len, xpos, y, scalarsPerPos, paint); 330 } 331 332 void SkDevice::drawTextOnPath(const SkDraw& draw, const void* text, 333 size_t len, const SkPath& path, 334 const SkMatrix* matrix, 335 const SkPaint& paint) { 336 draw.drawTextOnPath((const char*)text, len, path, matrix, paint); 337 } 338 339 #ifdef SK_BUILD_FOR_ANDROID 340 void SkDevice::drawPosTextOnPath(const SkDraw& draw, const void* text, size_t len, 341 const SkPoint pos[], const SkPaint& paint, 342 const SkPath& path, const SkMatrix* matrix) { 343 draw.drawPosTextOnPath((const char*)text, len, pos, paint, path, matrix); 344 } 345 #endif 346 347 void SkDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode, 348 int vertexCount, 349 const SkPoint verts[], const SkPoint textures[], 350 const SkColor colors[], SkXfermode* xmode, 351 const uint16_t indices[], int indexCount, 352 const SkPaint& paint) { 353 draw.drawVertices(vmode, vertexCount, verts, textures, colors, xmode, 354 indices, indexCount, paint); 355 } 356 357 void SkDevice::drawDevice(const SkDraw& draw, SkDevice* device, 358 int x, int y, const SkPaint& paint) { 359 const SkBitmap& src = device->accessBitmap(false); 360 draw.drawSprite(src, x, y, paint); 361 } 362 363 /////////////////////////////////////////////////////////////////////////////// 364 365 bool SkDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) { 366 if (!paint.isLCDRenderText() || !paint.isAntiAlias()) { 367 // we're cool with the paint as is 368 return false; 369 } 370 371 if (SkBitmap::kARGB_8888_Config != fBitmap.config() || 372 paint.getRasterizer() || 373 paint.getPathEffect() || 374 paint.isFakeBoldText() || 375 paint.getStyle() != SkPaint::kFill_Style || 376 !SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode)) { 377 // turn off lcd 378 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag; 379 flags->fHinting = paint.getHinting(); 380 return true; 381 } 382 // we're cool with the paint as is 383 return false; 384 } 385 386