1/* 2 * Copyright 2012 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 "SkCanvas.h" 10#include "SkData.h" 11#include "SkPictureUtils.h" 12#include "SkPixelRef.h" 13#include "SkRRect.h" 14#include "SkShader.h" 15 16class PixelRefSet { 17public: 18 PixelRefSet(SkTDArray<SkPixelRef*>* array) : fArray(array) {} 19 20 // This does a linear search on existing pixelrefs, so if this list gets big 21 // we should use a more complex sorted/hashy thing. 22 // 23 void add(SkPixelRef* pr) { 24 uint32_t genID = pr->getGenerationID(); 25 if (fGenID.find(genID) < 0) { 26 *fArray->append() = pr; 27 *fGenID.append() = genID; 28// SkDebugf("--- adding [%d] %x %d\n", fArray->count() - 1, pr, genID); 29 } else { 30// SkDebugf("--- already have %x %d\n", pr, genID); 31 } 32 } 33 34private: 35 SkTDArray<SkPixelRef*>* fArray; 36 SkTDArray<uint32_t> fGenID; 37}; 38 39static void not_supported() { 40 SkDEBUGFAIL("this method should never be called"); 41} 42 43static void nothing_to_do() {} 44 45/** 46 * This device will route all bitmaps (primitives and in shaders) to its PRSet. 47 * It should never actually draw anything, so there need not be any pixels 48 * behind its device. 49 */ 50class GatherPixelRefDevice : public SkBaseDevice { 51public: 52 GatherPixelRefDevice(int width, int height, PixelRefSet* prset) { 53 fSize.set(width, height); 54 fEmptyBitmap.setConfig(SkBitmap::kNo_Config, width, height); 55 fPRSet = prset; 56 } 57 58 virtual uint32_t getDeviceCapabilities() SK_OVERRIDE { return 0; } 59 virtual int width() const SK_OVERRIDE { return fSize.width(); } 60 virtual int height() const SK_OVERRIDE { return fSize.height(); } 61 virtual bool isOpaque() const SK_OVERRIDE { return false; } 62 virtual SkBitmap::Config config() const SK_OVERRIDE { 63 return SkBitmap::kNo_Config; 64 } 65 virtual GrRenderTarget* accessRenderTarget() SK_OVERRIDE { return NULL; } 66 virtual bool filterTextFlags(const SkPaint& paint, TextFlags*) SK_OVERRIDE { 67 return true; 68 } 69 // TODO: allow this call to return failure, or move to SkBitmapDevice only. 70 virtual const SkBitmap& onAccessBitmap() SK_OVERRIDE { 71 return fEmptyBitmap; 72 } 73 virtual void lockPixels() SK_OVERRIDE { nothing_to_do(); } 74 virtual void unlockPixels() SK_OVERRIDE { nothing_to_do(); } 75 virtual bool allowImageFilter(SkImageFilter*) SK_OVERRIDE { return false; } 76 virtual bool canHandleImageFilter(SkImageFilter*) SK_OVERRIDE { return false; } 77 virtual bool filterImage(SkImageFilter*, const SkBitmap&, const SkMatrix&, 78 SkBitmap* result, SkIPoint* offset) SK_OVERRIDE { 79 return false; 80 } 81 82 virtual void clear(SkColor color) SK_OVERRIDE { 83 nothing_to_do(); 84 } 85 virtual void writePixels(const SkBitmap& bitmap, int x, int y, 86 SkCanvas::Config8888 config8888) SK_OVERRIDE { 87 not_supported(); 88 } 89 90 virtual void drawPaint(const SkDraw&, const SkPaint& paint) SK_OVERRIDE { 91 this->addBitmapFromPaint(paint); 92 } 93 virtual void drawPoints(const SkDraw&, SkCanvas::PointMode mode, size_t count, 94 const SkPoint[], const SkPaint& paint) SK_OVERRIDE { 95 this->addBitmapFromPaint(paint); 96 } 97 virtual void drawRect(const SkDraw&, const SkRect&, 98 const SkPaint& paint) SK_OVERRIDE { 99 this->addBitmapFromPaint(paint); 100 } 101 virtual void drawRRect(const SkDraw&, const SkRRect&, 102 const SkPaint& paint) SK_OVERRIDE { 103 this->addBitmapFromPaint(paint); 104 } 105 virtual void drawOval(const SkDraw&, const SkRect&, 106 const SkPaint& paint) SK_OVERRIDE { 107 this->addBitmapFromPaint(paint); 108 } 109 virtual void drawPath(const SkDraw&, const SkPath& path, 110 const SkPaint& paint, const SkMatrix* prePathMatrix, 111 bool pathIsMutable) SK_OVERRIDE { 112 this->addBitmapFromPaint(paint); 113 } 114 virtual void drawBitmap(const SkDraw&, const SkBitmap& bitmap, 115 const SkMatrix&, const SkPaint&) SK_OVERRIDE { 116 this->addBitmap(bitmap); 117 } 118 virtual void drawBitmapRect(const SkDraw&, const SkBitmap& bitmap, 119 const SkRect* srcOrNull, const SkRect& dst, 120 const SkPaint&, 121 SkCanvas::DrawBitmapRectFlags flags) SK_OVERRIDE { 122 this->addBitmap(bitmap); 123 } 124 virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap, 125 int x, int y, const SkPaint& paint) SK_OVERRIDE { 126 this->addBitmap(bitmap); 127 } 128 virtual void drawText(const SkDraw&, const void* text, size_t len, 129 SkScalar x, SkScalar y, 130 const SkPaint& paint) SK_OVERRIDE { 131 this->addBitmapFromPaint(paint); 132 } 133 virtual void drawPosText(const SkDraw&, const void* text, size_t len, 134 const SkScalar pos[], SkScalar constY, 135 int, const SkPaint& paint) SK_OVERRIDE { 136 this->addBitmapFromPaint(paint); 137 } 138 virtual void drawTextOnPath(const SkDraw&, const void* text, size_t len, 139 const SkPath& path, const SkMatrix* matrix, 140 const SkPaint& paint) SK_OVERRIDE { 141 this->addBitmapFromPaint(paint); 142 } 143 virtual void drawVertices(const SkDraw&, SkCanvas::VertexMode, int vertexCount, 144 const SkPoint verts[], const SkPoint texs[], 145 const SkColor colors[], SkXfermode* xmode, 146 const uint16_t indices[], int indexCount, 147 const SkPaint& paint) SK_OVERRIDE { 148 this->addBitmapFromPaint(paint); 149 } 150 virtual void drawDevice(const SkDraw&, SkBaseDevice*, int x, int y, 151 const SkPaint&) SK_OVERRIDE { 152 nothing_to_do(); 153 } 154 155protected: 156 virtual bool onReadPixels(const SkBitmap& bitmap, 157 int x, int y, 158 SkCanvas::Config8888 config8888) SK_OVERRIDE { 159 not_supported(); 160 return false; 161 } 162 163 virtual void replaceBitmapBackendForRasterSurface(const SkBitmap&) SK_OVERRIDE { 164 not_supported(); 165 } 166 virtual SkBaseDevice* onCreateCompatibleDevice(SkBitmap::Config config, 167 int width, int height, 168 bool isOpaque, 169 Usage usage) SK_OVERRIDE { 170 // we expect to only get called via savelayer, in which case it is fine. 171 SkASSERT(kSaveLayer_Usage == usage); 172 return SkNEW_ARGS(GatherPixelRefDevice, (width, height, fPRSet)); 173 } 174 virtual void flush() SK_OVERRIDE {} 175 176private: 177 PixelRefSet* fPRSet; 178 SkBitmap fEmptyBitmap; // legacy -- need to remove the need for this guy 179 SkISize fSize; 180 181 void addBitmap(const SkBitmap& bm) { 182 fPRSet->add(bm.pixelRef()); 183 } 184 185 void addBitmapFromPaint(const SkPaint& paint) { 186 SkShader* shader = paint.getShader(); 187 if (shader) { 188 SkBitmap bm; 189 // Check whether the shader is a gradient in order to short-circuit 190 // call to asABitmap to prevent generation of bitmaps from 191 // gradient shaders, which implement asABitmap. 192 if (SkShader::kNone_GradientType == shader->asAGradient(NULL) && 193 shader->asABitmap(&bm, NULL, NULL)) { 194 fPRSet->add(bm.pixelRef()); 195 } 196 } 197 } 198 199 typedef SkBaseDevice INHERITED; 200}; 201 202class NoSaveLayerCanvas : public SkCanvas { 203public: 204 NoSaveLayerCanvas(SkBaseDevice* device) : INHERITED(device) {} 205 206 // turn saveLayer() into save() for speed, should not affect correctness. 207 virtual int saveLayer(const SkRect* bounds, const SkPaint* paint, 208 SaveFlags flags) SK_OVERRIDE { 209 210 // Like SkPictureRecord, we don't want to create layers, but we do need 211 // to respect the save and (possibly) its rect-clip. 212 213 int count = this->INHERITED::save(flags); 214 if (bounds) { 215 this->INHERITED::clipRectBounds(bounds, flags, NULL); 216 } 217 return count; 218 } 219 220 // disable aa for speed 221 virtual bool clipRect(const SkRect& rect, SkRegion::Op op, 222 bool doAA) SK_OVERRIDE { 223 return this->INHERITED::clipRect(rect, op, false); 224 } 225 226 // for speed, just respect the bounds, and disable AA. May give us a few 227 // false positives and negatives. 228 virtual bool clipPath(const SkPath& path, SkRegion::Op op, 229 bool doAA) SK_OVERRIDE { 230 return this->updateClipConservativelyUsingBounds(path.getBounds(), op, path.isInverseFillType()); 231 } 232 virtual bool clipRRect(const SkRRect& rrect, SkRegion::Op op, 233 bool doAA) SK_OVERRIDE { 234 return this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false); 235 } 236 237private: 238 typedef SkCanvas INHERITED; 239}; 240 241SkData* SkPictureUtils::GatherPixelRefs(SkPicture* pict, const SkRect& area) { 242 if (NULL == pict) { 243 return NULL; 244 } 245 246 // this test also handles if either area or pict's width/height are empty 247 if (!SkRect::Intersects(area, 248 SkRect::MakeWH(SkIntToScalar(pict->width()), 249 SkIntToScalar(pict->height())))) { 250 return NULL; 251 } 252 253 SkTDArray<SkPixelRef*> array; 254 PixelRefSet prset(&array); 255 256 GatherPixelRefDevice device(pict->width(), pict->height(), &prset); 257 NoSaveLayerCanvas canvas(&device); 258 259 canvas.clipRect(area, SkRegion::kIntersect_Op, false); 260 canvas.drawPicture(*pict); 261 262 SkData* data = NULL; 263 int count = array.count(); 264 if (count > 0) { 265 data = SkData::NewFromMalloc(array.detach(), count * sizeof(SkPixelRef*)); 266 } 267 return data; 268} 269