Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(188)

Side by Side Diff: src/core/SkMatrixClipStateMgr.cpp

Issue 169283011: Fix saveLayer bugs in SkMatrixClipStateMgr (Closed) Base URL: http://skia.googlecode.com/svn/trunk/
Patch Set: Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/core/SkMatrixClipStateMgr.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2014 Google Inc. 2 * Copyright 2014 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkMatrixClipStateMgr.h" 8 #include "SkMatrixClipStateMgr.h"
9 #include "SkPictureRecord.h" 9 #include "SkPictureRecord.h"
10 10
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
105 sizeof(fMatrixClipStackStorage)) 105 sizeof(fMatrixClipStackStorage))
106 , fCurOpenStateID(kIdentityWideOpenStateID) { 106 , fCurOpenStateID(kIdentityWideOpenStateID) {
107 107
108 fSkipOffsets = SkNEW(SkTDArray<int>); 108 fSkipOffsets = SkNEW(SkTDArray<int>);
109 109
110 // The first slot in the matrix dictionary is reserved for the identity matr ix 110 // The first slot in the matrix dictionary is reserved for the identity matr ix
111 fMatrixDict.append()->reset(); 111 fMatrixDict.append()->reset();
112 112
113 fCurMCState = (MatrixClipState*)fMatrixClipStack.push_back(); 113 fCurMCState = (MatrixClipState*)fMatrixClipStack.push_back();
114 new (fCurMCState) MatrixClipState(NULL, 0); // balanced in restore() 114 new (fCurMCState) MatrixClipState(NULL, 0); // balanced in restore()
115
116 #ifdef SK_DEBUG
117 fActualDepth = 0;
118 #endif
115 } 119 }
116 120
117 SkMatrixClipStateMgr::~SkMatrixClipStateMgr() { 121 SkMatrixClipStateMgr::~SkMatrixClipStateMgr() {
118 for (int i = 0; i < fRegionDict.count(); ++i) { 122 for (int i = 0; i < fRegionDict.count(); ++i) {
119 SkDELETE(fRegionDict[i]); 123 SkDELETE(fRegionDict[i]);
120 } 124 }
121 125
122 SkDELETE(fSkipOffsets); 126 SkDELETE(fSkipOffsets);
123 } 127 }
124 128
125 129
126 int SkMatrixClipStateMgr::MCStackPush(SkCanvas::SaveFlags flags) { 130 int SkMatrixClipStateMgr::MCStackPush(SkCanvas::SaveFlags flags) {
127 MatrixClipState* newTop = (MatrixClipState*)fMatrixClipStack.push_back(); 131 MatrixClipState* newTop = (MatrixClipState*)fMatrixClipStack.push_back();
128 new (newTop) MatrixClipState(fCurMCState, flags); // balanced in restore() 132 new (newTop) MatrixClipState(fCurMCState, flags); // balanced in restore()
129 fCurMCState = newTop; 133 fCurMCState = newTop;
130 134
131 SkDEBUGCODE(this->validate();) 135 SkDEBUGCODE(this->validate();)
132 136
133 return fMatrixClipStack.count(); 137 return fMatrixClipStack.count();
134 } 138 }
135 139
136 int SkMatrixClipStateMgr::save(SkCanvas::SaveFlags flags) { 140 int SkMatrixClipStateMgr::save(SkCanvas::SaveFlags flags) {
137 SkDEBUGCODE(this->validate();) 141 SkDEBUGCODE(this->validate();)
138 142
139 return this->MCStackPush(flags); 143 return this->MCStackPush(flags);
140 } 144 }
141 145
142 int SkMatrixClipStateMgr::saveLayer(const SkRect* bounds, const SkPaint* paint, 146 int SkMatrixClipStateMgr::saveLayer(const SkRect* bounds, const SkPaint* paint,
143 SkCanvas::SaveFlags flags) { 147 SkCanvas::SaveFlags flags) {
148 #ifdef SK_DEBUG
149 if (fCurMCState->fIsSaveLayer) {
150 SkASSERT(0 == fSkipOffsets->count());
151 }
152 #endif
153
144 // Since the saveLayer call draws something we need to potentially dump 154 // Since the saveLayer call draws something we need to potentially dump
145 // out the MC state 155 // out the MC state
146 this->call(kOther_CallType); 156 SkDEBUGCODE(bool saved =) this->call(kOther_CallType);
147 157
148 int result = this->MCStackPush(flags); 158 int result = this->MCStackPush(flags);
149 ++fCurMCState->fLayerID; 159 ++fCurMCState->fLayerID;
150 fCurMCState->fIsSaveLayer = true; 160 fCurMCState->fIsSaveLayer = true;
151 161
162 #ifdef SK_DEBUG
163 if (saved) {
164 fCurMCState->fExpectedDepth++; // 1 for nesting save
165 }
166 fCurMCState->fExpectedDepth++; // 1 for saveLayer
167 #endif
168
152 fCurMCState->fSaveLayerBaseStateID = fCurOpenStateID; 169 fCurMCState->fSaveLayerBaseStateID = fCurOpenStateID;
153 fCurMCState->fSavedSkipOffsets = fSkipOffsets; 170 fCurMCState->fSavedSkipOffsets = fSkipOffsets;
154 171
155 // TODO: recycle these rather then new & deleting them on every saveLayer/ 172 // TODO: recycle these rather then new & deleting them on every saveLayer/
156 // restore 173 // restore
157 fSkipOffsets = SkNEW(SkTDArray<int>); 174 fSkipOffsets = SkNEW(SkTDArray<int>);
158 175
159 fPicRecord->recordSaveLayer(bounds, paint, 176 fPicRecord->recordSaveLayer(bounds, paint,
160 (SkCanvas::SaveFlags)(flags| SkCanvas::kMatrixCl ip_SaveFlag)); 177 (SkCanvas::SaveFlags)(flags| SkCanvas::kMatrixCl ip_SaveFlag));
178 #ifdef SK_DEBUG
179 fActualDepth++;
180 #endif
161 return result; 181 return result;
162 } 182 }
163 183
164 void SkMatrixClipStateMgr::restore() { 184 void SkMatrixClipStateMgr::restore() {
165 SkDEBUGCODE(this->validate();) 185 SkDEBUGCODE(this->validate();)
166 186
167 if (fCurMCState->fIsSaveLayer) { 187 if (fCurMCState->fIsSaveLayer) {
168 if (fCurMCState->fSaveLayerBaseStateID != fCurOpenStateID) { 188 if (fCurMCState->fHasOpen) {
189 fCurMCState->fHasOpen = false;
169 fPicRecord->recordRestore(); // Close the open block inside the save Layer 190 fPicRecord->recordRestore(); // Close the open block inside the save Layer
191 #ifdef SK_DEBUG
192 SkASSERT(fActualDepth > 0);
193 fActualDepth--;
194 #endif
195 } else {
196 SkASSERT(0 == fSkipOffsets->count());
170 } 197 }
198
171 // The saveLayer's don't carry any matrix or clip state in the 199 // The saveLayer's don't carry any matrix or clip state in the
172 // new scheme so make sure the saveLayer's recordRestore doesn't 200 // new scheme so make sure the saveLayer's recordRestore doesn't
173 // try to finalize them (i.e., fill in their skip offsets). 201 // try to finalize them (i.e., fill in their skip offsets).
174 fPicRecord->recordRestore(false); // close of saveLayer 202 fPicRecord->recordRestore(false); // close of saveLayer
203 #ifdef SK_DEBUG
204 SkASSERT(fActualDepth > 0);
205 fActualDepth--;
206 #endif
175 207
176 fCurOpenStateID = fCurMCState->fSaveLayerBaseStateID; 208 fCurOpenStateID = fCurMCState->fSaveLayerBaseStateID;
177 209
178 SkASSERT(0 == fSkipOffsets->count()); 210 SkASSERT(0 == fSkipOffsets->count());
179 SkASSERT(NULL != fCurMCState->fSavedSkipOffsets); 211 SkASSERT(NULL != fCurMCState->fSavedSkipOffsets);
180 212
181 SkDELETE(fSkipOffsets); 213 SkDELETE(fSkipOffsets);
182 fSkipOffsets = fCurMCState->fSavedSkipOffsets; 214 fSkipOffsets = fCurMCState->fSavedSkipOffsets;
183 } 215 }
184 216
217 bool prevHadOpen = fCurMCState->fHasOpen;
218 bool prevWasSaveLayer = fCurMCState->fIsSaveLayer;
219
185 fCurMCState->~MatrixClipState(); // balanced in save() 220 fCurMCState->~MatrixClipState(); // balanced in save()
186 fMatrixClipStack.pop_back(); 221 fMatrixClipStack.pop_back();
187 fCurMCState = (MatrixClipState*)fMatrixClipStack.back(); 222 fCurMCState = (MatrixClipState*)fMatrixClipStack.back();
188 223
224 if (!prevWasSaveLayer) {
225 fCurMCState->fHasOpen = prevHadOpen;
226 }
227
228 if (fCurMCState->fIsSaveLayer) {
229 if (0 != fSkipOffsets->count()) {
230 SkASSERT(fCurMCState->fHasOpen);
231 }
232 }
233
189 SkDEBUGCODE(this->validate();) 234 SkDEBUGCODE(this->validate();)
190 } 235 }
191 236
192 // kIdentityWideOpenStateID (0) is reserved for the identity/wide-open clip stat e 237 // kIdentityWideOpenStateID (0) is reserved for the identity/wide-open clip stat e
193 int32_t SkMatrixClipStateMgr::NewMCStateID() { 238 int32_t SkMatrixClipStateMgr::NewMCStateID() {
194 // TODO: guard against wrap around 239 // TODO: guard against wrap around
195 // TODO: make uint32_t 240 // TODO: make uint32_t
196 static int32_t gMCStateID = kIdentityWideOpenStateID; 241 static int32_t gMCStateID = kIdentityWideOpenStateID;
197 ++gMCStateID; 242 ++gMCStateID;
198 return gMCStateID; 243 return gMCStateID;
199 } 244 }
200 245
246 bool SkMatrixClipStateMgr::isCurrentlyOpen(int32_t stateID) {
247 if (fCurMCState->fIsSaveLayer)
248 return false;
249
250 SkDeque::Iter iter(fMatrixClipStack, SkDeque::Iter::kBack_IterStart);
251
252 for (const MatrixClipState* state = (const MatrixClipState*) iter.prev();
253 state != NULL;
254 state = (const MatrixClipState*) iter.prev()) {
255 if (state->fIsSaveLayer) {
256 if (state->fSaveLayerBaseStateID == stateID) {
257 return true;
258 }
259 }
260 }
261
262 return false;
263 }
264
201 bool SkMatrixClipStateMgr::call(CallType callType) { 265 bool SkMatrixClipStateMgr::call(CallType callType) {
202 SkDEBUGCODE(this->validate();) 266 SkDEBUGCODE(this->validate();)
203 267
204 if (kMatrix_CallType == callType || kClip_CallType == callType) { 268 if (kMatrix_CallType == callType || kClip_CallType == callType) {
205 fCurMCState->fMCStateID = NewMCStateID(); 269 fCurMCState->fMCStateID = NewMCStateID();
206 SkDEBUGCODE(this->validate();) 270 SkDEBUGCODE(this->validate();)
207 return false; 271 return false;
208 } 272 }
209 273
210 SkASSERT(kOther_CallType == callType); 274 SkASSERT(kOther_CallType == callType);
211 275
212 if (fCurMCState->fMCStateID == fCurOpenStateID) { 276 if (fCurMCState->fMCStateID == fCurOpenStateID) {
213 // Required MC state is already active one - nothing to do 277 // Required MC state is already active one - nothing to do
214 SkDEBUGCODE(this->validate();) 278 SkDEBUGCODE(this->validate();)
215 return false; 279 return false;
216 } 280 }
217 281
218 if (kIdentityWideOpenStateID != fCurOpenStateID && 282 if (kIdentityWideOpenStateID != fCurOpenStateID &&
219 (!fCurMCState->fIsSaveLayer || 283 !this->isCurrentlyOpen(fCurOpenStateID)) {
220 fCurMCState->fSaveLayerBaseStateID != fCurOpenStateID)) {
221 // Don't write a restore if the open state is one in which a saveLayer 284 // Don't write a restore if the open state is one in which a saveLayer
222 // is nested. The save after the saveLayer's restore will close it. 285 // is nested. The save after the saveLayer's restore will close it.
223 fPicRecord->recordRestore(); // Close the open block 286 fPicRecord->recordRestore(); // Close the open block
287 fCurMCState->fHasOpen = false;
288 #ifdef SK_DEBUG
289 SkASSERT(fActualDepth > 0);
290 fActualDepth--;
291 #endif
224 } 292 }
225 293
226 // Install the required MC state as the active one 294 // Install the required MC state as the active one
227 fCurOpenStateID = fCurMCState->fMCStateID; 295 fCurOpenStateID = fCurMCState->fMCStateID;
228 296
297 if (kIdentityWideOpenStateID == fCurOpenStateID) {
298 SkASSERT(0 == fActualDepth);
299 SkASSERT(!fCurMCState->fHasOpen);
300 SkASSERT(0 == fSkipOffsets->count());
301 return false;
302 }
303
304 SkASSERT(!fCurMCState->fHasOpen);
305 SkASSERT(0 == fSkipOffsets->count());
306 fCurMCState->fHasOpen = true;
229 fPicRecord->recordSave(SkCanvas::kMatrixClip_SaveFlag); 307 fPicRecord->recordSave(SkCanvas::kMatrixClip_SaveFlag);
308 #ifdef SK_DEBUG
309 fActualDepth++;
310 SkASSERT(fActualDepth == fCurMCState->fExpectedDepth);
311 #endif
230 312
231 // write out clips 313 // write out clips
232 SkDeque::Iter iter(fMatrixClipStack, SkDeque::Iter::kBack_IterStart); 314 SkDeque::Iter iter(fMatrixClipStack, SkDeque::Iter::kBack_IterStart);
233 const MatrixClipState* state; 315 const MatrixClipState* state;
234 // Loop back across the MC states until the last saveLayer. The MC 316 // Loop back across the MC states until the last saveLayer. The MC
235 // state in front of the saveLayer has already been written out. 317 // state in front of the saveLayer has already been written out.
236 for (state = (const MatrixClipState*) iter.prev(); 318 for (state = (const MatrixClipState*) iter.prev();
237 state != NULL; 319 state != NULL;
238 state = (const MatrixClipState*) iter.prev()) { 320 state = (const MatrixClipState*) iter.prev()) {
239 if (state->fIsSaveLayer) { 321 if (state->fIsSaveLayer) {
240 break; 322 break;
241 } 323 }
242 } 324 }
243 325
326 int curMatID;
327
244 if (NULL == state) { 328 if (NULL == state) {
245 // There was no saveLayer in the MC stack so we need to output them all 329 // There was no saveLayer in the MC stack so we need to output them all
246 iter.reset(fMatrixClipStack, SkDeque::Iter::kFront_IterStart); 330 iter.reset(fMatrixClipStack, SkDeque::Iter::kFront_IterStart);
247 state = (const MatrixClipState*) iter.next(); 331 state = (const MatrixClipState*) iter.next();
332 curMatID = kIdentityMatID;
248 } else { 333 } else {
249 // SkDeque's iterators actually return the previous location so we 334 // SkDeque's iterators actually return the previous location so we
250 // need to reverse and go forward one to get back on track. 335 // need to reverse and go forward one to get back on track.
251 iter.next(); 336 iter.next();
252 SkDEBUGCODE(const MatrixClipState* test = (const MatrixClipState*)) iter .next(); 337 SkDEBUGCODE(const MatrixClipState* test = (const MatrixClipState*)) iter .next();
253 SkASSERT(test == state); 338 SkASSERT(test == state);
339
340 curMatID = state->fMatrixInfo->getID(this);
341
342 // TODO: this assumes that, in the case of Save|SaveLayer when the SaveL ayer
343 // doesn't save the clip, that the SaveLayer doesn't add any additional clip state.
344 // This assumption will be removed when we explicitly store the clip sta te in
345 // self-contained objects. It is valid for the small set of skps.
346 if (NULL != state->fPrev && state->fClipInfo == state->fPrev->fClipInfo) {
347 // By the above assumption the SaveLayer's MC state has already been
348 // written out by the prior Save so don't output it again.
349 state = (const MatrixClipState*) iter.next();
350 }
254 } 351 }
255 352
256 int curMatID = NULL != state ? state->fMatrixInfo->getID(this) : kIdentityMa tID;
257 for ( ; state != NULL; state = (const MatrixClipState*) iter.next()) { 353 for ( ; state != NULL; state = (const MatrixClipState*) iter.next()) {
258 state->fClipInfo->writeClip(&curMatID, this); 354 state->fClipInfo->writeClip(&curMatID, this);
259 } 355 }
260 356
261 // write out matrix 357 // write out matrix
262 // TODO: this test isn't quite right. It should be: 358 // TODO: this test isn't quite right. It should be:
263 // if (curMatID != fCurMCState->fMatrixInfo->getID(this)) { 359 // if (curMatID != fCurMCState->fMatrixInfo->getID(this)) {
264 // but right now the testing harness always expects a matrix if 360 // but right now the testing harness always expects a matrix if
265 // the matrices are non-I 361 // the matrices are non-I
266 if (kIdentityMatID != fCurMCState->fMatrixInfo->getID(this)) { 362 if (kIdentityMatID != fCurMCState->fMatrixInfo->getID(this)) {
267 // TODO: writing out the delta matrix here is an artifact of the writing 363 // TODO: writing out the delta matrix here is an artifact of the writing
268 // out of the entire clip stack (with its matrices). Ultimately we will 364 // out of the entire clip stack (with its matrices). Ultimately we will
269 // write out the CTM here when the clip state is collapsed to a single p ath. 365 // write out the CTM here when the clip state is collapsed to a single p ath.
270 this->writeDeltaMat(curMatID, fCurMCState->fMatrixInfo->getID(this)); 366 this->writeDeltaMat(curMatID, fCurMCState->fMatrixInfo->getID(this));
271 } 367 }
272 368
273 SkDEBUGCODE(this->validate();) 369 SkDEBUGCODE(this->validate();)
274
275 return true; 370 return true;
276 } 371 }
277 372
278 // Fill in the skip offsets for all the clips written in the current block 373 // Fill in the skip offsets for all the clips written in the current block
279 void SkMatrixClipStateMgr::fillInSkips(SkWriter32* writer, int32_t restoreOffset ) { 374 void SkMatrixClipStateMgr::fillInSkips(SkWriter32* writer, int32_t restoreOffset ) {
280 for (int i = 0; i < fSkipOffsets->count(); ++i) { 375 for (int i = 0; i < fSkipOffsets->count(); ++i) {
281 SkDEBUGCODE(int32_t peek = writer->readTAt<int32_t>((*fSkipOffsets)[i]); ) 376 SkDEBUGCODE(int32_t peek = writer->readTAt<int32_t>((*fSkipOffsets)[i]); )
282 SkASSERT(-1 == peek); 377 SkASSERT(-1 == peek);
283 writer->overwriteTAt<int32_t>((*fSkipOffsets)[i], restoreOffset); 378 writer->overwriteTAt<int32_t>((*fSkipOffsets)[i], restoreOffset);
284 } 379 }
285 380
286 fSkipOffsets->rewind(); 381 fSkipOffsets->rewind();
382 SkASSERT(0 == fSkipOffsets->count());
287 } 383 }
288 384
289 void SkMatrixClipStateMgr::finish() { 385 void SkMatrixClipStateMgr::finish() {
290 if (kIdentityWideOpenStateID != fCurOpenStateID) { 386 if (kIdentityWideOpenStateID != fCurOpenStateID) {
291 fPicRecord->recordRestore(); // Close the open block 387 fPicRecord->recordRestore(); // Close the open block
388 fCurMCState->fHasOpen = false;
389 #ifdef SK_DEBUG
390 SkASSERT(fActualDepth > 0);
391 fActualDepth--;
392 #endif
292 fCurOpenStateID = kIdentityWideOpenStateID; 393 fCurOpenStateID = kIdentityWideOpenStateID;
394 SkASSERT(!fCurMCState->fHasOpen);
293 } 395 }
294 } 396 }
295 397
296 #ifdef SK_DEBUG 398 #ifdef SK_DEBUG
297 void SkMatrixClipStateMgr::validate() { 399 void SkMatrixClipStateMgr::validate() {
298 if (fCurOpenStateID == fCurMCState->fMCStateID && 400 if (fCurOpenStateID == fCurMCState->fMCStateID &&
299 (!fCurMCState->fIsSaveLayer || 401 (!fCurMCState->fIsSaveLayer ||
300 fCurOpenStateID != fCurMCState->fSaveLayerBaseStateID)) { 402 fCurOpenStateID != fCurMCState->fSaveLayerBaseStateID)) {
301 // The current state is the active one so it should have a skip 403 // The current state is the active one so it should have a skip
302 // offset for each clip 404 // offset for each clip
303 SkDeque::Iter iter(fMatrixClipStack, SkDeque::Iter::kBack_IterStart); 405 SkDeque::Iter iter(fMatrixClipStack, SkDeque::Iter::kBack_IterStart);
304 int clipCount = 0; 406 int clipCount = 0;
305 for (const MatrixClipState* state = (const MatrixClipState*) iter.prev() ; 407 for (const MatrixClipState* state = (const MatrixClipState*) iter.prev() ;
306 state != NULL; 408 state != NULL;
307 state = (const MatrixClipState*) iter.prev()) { 409 state = (const MatrixClipState*) iter.prev()) {
308 clipCount += state->fClipInfo->numClips(); 410 if (NULL == state->fPrev || state->fPrev->fClipInfo != state->fClipI nfo) {
309 if (state->fIsSaveLayer) { 411 clipCount += state->fClipInfo->numClips();
310 break; 412 }
311 } 413 if (state->fIsSaveLayer) {
414 break;
415 }
312 } 416 }
313 417
314 SkASSERT(fSkipOffsets->count() == clipCount); 418 SkASSERT(fSkipOffsets->count() == clipCount);
315 } 419 }
316 } 420 }
317 #endif 421 #endif
318 422
319 int SkMatrixClipStateMgr::addRegionToDict(const SkRegion& region) { 423 int SkMatrixClipStateMgr::addRegionToDict(const SkRegion& region) {
320 int index = fRegionDict.count(); 424 int index = fRegionDict.count();
321 *fRegionDict.append() = SkNEW(SkRegion(region)); 425 *fRegionDict.append() = SkNEW(SkRegion(region));
322 return index; 426 return index;
323 } 427 }
324 428
325 int SkMatrixClipStateMgr::addMatToDict(const SkMatrix& mat) { 429 int SkMatrixClipStateMgr::addMatToDict(const SkMatrix& mat) {
326 if (mat.isIdentity()) { 430 if (mat.isIdentity()) {
327 return kIdentityMatID; 431 return kIdentityMatID;
328 } 432 }
329 433
330 *fMatrixDict.append() = mat; 434 *fMatrixDict.append() = mat;
331 return fMatrixDict.count()-1; 435 return fMatrixDict.count()-1;
332 } 436 }
OLDNEW
« no previous file with comments | « src/core/SkMatrixClipStateMgr.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698