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 "SkPictureUtils.h" 9 #include "SkCanvas.h" 10 #include "SkData.h" 11 #include "SkDevice.h" 12 #include "SkPixelRef.h" 13 #include "SkShader.h" 14 #include "SkRRect.h" 15 16 class PixelRefSet { 17 public: 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 34 private: 35 SkTDArray<SkPixelRef*>* fArray; 36 SkTDArray<uint32_t> fGenID; 37 }; 38 39 static void not_supported() { 40 SkASSERT(!"this method should never be called"); 41 } 42 43 static 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-bitmap. 49 * FIXME: Derive from SkBaseDevice. 50 */ 51 class GatherPixelRefDevice : public SkDevice { 52 private: 53 PixelRefSet* fPRSet; 54 55 void addBitmap(const SkBitmap& bm) { 56 fPRSet->add(bm.pixelRef()); 57 } 58 59 void addBitmapFromPaint(const SkPaint& paint) { 60 SkShader* shader = paint.getShader(); 61 if (shader) { 62 SkBitmap bm; 63 // Check whether the shader is a gradient in order to short-circuit 64 // call to asABitmap to prevent generation of bitmaps from 65 // gradient shaders, which implement asABitmap. 66 if (SkShader::kNone_GradientType == shader->asAGradient(NULL) && 67 shader->asABitmap(&bm, NULL, NULL)) { 68 fPRSet->add(bm.pixelRef()); 69 } 70 } 71 } 72 73 public: 74 GatherPixelRefDevice(const SkBitmap& bm, PixelRefSet* prset) : SkDevice(bm) { 75 fPRSet = prset; 76 } 77 78 virtual void clear(SkColor color) SK_OVERRIDE { 79 nothing_to_do(); 80 } 81 virtual void writePixels(const SkBitmap& bitmap, int x, int y, 82 SkCanvas::Config8888 config8888) SK_OVERRIDE { 83 not_supported(); 84 } 85 86 virtual void drawPaint(const SkDraw&, const SkPaint& paint) SK_OVERRIDE { 87 this->addBitmapFromPaint(paint); 88 } 89 virtual void drawPoints(const SkDraw&, SkCanvas::PointMode mode, size_t count, 90 const SkPoint[], const SkPaint& paint) SK_OVERRIDE { 91 this->addBitmapFromPaint(paint); 92 } 93 virtual void drawRect(const SkDraw&, const SkRect&, 94 const SkPaint& paint) SK_OVERRIDE { 95 this->addBitmapFromPaint(paint); 96 } 97 virtual void drawRRect(const SkDraw&, const SkRRect&, 98 const SkPaint& paint) SK_OVERRIDE { 99 this->addBitmapFromPaint(paint); 100 } 101 virtual void drawOval(const SkDraw&, const SkRect&, 102 const SkPaint& paint) SK_OVERRIDE { 103 this->addBitmapFromPaint(paint); 104 } 105 virtual void drawPath(const SkDraw&, const SkPath& path, 106 const SkPaint& paint, const SkMatrix* prePathMatrix, 107 bool pathIsMutable) SK_OVERRIDE { 108 this->addBitmapFromPaint(paint); 109 } 110 virtual void drawBitmap(const SkDraw&, const SkBitmap& bitmap, 111 const SkMatrix&, const SkPaint&) SK_OVERRIDE { 112 this->addBitmap(bitmap); 113 } 114 virtual void drawBitmapRect(const SkDraw&, const SkBitmap& bitmap, 115 const SkRect* srcOrNull, const SkRect& dst, 116 const SkPaint&) SK_OVERRIDE { 117 this->addBitmap(bitmap); 118 } 119 virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap, 120 int x, int y, const SkPaint& paint) SK_OVERRIDE { 121 this->addBitmap(bitmap); 122 } 123 virtual void drawText(const SkDraw&, const void* text, size_t len, 124 SkScalar x, SkScalar y, 125 const SkPaint& paint) SK_OVERRIDE { 126 this->addBitmapFromPaint(paint); 127 } 128 virtual void drawPosText(const SkDraw&, const void* text, size_t len, 129 const SkScalar pos[], SkScalar constY, 130 int, const SkPaint& paint) SK_OVERRIDE { 131 this->addBitmapFromPaint(paint); 132 } 133 virtual void drawTextOnPath(const SkDraw&, const void* text, size_t len, 134 const SkPath& path, const SkMatrix* matrix, 135 const SkPaint& paint) SK_OVERRIDE { 136 this->addBitmapFromPaint(paint); 137 } 138 virtual void drawVertices(const SkDraw&, SkCanvas::VertexMode, int vertexCount, 139 const SkPoint verts[], const SkPoint texs[], 140 const SkColor colors[], SkXfermode* xmode, 141 const uint16_t indices[], int indexCount, 142 const SkPaint& paint) SK_OVERRIDE { 143 this->addBitmapFromPaint(paint); 144 } 145 virtual void drawDevice(const SkDraw&, SkDevice*, int x, int y, 146 const SkPaint&) SK_OVERRIDE { 147 nothing_to_do(); 148 } 149 150 protected: 151 virtual bool onReadPixels(const SkBitmap& bitmap, 152 int x, int y, 153 SkCanvas::Config8888 config8888) SK_OVERRIDE { 154 not_supported(); 155 return false; 156 } 157 }; 158 159 class NoSaveLayerCanvas : public SkCanvas { 160 public: 161 NoSaveLayerCanvas(SkDevice* device) : INHERITED(device) {} 162 163 // turn saveLayer() into save() for speed, should not affect correctness. 164 virtual int saveLayer(const SkRect* bounds, const SkPaint* paint, 165 SaveFlags flags) SK_OVERRIDE { 166 167 // Like SkPictureRecord, we don't want to create layers, but we do need 168 // to respect the save and (possibly) its rect-clip. 169 170 int count = this->INHERITED::save(flags); 171 if (bounds) { 172 this->INHERITED::clipRectBounds(bounds, flags, NULL); 173 } 174 return count; 175 } 176 177 // disable aa for speed 178 virtual bool clipRect(const SkRect& rect, SkRegion::Op op, 179 bool doAA) SK_OVERRIDE { 180 return this->INHERITED::clipRect(rect, op, false); 181 } 182 183 // for speed, just respect the bounds, and disable AA. May give us a few 184 // false positives and negatives. 185 virtual bool clipPath(const SkPath& path, SkRegion::Op op, 186 bool doAA) SK_OVERRIDE { 187 return this->updateClipConservativelyUsingBounds(path.getBounds(), op, path.isInverseFillType()); 188 } 189 virtual bool clipRRect(const SkRRect& rrect, SkRegion::Op op, 190 bool doAA) SK_OVERRIDE { 191 return this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false); 192 } 193 194 private: 195 typedef SkCanvas INHERITED; 196 }; 197 198 SkData* SkPictureUtils::GatherPixelRefs(SkPicture* pict, const SkRect& area) { 199 if (NULL == pict) { 200 return NULL; 201 } 202 203 // this test also handles if either area or pict's width/height are empty 204 if (!SkRect::Intersects(area, 205 SkRect::MakeWH(SkIntToScalar(pict->width()), 206 SkIntToScalar(pict->height())))) { 207 return NULL; 208 } 209 210 SkTDArray<SkPixelRef*> array; 211 PixelRefSet prset(&array); 212 213 SkBitmap emptyBitmap; 214 emptyBitmap.setConfig(SkBitmap::kARGB_8888_Config, pict->width(), pict->height()); 215 // note: we do not set any pixels (shouldn't need to) 216 217 GatherPixelRefDevice device(emptyBitmap, &prset); 218 NoSaveLayerCanvas canvas(&device); 219 220 canvas.clipRect(area, SkRegion::kIntersect_Op, false); 221 canvas.drawPicture(*pict); 222 223 SkData* data = NULL; 224 int count = array.count(); 225 if (count > 0) { 226 data = SkData::NewFromMalloc(array.detach(), count * sizeof(SkPixelRef*)); 227 } 228 return data; 229 } 230