1/*
2 * Copyright 2014 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 "GrContext.h"
9#include "GrLayerCache.h"
10#include "GrRecordReplaceDraw.h"
11#include "SkBigPicture.h"
12#include "SkCanvasPriv.h"
13#include "SkGr.h"
14#include "SkImage.h"
15#include "SkRecordDraw.h"
16#include "SkRecords.h"
17
18
19static inline void draw_replacement_bitmap(GrCachedLayer* layer, SkCanvas* canvas) {
20
21    // Some image filter can totally filter away a layer (e.g., SkPictureImageFilter's with
22    // no picture).
23    if (!layer->texture()) {
24        return;
25    }
26
27    SkBitmap bm;
28    GrWrapTextureInBitmap(layer->texture(),
29                          !layer->isAtlased() ? layer->rect().width()  : layer->texture()->width(),
30                          !layer->isAtlased() ? layer->rect().height() : layer->texture()->height(),
31                          false,
32                          &bm);
33
34    canvas->save();
35    canvas->setMatrix(SkMatrix::I());
36    if (layer->isAtlased()) {
37        const SkRect src = SkRect::Make(layer->rect());
38        const SkRect dst = SkRect::Make(layer->srcIR());
39
40        SkASSERT(layer->offset().isZero());
41
42        canvas->drawBitmapRect(bm, src, dst, layer->paint(), SkCanvas::kStrict_SrcRectConstraint);
43    } else {
44        canvas->drawBitmap(bm,
45                           SkIntToScalar(layer->srcIR().fLeft + layer->offset().fX),
46                           SkIntToScalar(layer->srcIR().fTop + layer->offset().fY),
47                           layer->paint());
48    }
49    canvas->restore();
50}
51
52// Used by GrRecordReplaceDraw. It intercepts nested drawPicture calls and
53// also draws them with replaced layers.
54class ReplaceDraw : public SkRecords::Draw {
55public:
56    ReplaceDraw(SkCanvas* canvas, GrLayerCache* layerCache,
57                SkPicture const* const drawablePicts[], int drawableCount,
58                const SkPicture* topLevelPicture,
59                const SkBigPicture* picture,
60                const SkMatrix& initialMatrix,
61                SkPicture::AbortCallback* callback,
62                const int* opIndices, int numIndices)
63        : INHERITED(canvas, drawablePicts, nullptr, drawableCount)
64        , fCanvas(canvas)
65        , fLayerCache(layerCache)
66        , fTopLevelPicture(topLevelPicture)
67        , fPicture(picture)
68        , fInitialMatrix(initialMatrix)
69        , fCallback(callback)
70        , fIndex(0)
71        , fNumReplaced(0) {
72        fOpIndexStack.append(numIndices, opIndices);
73    }
74
75    int draw() {
76        const SkBBoxHierarchy* bbh = fPicture->bbh();
77        const SkRecord* record = fPicture->record();
78        if (nullptr == record) {
79            return 0;
80        }
81
82        fNumReplaced = 0;
83
84        fOps.rewind();
85
86        if (bbh) {
87            // Draw only ops that affect pixels in the canvas's current clip.
88            // The SkRecord and BBH were recorded in identity space.  This canvas
89            // is not necessarily in that same space.  getClipBounds() returns us
90            // this canvas' clip bounds transformed back into identity space, which
91            // lets us query the BBH.
92            SkRect query = { 0, 0, 0, 0 };
93            (void)fCanvas->getClipBounds(&query);
94
95            bbh->search(query, &fOps);
96
97            for (fIndex = 0; fIndex < fOps.count(); ++fIndex) {
98                if (fCallback && fCallback->abort()) {
99                    return fNumReplaced;
100                }
101
102                record->visit<void>(fOps[fIndex], *this);
103            }
104
105        } else {
106            for (fIndex = 0; fIndex < (int) record->count(); ++fIndex) {
107                if (fCallback && fCallback->abort()) {
108                    return fNumReplaced;
109                }
110
111                record->visit<void>(fIndex, *this);
112            }
113        }
114
115        return fNumReplaced;
116    }
117
118    // Same as Draw for all ops except DrawPicture and SaveLayer.
119    template <typename T> void operator()(const T& r) {
120        this->INHERITED::operator()(r);
121    }
122    void operator()(const SkRecords::DrawPicture& dp) {
123
124        int drawPictureOffset;
125        if (fOps.count()) {
126            drawPictureOffset = fOps[fIndex];
127        } else {
128            drawPictureOffset = fIndex;
129        }
130
131        fOpIndexStack.push(drawPictureOffset);
132
133        SkAutoCanvasMatrixPaint acmp(fCanvas, &dp.matrix, dp.paint, dp.picture->cullRect());
134
135        if (const SkBigPicture* bp = dp.picture->asSkBigPicture()) {
136            // Draw sub-pictures with the same replacement list but a different picture
137            ReplaceDraw draw(fCanvas, fLayerCache,
138                             this->drawablePicts(), this->drawableCount(),
139                             fTopLevelPicture, bp, fInitialMatrix, fCallback,
140                             fOpIndexStack.begin(), fOpIndexStack.count());
141            fNumReplaced += draw.draw();
142        } else {
143            // TODO: can we assume / assert this doesn't happen?
144            dp.picture->playback(fCanvas, fCallback);
145        }
146
147        fOpIndexStack.pop();
148    }
149    void operator()(const SkRecords::SaveLayer& sl) {
150
151        // For a saveLayer command, check if it can be replaced by a drawBitmap
152        // call and, if so, draw it and then update the current op index accordingly.
153        int startOffset;
154        if (fOps.count()) {
155            startOffset = fOps[fIndex];
156        } else {
157            startOffset = fIndex;
158        }
159
160        fOpIndexStack.push(startOffset);
161
162        GrCachedLayer* layer = fLayerCache->findLayer(fTopLevelPicture->uniqueID(),
163                                                      fInitialMatrix,
164                                                      fOpIndexStack.begin(),
165                                                      fOpIndexStack.count());
166
167        if (layer) {
168            fNumReplaced++;
169
170            draw_replacement_bitmap(layer, fCanvas);
171
172            if (fPicture->bbh()) {
173                while (fOps[fIndex] < layer->stop()) {
174                    ++fIndex;
175                }
176                SkASSERT(fOps[fIndex] == layer->stop());
177            } else {
178                fIndex = layer->stop();
179            }
180            fOpIndexStack.pop();
181            return;
182        }
183
184        // This is a fail for layer hoisting
185        this->INHERITED::operator()(sl);
186
187        fOpIndexStack.pop();
188    }
189
190private:
191    SkCanvas*                 fCanvas;
192    GrLayerCache*             fLayerCache;
193    const SkPicture*          fTopLevelPicture;
194    const SkBigPicture*       fPicture;
195    const SkMatrix            fInitialMatrix;
196    SkPicture::AbortCallback* fCallback;
197
198    SkTDArray<int>            fOps;
199    int                       fIndex;
200    int                       fNumReplaced;
201
202    // The op code indices of all the enclosing drawPicture and saveLayer calls
203    SkTDArray<int>            fOpIndexStack;
204
205    typedef Draw INHERITED;
206};
207
208int GrRecordReplaceDraw(const SkPicture* picture,
209                        SkCanvas* canvas,
210                        GrLayerCache* layerCache,
211                        const SkMatrix& initialMatrix,
212                        SkPicture::AbortCallback* callback) {
213    SkAutoCanvasRestore saveRestore(canvas, true /*save now, restore at exit*/);
214
215    if (const SkBigPicture* bp = picture->asSkBigPicture()) {
216        // TODO: drawablePicts?
217        ReplaceDraw draw(canvas, layerCache, nullptr, 0,
218                         bp, bp,
219                         initialMatrix, callback, nullptr, 0);
220        return draw.draw();
221    } else {
222        // TODO: can we assume / assert this doesn't happen?
223        picture->playback(canvas, callback);
224        return 0;
225    }
226}
227