SkPictureUtils.cpp revision eed779d866e1e239bfb9ebc6a225b7345a41adf9
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
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    SkASSERT(!"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-bitmap.
49 */
50class GatherPixelRefDevice : public SkDevice {
51private:
52    PixelRefSet*  fPRSet;
53
54    void addBitmap(const SkBitmap& bm) {
55        fPRSet->add(bm.pixelRef());
56    }
57
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
72public:
73    GatherPixelRefDevice(const SkBitmap& bm, PixelRefSet* prset) : SkDevice(bm) {
74        fPRSet = prset;
75    }
76
77    virtual void clear(SkColor color) SK_OVERRIDE {
78        nothing_to_do();
79    }
80    virtual void writePixels(const SkBitmap& bitmap, int x, int y,
81                             SkCanvas::Config8888 config8888) SK_OVERRIDE {
82        not_supported();
83    }
84
85    virtual void drawPaint(const SkDraw&, const SkPaint& paint) SK_OVERRIDE {
86        this->addBitmapFromPaint(paint);
87    }
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    }
92    virtual void drawRect(const SkDraw&, const SkRect&,
93                          const SkPaint& paint) SK_OVERRIDE {
94        this->addBitmapFromPaint(paint);
95    }
96    virtual void drawOval(const SkDraw&, const SkRect&,
97                          const SkPaint& paint) SK_OVERRIDE {
98        this->addBitmapFromPaint(paint);
99    }
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    }
105    virtual void drawBitmap(const SkDraw&, const SkBitmap& bitmap,
106                            const SkMatrix&, const SkPaint&) SK_OVERRIDE {
107        this->addBitmap(bitmap);
108    }
109    virtual void drawBitmapRect(const SkDraw&, const SkBitmap& bitmap,
110                                const SkRect* srcOrNull, const SkRect& dst,
111                                const SkPaint&,
112                                SkCanvas::DrawBitmapRectFlags flags) SK_OVERRIDE {
113        this->addBitmap(bitmap);
114    }
115    virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap,
116                            int x, int y, const SkPaint& paint) SK_OVERRIDE {
117        this->addBitmap(bitmap);
118    }
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    }
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    }
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    }
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    }
141    virtual void drawDevice(const SkDraw&, SkDevice*, int x, int y,
142                            const SkPaint&) SK_OVERRIDE {
143        nothing_to_do();
144    }
145
146protected:
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
155class NoSaveLayerCanvas : public SkCanvas {
156public:
157    NoSaveLayerCanvas(SkDevice* device) : INHERITED(device) {}
158
159    // turn saveLayer() into save() for speed, should not affect correctness.
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
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.
181    virtual bool clipPath(const SkPath& path, SkRegion::Op op,
182                          bool doAA) SK_OVERRIDE {
183        return this->updateClipConservativelyUsingBounds(path.getBounds(), op, path.isInverseFillType());
184    }
185    virtual bool clipRRect(const SkRRect& rrect, SkRegion::Op op,
186                           bool doAA) SK_OVERRIDE {
187        return this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
188    }
189
190private:
191    typedef SkCanvas INHERITED;
192};
193
194SkData* 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