1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/core/SkMatrixClipStateMgr.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,420 @@ 1.4 +/* 1.5 + * Copyright 2014 Google Inc. 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license that can be 1.8 + * found in the LICENSE file. 1.9 + */ 1.10 + 1.11 +#include "SkMatrixClipStateMgr.h" 1.12 +#include "SkPictureRecord.h" 1.13 + 1.14 +bool SkMatrixClipStateMgr::MatrixClipState::ClipInfo::clipPath(SkPictureRecord* picRecord, 1.15 + const SkPath& path, 1.16 + SkRegion::Op op, 1.17 + bool doAA, 1.18 + int matrixID) { 1.19 + int pathID = picRecord->addPathToHeap(path); 1.20 + 1.21 + ClipOp* newClip = fClips.append(); 1.22 + newClip->fClipType = kPath_ClipType; 1.23 + newClip->fGeom.fPathID = pathID; 1.24 + newClip->fOp = op; 1.25 + newClip->fDoAA = doAA; 1.26 + newClip->fMatrixID = matrixID; 1.27 + return false; 1.28 +} 1.29 + 1.30 +bool SkMatrixClipStateMgr::MatrixClipState::ClipInfo::clipRegion(SkPictureRecord* picRecord, 1.31 + int regionID, 1.32 + SkRegion::Op op, 1.33 + int matrixID) { 1.34 + ClipOp* newClip = fClips.append(); 1.35 + newClip->fClipType = kRegion_ClipType; 1.36 + newClip->fGeom.fRegionID = regionID; 1.37 + newClip->fOp = op; 1.38 + newClip->fDoAA = true; // not necessary but sanity preserving 1.39 + newClip->fMatrixID = matrixID; 1.40 + return false; 1.41 +} 1.42 + 1.43 +void SkMatrixClipStateMgr::writeDeltaMat(int currentMatID, int desiredMatID) { 1.44 + const SkMatrix& current = this->lookupMat(currentMatID); 1.45 + const SkMatrix& desired = this->lookupMat(desiredMatID); 1.46 + 1.47 + SkMatrix delta; 1.48 + bool result = current.invert(&delta); 1.49 + if (result) { 1.50 + delta.preConcat(desired); 1.51 + } 1.52 + fPicRecord->recordConcat(delta); 1.53 +} 1.54 + 1.55 +// Note: this only writes out the clips for the current save state. To get the 1.56 +// entire clip stack requires iterating of the entire matrix/clip stack. 1.57 +void SkMatrixClipStateMgr::MatrixClipState::ClipInfo::writeClip(int* curMatID, 1.58 + SkMatrixClipStateMgr* mgr) { 1.59 + for (int i = 0; i < fClips.count(); ++i) { 1.60 + ClipOp& curClip = fClips[i]; 1.61 + 1.62 + // TODO: use the matrix ID to skip writing the identity matrix 1.63 + // over and over, i.e.: 1.64 + // if (*curMatID != curClip.fMatrixID) { 1.65 + // mgr->writeDeltaMat... 1.66 + // *curMatID... 1.67 + // } 1.68 + // Right now this optimization would throw off the testing harness. 1.69 + // TODO: right now we're writing out the delta matrix from the prior 1.70 + // matrix state. This is a side-effect of writing out the entire 1.71 + // clip stack and should be resolved when that is fixed. 1.72 + mgr->writeDeltaMat(*curMatID, curClip.fMatrixID); 1.73 + *curMatID = curClip.fMatrixID; 1.74 + 1.75 + int offset = 0; 1.76 + 1.77 + switch (curClip.fClipType) { 1.78 + case kRect_ClipType: 1.79 + offset = mgr->getPicRecord()->recordClipRect(curClip.fGeom.fRRect.rect(), 1.80 + curClip.fOp, curClip.fDoAA); 1.81 + break; 1.82 + case kRRect_ClipType: 1.83 + offset = mgr->getPicRecord()->recordClipRRect(curClip.fGeom.fRRect, curClip.fOp, 1.84 + curClip.fDoAA); 1.85 + break; 1.86 + case kPath_ClipType: 1.87 + offset = mgr->getPicRecord()->recordClipPath(curClip.fGeom.fPathID, curClip.fOp, 1.88 + curClip.fDoAA); 1.89 + break; 1.90 + case kRegion_ClipType: { 1.91 + const SkRegion* region = mgr->lookupRegion(curClip.fGeom.fRegionID); 1.92 + offset = mgr->getPicRecord()->recordClipRegion(*region, curClip.fOp); 1.93 + break; 1.94 + } 1.95 + default: 1.96 + SkASSERT(0); 1.97 + } 1.98 + 1.99 + mgr->addClipOffset(offset); 1.100 + } 1.101 +} 1.102 + 1.103 +SkMatrixClipStateMgr::SkMatrixClipStateMgr() 1.104 + : fPicRecord(NULL) 1.105 + , fMatrixClipStack(sizeof(MatrixClipState), 1.106 + fMatrixClipStackStorage, 1.107 + sizeof(fMatrixClipStackStorage)) 1.108 + , fCurOpenStateID(kIdentityWideOpenStateID) { 1.109 + 1.110 + fSkipOffsets = SkNEW(SkTDArray<int>); 1.111 + 1.112 + // The first slot in the matrix dictionary is reserved for the identity matrix 1.113 + fMatrixDict.append()->reset(); 1.114 + 1.115 + fCurMCState = (MatrixClipState*)fMatrixClipStack.push_back(); 1.116 + new (fCurMCState) MatrixClipState(NULL, 0); // balanced in restore() 1.117 + 1.118 +#ifdef SK_DEBUG 1.119 + fActualDepth = 0; 1.120 +#endif 1.121 +} 1.122 + 1.123 +SkMatrixClipStateMgr::~SkMatrixClipStateMgr() { 1.124 + for (int i = 0; i < fRegionDict.count(); ++i) { 1.125 + SkDELETE(fRegionDict[i]); 1.126 + } 1.127 + 1.128 + SkDELETE(fSkipOffsets); 1.129 +} 1.130 + 1.131 + 1.132 +int SkMatrixClipStateMgr::MCStackPush(SkCanvas::SaveFlags flags) { 1.133 + MatrixClipState* newTop = (MatrixClipState*)fMatrixClipStack.push_back(); 1.134 + new (newTop) MatrixClipState(fCurMCState, flags); // balanced in restore() 1.135 + fCurMCState = newTop; 1.136 + 1.137 + SkDEBUGCODE(this->validate();) 1.138 + 1.139 + return fMatrixClipStack.count(); 1.140 +} 1.141 + 1.142 +int SkMatrixClipStateMgr::save(SkCanvas::SaveFlags flags) { 1.143 + SkDEBUGCODE(this->validate();) 1.144 + 1.145 + return this->MCStackPush(flags); 1.146 +} 1.147 + 1.148 +int SkMatrixClipStateMgr::saveLayer(const SkRect* bounds, const SkPaint* paint, 1.149 + SkCanvas::SaveFlags flags) { 1.150 +#ifdef SK_DEBUG 1.151 + if (fCurMCState->fIsSaveLayer) { 1.152 + SkASSERT(0 == fSkipOffsets->count()); 1.153 + } 1.154 +#endif 1.155 + 1.156 + // Since the saveLayer call draws something we need to potentially dump 1.157 + // out the MC state 1.158 + SkDEBUGCODE(bool saved =) this->call(kOther_CallType); 1.159 + 1.160 + int result = this->MCStackPush(flags); 1.161 + ++fCurMCState->fLayerID; 1.162 + fCurMCState->fIsSaveLayer = true; 1.163 + 1.164 +#ifdef SK_DEBUG 1.165 + if (saved) { 1.166 + fCurMCState->fExpectedDepth++; // 1 for nesting save 1.167 + } 1.168 + fCurMCState->fExpectedDepth++; // 1 for saveLayer 1.169 +#endif 1.170 + 1.171 + *fStateIDStack.append() = fCurOpenStateID; 1.172 + fCurMCState->fSavedSkipOffsets = fSkipOffsets; 1.173 + 1.174 + // TODO: recycle these rather then new & deleting them on every saveLayer/ 1.175 + // restore 1.176 + fSkipOffsets = SkNEW(SkTDArray<int>); 1.177 + 1.178 + fPicRecord->recordSaveLayer(bounds, paint, 1.179 + (SkCanvas::SaveFlags)(flags| SkCanvas::kMatrixClip_SaveFlag)); 1.180 +#ifdef SK_DEBUG 1.181 + fActualDepth++; 1.182 +#endif 1.183 + return result; 1.184 +} 1.185 + 1.186 +void SkMatrixClipStateMgr::restore() { 1.187 + SkDEBUGCODE(this->validate();) 1.188 + 1.189 + if (fCurMCState->fIsSaveLayer) { 1.190 + if (fCurMCState->fHasOpen) { 1.191 + fCurMCState->fHasOpen = false; 1.192 + fPicRecord->recordRestore(); // Close the open block inside the saveLayer 1.193 +#ifdef SK_DEBUG 1.194 + SkASSERT(fActualDepth > 0); 1.195 + fActualDepth--; 1.196 +#endif 1.197 + } else { 1.198 + SkASSERT(0 == fSkipOffsets->count()); 1.199 + } 1.200 + 1.201 + // The saveLayer's don't carry any matrix or clip state in the 1.202 + // new scheme so make sure the saveLayer's recordRestore doesn't 1.203 + // try to finalize them (i.e., fill in their skip offsets). 1.204 + fPicRecord->recordRestore(false); // close of saveLayer 1.205 +#ifdef SK_DEBUG 1.206 + SkASSERT(fActualDepth > 0); 1.207 + fActualDepth--; 1.208 +#endif 1.209 + 1.210 + SkASSERT(fStateIDStack.count() >= 1); 1.211 + fCurOpenStateID = fStateIDStack[fStateIDStack.count()-1]; 1.212 + fStateIDStack.pop(); 1.213 + 1.214 + SkASSERT(0 == fSkipOffsets->count()); 1.215 + SkASSERT(NULL != fCurMCState->fSavedSkipOffsets); 1.216 + 1.217 + SkDELETE(fSkipOffsets); 1.218 + fSkipOffsets = fCurMCState->fSavedSkipOffsets; 1.219 + } 1.220 + 1.221 + bool prevHadOpen = fCurMCState->fHasOpen; 1.222 + bool prevWasSaveLayer = fCurMCState->fIsSaveLayer; 1.223 + 1.224 + fCurMCState->~MatrixClipState(); // balanced in save() 1.225 + fMatrixClipStack.pop_back(); 1.226 + fCurMCState = (MatrixClipState*)fMatrixClipStack.back(); 1.227 + 1.228 + if (!prevWasSaveLayer) { 1.229 + fCurMCState->fHasOpen = prevHadOpen; 1.230 + } 1.231 + 1.232 + if (fCurMCState->fIsSaveLayer) { 1.233 + if (0 != fSkipOffsets->count()) { 1.234 + SkASSERT(fCurMCState->fHasOpen); 1.235 + } 1.236 + } 1.237 + 1.238 + SkDEBUGCODE(this->validate();) 1.239 +} 1.240 + 1.241 +// kIdentityWideOpenStateID (0) is reserved for the identity/wide-open clip state 1.242 +int32_t SkMatrixClipStateMgr::NewMCStateID() { 1.243 + // TODO: guard against wrap around 1.244 + // TODO: make uint32_t 1.245 + static int32_t gMCStateID = kIdentityWideOpenStateID; 1.246 + ++gMCStateID; 1.247 + return gMCStateID; 1.248 +} 1.249 + 1.250 +bool SkMatrixClipStateMgr::isNestingMCState(int stateID) { 1.251 + return fStateIDStack.count() > 0 && fStateIDStack[fStateIDStack.count()-1] == fCurOpenStateID; 1.252 +} 1.253 + 1.254 +bool SkMatrixClipStateMgr::call(CallType callType) { 1.255 + SkDEBUGCODE(this->validate();) 1.256 + 1.257 + if (kMatrix_CallType == callType || kClip_CallType == callType) { 1.258 + fCurMCState->fMCStateID = NewMCStateID(); 1.259 + SkDEBUGCODE(this->validate();) 1.260 + return false; 1.261 + } 1.262 + 1.263 + SkASSERT(kOther_CallType == callType); 1.264 + 1.265 + if (fCurMCState->fMCStateID == fCurOpenStateID) { 1.266 + // Required MC state is already active one - nothing to do 1.267 + SkDEBUGCODE(this->validate();) 1.268 + return false; 1.269 + } 1.270 + 1.271 + if (kIdentityWideOpenStateID != fCurOpenStateID && 1.272 + !this->isNestingMCState(fCurOpenStateID)) { 1.273 + // Don't write a restore if the open state is one in which a saveLayer 1.274 + // is nested. The save after the saveLayer's restore will close it. 1.275 + fPicRecord->recordRestore(); // Close the open block 1.276 + fCurMCState->fHasOpen = false; 1.277 +#ifdef SK_DEBUG 1.278 + SkASSERT(fActualDepth > 0); 1.279 + fActualDepth--; 1.280 +#endif 1.281 + } 1.282 + 1.283 + // Install the required MC state as the active one 1.284 + fCurOpenStateID = fCurMCState->fMCStateID; 1.285 + 1.286 + if (kIdentityWideOpenStateID == fCurOpenStateID) { 1.287 + SkASSERT(0 == fActualDepth); 1.288 + SkASSERT(!fCurMCState->fHasOpen); 1.289 + SkASSERT(0 == fSkipOffsets->count()); 1.290 + return false; 1.291 + } 1.292 + 1.293 + SkASSERT(!fCurMCState->fHasOpen); 1.294 + SkASSERT(0 == fSkipOffsets->count()); 1.295 + fCurMCState->fHasOpen = true; 1.296 + fPicRecord->recordSave(SkCanvas::kMatrixClip_SaveFlag); 1.297 +#ifdef SK_DEBUG 1.298 + fActualDepth++; 1.299 + SkASSERT(fActualDepth == fCurMCState->fExpectedDepth); 1.300 +#endif 1.301 + 1.302 + // write out clips 1.303 + SkDeque::Iter iter(fMatrixClipStack, SkDeque::Iter::kBack_IterStart); 1.304 + const MatrixClipState* state; 1.305 + // Loop back across the MC states until the last saveLayer. The MC 1.306 + // state in front of the saveLayer has already been written out. 1.307 + for (state = (const MatrixClipState*) iter.prev(); 1.308 + state != NULL; 1.309 + state = (const MatrixClipState*) iter.prev()) { 1.310 + if (state->fIsSaveLayer) { 1.311 + break; 1.312 + } 1.313 + } 1.314 + 1.315 + int curMatID; 1.316 + 1.317 + if (NULL == state) { 1.318 + // There was no saveLayer in the MC stack so we need to output them all 1.319 + iter.reset(fMatrixClipStack, SkDeque::Iter::kFront_IterStart); 1.320 + state = (const MatrixClipState*) iter.next(); 1.321 + curMatID = kIdentityMatID; 1.322 + } else { 1.323 + // SkDeque's iterators actually return the previous location so we 1.324 + // need to reverse and go forward one to get back on track. 1.325 + iter.next(); 1.326 + SkDEBUGCODE(const MatrixClipState* test = (const MatrixClipState*)) iter.next(); 1.327 + SkASSERT(test == state); 1.328 + 1.329 + curMatID = state->fMatrixInfo->getID(this); 1.330 + 1.331 + // TODO: this assumes that, in the case of Save|SaveLayer when the SaveLayer 1.332 + // doesn't save the clip, that the SaveLayer doesn't add any additional clip state. 1.333 + // This assumption will be removed when we explicitly store the clip state in 1.334 + // self-contained objects. It is valid for the small set of skps. 1.335 + if (NULL != state->fPrev && state->fClipInfo == state->fPrev->fClipInfo) { 1.336 + // By the above assumption the SaveLayer's MC state has already been 1.337 + // written out by the prior Save so don't output it again. 1.338 + state = (const MatrixClipState*) iter.next(); 1.339 + } 1.340 + } 1.341 + 1.342 + for ( ; state != NULL; state = (const MatrixClipState*) iter.next()) { 1.343 + state->fClipInfo->writeClip(&curMatID, this); 1.344 + } 1.345 + 1.346 + // write out matrix 1.347 + // TODO: this test isn't quite right. It should be: 1.348 + // if (curMatID != fCurMCState->fMatrixInfo->getID(this)) { 1.349 + // but right now the testing harness always expects a matrix if 1.350 + // the matrices are non-I 1.351 + if (kIdentityMatID != fCurMCState->fMatrixInfo->getID(this)) { 1.352 + // TODO: writing out the delta matrix here is an artifact of the writing 1.353 + // out of the entire clip stack (with its matrices). Ultimately we will 1.354 + // write out the CTM here when the clip state is collapsed to a single path. 1.355 + this->writeDeltaMat(curMatID, fCurMCState->fMatrixInfo->getID(this)); 1.356 + } 1.357 + 1.358 + SkDEBUGCODE(this->validate();) 1.359 + return true; 1.360 +} 1.361 + 1.362 +// Fill in the skip offsets for all the clips written in the current block 1.363 +void SkMatrixClipStateMgr::fillInSkips(SkWriter32* writer, int32_t restoreOffset) { 1.364 + for (int i = 0; i < fSkipOffsets->count(); ++i) { 1.365 + SkDEBUGCODE(int32_t peek = writer->readTAt<int32_t>((*fSkipOffsets)[i]);) 1.366 + SkASSERT(-1 == peek); 1.367 + writer->overwriteTAt<int32_t>((*fSkipOffsets)[i], restoreOffset); 1.368 + } 1.369 + 1.370 + fSkipOffsets->rewind(); 1.371 + SkASSERT(0 == fSkipOffsets->count()); 1.372 +} 1.373 + 1.374 +void SkMatrixClipStateMgr::finish() { 1.375 + if (kIdentityWideOpenStateID != fCurOpenStateID) { 1.376 + fPicRecord->recordRestore(); // Close the open block 1.377 + fCurMCState->fHasOpen = false; 1.378 +#ifdef SK_DEBUG 1.379 + SkASSERT(fActualDepth > 0); 1.380 + fActualDepth--; 1.381 +#endif 1.382 + fCurOpenStateID = kIdentityWideOpenStateID; 1.383 + SkASSERT(!fCurMCState->fHasOpen); 1.384 + } 1.385 +} 1.386 + 1.387 +#ifdef SK_DEBUG 1.388 +void SkMatrixClipStateMgr::validate() { 1.389 + if (fCurOpenStateID == fCurMCState->fMCStateID && !this->isNestingMCState(fCurOpenStateID)) { 1.390 + // The current state is the active one so it should have a skip 1.391 + // offset for each clip 1.392 + SkDeque::Iter iter(fMatrixClipStack, SkDeque::Iter::kBack_IterStart); 1.393 + int clipCount = 0; 1.394 + for (const MatrixClipState* state = (const MatrixClipState*) iter.prev(); 1.395 + state != NULL; 1.396 + state = (const MatrixClipState*) iter.prev()) { 1.397 + if (NULL == state->fPrev || state->fPrev->fClipInfo != state->fClipInfo) { 1.398 + clipCount += state->fClipInfo->numClips(); 1.399 + } 1.400 + if (state->fIsSaveLayer) { 1.401 + break; 1.402 + } 1.403 + } 1.404 + 1.405 + SkASSERT(fSkipOffsets->count() == clipCount); 1.406 + } 1.407 +} 1.408 +#endif 1.409 + 1.410 +int SkMatrixClipStateMgr::addRegionToDict(const SkRegion& region) { 1.411 + int index = fRegionDict.count(); 1.412 + *fRegionDict.append() = SkNEW(SkRegion(region)); 1.413 + return index; 1.414 +} 1.415 + 1.416 +int SkMatrixClipStateMgr::addMatToDict(const SkMatrix& mat) { 1.417 + if (mat.isIdentity()) { 1.418 + return kIdentityMatID; 1.419 + } 1.420 + 1.421 + *fMatrixDict.append() = mat; 1.422 + return fMatrixDict.count()-1; 1.423 +}