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
draw_replacement_bitmap(GrCachedLayer * layer,SkCanvas * canvas)19 static 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.
54 class ReplaceDraw : public SkRecords::Draw {
55 public:
ReplaceDraw(SkCanvas * canvas,GrLayerCache * layerCache,SkPicture const * const drawablePicts[],int drawableCount,const SkPicture * topLevelPicture,const SkBigPicture * picture,const SkMatrix & initialMatrix,SkPicture::AbortCallback * callback,const int * opIndices,int numIndices)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
draw()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.
operator ()(const T & r)119 template <typename T> void operator()(const T& r) {
120 this->INHERITED::operator()(r);
121 }
operator ()(const SkRecords::DrawPicture & dp)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 }
operator ()(const SkRecords::SaveLayer & sl)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
190 private:
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
GrRecordReplaceDraw(const SkPicture * picture,SkCanvas * canvas,GrLayerCache * layerCache,const SkMatrix & initialMatrix,SkPicture::AbortCallback * callback)208 int 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