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