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