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