OLD | NEW |
| (Empty) |
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 | |
19 static inline void draw_replacement_bitmap(GrCachedLayer* layer, SkCanvas* canva
s) { | |
20 | |
21 // Some image filter can totally filter away a layer (e.g., SkPictureImageFi
lter'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_S
rcRectConstraint); | |
43 } else { | |
44 canvas->drawBitmap(bm, | |
45 SkIntToScalar(layer->srcIR().fLeft + layer->offset().
fX), | |
46 SkIntToScalar(layer->srcIR().fTop + layer->offset().f
Y), | |
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: | |
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 canva
s | |
89 // is not necessarily in that same space. getClipBounds() returns u
s | |
90 // this canvas' clip bounds transformed back into identity space, wh
ich | |
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(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(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 accordi
ngly. | |
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 | |
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 } | |
OLD | NEW |