| 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 "SkMatrixClipStateMgr.h" | |
| 9 #include "SkPictureRecord.h" | |
| 10 | |
| 11 bool SkMatrixClipStateMgr::MatrixClipState::ClipInfo::clipPath(SkPictureRecord*
picRecord, | |
| 12 const SkPath& pat
h, | |
| 13 SkRegion::Op op, | |
| 14 bool doAA, | |
| 15 int matrixID) { | |
| 16 int pathID = picRecord->addPathToHeap(path); | |
| 17 | |
| 18 ClipOp* newClip = fClips.append(); | |
| 19 newClip->fClipType = kPath_ClipType; | |
| 20 newClip->fGeom.fPathID = pathID; | |
| 21 newClip->fOp = op; | |
| 22 newClip->fDoAA = doAA; | |
| 23 newClip->fMatrixID = matrixID; | |
| 24 return false; | |
| 25 } | |
| 26 | |
| 27 bool SkMatrixClipStateMgr::MatrixClipState::ClipInfo::clipRegion(SkPictureRecord
* picRecord, | |
| 28 int regionID, | |
| 29 SkRegion::Op op
, | |
| 30 int matrixID) { | |
| 31 ClipOp* newClip = fClips.append(); | |
| 32 newClip->fClipType = kRegion_ClipType; | |
| 33 newClip->fGeom.fRegionID = regionID; | |
| 34 newClip->fOp = op; | |
| 35 newClip->fDoAA = true; // not necessary but sanity preserving | |
| 36 newClip->fMatrixID = matrixID; | |
| 37 return false; | |
| 38 } | |
| 39 | |
| 40 void SkMatrixClipStateMgr::writeDeltaMat(int currentMatID, int desiredMatID) { | |
| 41 const SkMatrix& current = this->lookupMat(currentMatID); | |
| 42 const SkMatrix& desired = this->lookupMat(desiredMatID); | |
| 43 | |
| 44 SkMatrix delta; | |
| 45 bool result = current.invert(&delta); | |
| 46 if (result) { | |
| 47 delta.preConcat(desired); | |
| 48 } | |
| 49 fPicRecord->recordConcat(delta); | |
| 50 } | |
| 51 | |
| 52 // Note: this only writes out the clips for the current save state. To get the | |
| 53 // entire clip stack requires iterating of the entire matrix/clip stack. | |
| 54 void SkMatrixClipStateMgr::MatrixClipState::ClipInfo::writeClip(int* curMatID, | |
| 55 SkMatrixClipStat
eMgr* mgr) { | |
| 56 for (int i = 0; i < fClips.count(); ++i) { | |
| 57 ClipOp& curClip = fClips[i]; | |
| 58 | |
| 59 // TODO: use the matrix ID to skip writing the identity matrix | |
| 60 // over and over, i.e.: | |
| 61 // if (*curMatID != curClip.fMatrixID) { | |
| 62 // mgr->writeDeltaMat... | |
| 63 // *curMatID... | |
| 64 // } | |
| 65 // Right now this optimization would throw off the testing harness. | |
| 66 // TODO: right now we're writing out the delta matrix from the prior | |
| 67 // matrix state. This is a side-effect of writing out the entire | |
| 68 // clip stack and should be resolved when that is fixed. | |
| 69 mgr->writeDeltaMat(*curMatID, curClip.fMatrixID); | |
| 70 *curMatID = curClip.fMatrixID; | |
| 71 | |
| 72 size_t offset = 0; | |
| 73 | |
| 74 switch (curClip.fClipType) { | |
| 75 case kRect_ClipType: | |
| 76 offset = mgr->getPicRecord()->recordClipRect(curClip.fGeom.fRRect.re
ct(), | |
| 77 curClip.fOp, curClip.fD
oAA); | |
| 78 break; | |
| 79 case kRRect_ClipType: | |
| 80 offset = mgr->getPicRecord()->recordClipRRect(curClip.fGeom.fRRect,
curClip.fOp, | |
| 81 curClip.fDoAA); | |
| 82 break; | |
| 83 case kPath_ClipType: | |
| 84 offset = mgr->getPicRecord()->recordClipPath(curClip.fGeom.fPathID,
curClip.fOp, | |
| 85 curClip.fDoAA); | |
| 86 break; | |
| 87 case kRegion_ClipType: { | |
| 88 const SkRegion* region = mgr->lookupRegion(curClip.fGeom.fRegionID); | |
| 89 offset = mgr->getPicRecord()->recordClipRegion(*region, curClip.fOp)
; | |
| 90 break; | |
| 91 } | |
| 92 default: | |
| 93 SkASSERT(0); | |
| 94 } | |
| 95 | |
| 96 mgr->addClipOffset(offset); | |
| 97 } | |
| 98 } | |
| 99 | |
| 100 SkMatrixClipStateMgr::SkMatrixClipStateMgr() | |
| 101 : fPicRecord(NULL) | |
| 102 , fMatrixClipStack(sizeof(MatrixClipState), | |
| 103 fMatrixClipStackStorage, | |
| 104 sizeof(fMatrixClipStackStorage)) | |
| 105 , fCurOpenStateID(kIdentityWideOpenStateID) { | |
| 106 | |
| 107 fSkipOffsets = SkNEW(SkTDArray<int>); | |
| 108 | |
| 109 // The first slot in the matrix dictionary is reserved for the identity matr
ix | |
| 110 fMatrixDict.append()->reset(); | |
| 111 | |
| 112 fCurMCState = (MatrixClipState*)fMatrixClipStack.push_back(); | |
| 113 new (fCurMCState) MatrixClipState(NULL); // balanced in restore() | |
| 114 | |
| 115 #ifdef SK_DEBUG | |
| 116 fActualDepth = 0; | |
| 117 #endif | |
| 118 } | |
| 119 | |
| 120 SkMatrixClipStateMgr::~SkMatrixClipStateMgr() { | |
| 121 for (int i = 0; i < fRegionDict.count(); ++i) { | |
| 122 SkDELETE(fRegionDict[i]); | |
| 123 } | |
| 124 | |
| 125 SkDELETE(fSkipOffsets); | |
| 126 } | |
| 127 | |
| 128 | |
| 129 int SkMatrixClipStateMgr::MCStackPush() { | |
| 130 MatrixClipState* newTop = (MatrixClipState*)fMatrixClipStack.push_back(); | |
| 131 new (newTop) MatrixClipState(fCurMCState); // balanced in restore() | |
| 132 fCurMCState = newTop; | |
| 133 | |
| 134 SkDEBUGCODE(this->validate();) | |
| 135 | |
| 136 return fMatrixClipStack.count(); | |
| 137 } | |
| 138 | |
| 139 int SkMatrixClipStateMgr::save() { | |
| 140 SkDEBUGCODE(this->validate();) | |
| 141 | |
| 142 return this->MCStackPush(); | |
| 143 } | |
| 144 | |
| 145 int SkMatrixClipStateMgr::saveLayer(const SkRect* bounds, const SkPaint* paint, | |
| 146 SkCanvas::SaveFlags flags) { | |
| 147 #ifdef SK_DEBUG | |
| 148 if (fCurMCState->fIsSaveLayer) { | |
| 149 SkASSERT(0 == fSkipOffsets->count()); | |
| 150 } | |
| 151 #endif | |
| 152 | |
| 153 // Since the saveLayer call draws something we need to potentially dump | |
| 154 // out the MC state | |
| 155 SkDEBUGCODE(bool saved =) this->call(kOther_CallType); | |
| 156 | |
| 157 int result = this->MCStackPush(); | |
| 158 ++fCurMCState->fLayerID; | |
| 159 fCurMCState->fIsSaveLayer = true; | |
| 160 | |
| 161 #ifdef SK_DEBUG | |
| 162 if (saved) { | |
| 163 fCurMCState->fExpectedDepth++; // 1 for nesting save | |
| 164 } | |
| 165 fCurMCState->fExpectedDepth++; // 1 for saveLayer | |
| 166 #endif | |
| 167 | |
| 168 *fStateIDStack.append() = fCurOpenStateID; | |
| 169 fCurMCState->fSavedSkipOffsets = fSkipOffsets; | |
| 170 | |
| 171 // TODO: recycle these rather then new & deleting them on every saveLayer/ | |
| 172 // restore | |
| 173 fSkipOffsets = SkNEW(SkTDArray<int>); | |
| 174 | |
| 175 fPicRecord->recordSaveLayer(bounds, paint, flags); | |
| 176 #ifdef SK_DEBUG | |
| 177 fActualDepth++; | |
| 178 #endif | |
| 179 return result; | |
| 180 } | |
| 181 | |
| 182 void SkMatrixClipStateMgr::restore() { | |
| 183 SkDEBUGCODE(this->validate();) | |
| 184 | |
| 185 if (fCurMCState->fIsSaveLayer) { | |
| 186 if (fCurMCState->fHasOpen) { | |
| 187 fCurMCState->fHasOpen = false; | |
| 188 fPicRecord->recordRestore(); // Close the open block inside the save
Layer | |
| 189 #ifdef SK_DEBUG | |
| 190 SkASSERT(fActualDepth > 0); | |
| 191 fActualDepth--; | |
| 192 #endif | |
| 193 } else { | |
| 194 SkASSERT(0 == fSkipOffsets->count()); | |
| 195 } | |
| 196 | |
| 197 // The saveLayer's don't carry any matrix or clip state in the | |
| 198 // new scheme so make sure the saveLayer's recordRestore doesn't | |
| 199 // try to finalize them (i.e., fill in their skip offsets). | |
| 200 fPicRecord->recordRestore(false); // close of saveLayer | |
| 201 #ifdef SK_DEBUG | |
| 202 SkASSERT(fActualDepth > 0); | |
| 203 fActualDepth--; | |
| 204 #endif | |
| 205 | |
| 206 SkASSERT(fStateIDStack.count() >= 1); | |
| 207 fCurOpenStateID = fStateIDStack[fStateIDStack.count()-1]; | |
| 208 fStateIDStack.pop(); | |
| 209 | |
| 210 SkASSERT(0 == fSkipOffsets->count()); | |
| 211 SkASSERT(NULL != fCurMCState->fSavedSkipOffsets); | |
| 212 | |
| 213 SkDELETE(fSkipOffsets); | |
| 214 fSkipOffsets = fCurMCState->fSavedSkipOffsets; | |
| 215 } | |
| 216 | |
| 217 bool prevHadOpen = fCurMCState->fHasOpen; | |
| 218 bool prevWasSaveLayer = fCurMCState->fIsSaveLayer; | |
| 219 | |
| 220 fCurMCState->~MatrixClipState(); // balanced in save() | |
| 221 fMatrixClipStack.pop_back(); | |
| 222 fCurMCState = (MatrixClipState*)fMatrixClipStack.back(); | |
| 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 | |
| 234 SkDEBUGCODE(this->validate();) | |
| 235 } | |
| 236 | |
| 237 // kIdentityWideOpenStateID (0) is reserved for the identity/wide-open clip stat
e | |
| 238 int32_t SkMatrixClipStateMgr::NewMCStateID() { | |
| 239 // TODO: guard against wrap around | |
| 240 // TODO: make uint32_t | |
| 241 static int32_t gMCStateID = kIdentityWideOpenStateID; | |
| 242 ++gMCStateID; | |
| 243 return gMCStateID; | |
| 244 } | |
| 245 | |
| 246 bool SkMatrixClipStateMgr::isNestingMCState(int stateID) { | |
| 247 return fStateIDStack.count() > 0 && fStateIDStack[fStateIDStack.count()-1] =
= fCurOpenStateID; | |
| 248 } | |
| 249 | |
| 250 bool SkMatrixClipStateMgr::call(CallType callType) { | |
| 251 SkDEBUGCODE(this->validate();) | |
| 252 | |
| 253 if (kMatrix_CallType == callType || kClip_CallType == callType) { | |
| 254 fCurMCState->fMCStateID = NewMCStateID(); | |
| 255 SkDEBUGCODE(this->validate();) | |
| 256 return false; | |
| 257 } | |
| 258 | |
| 259 SkASSERT(kOther_CallType == callType); | |
| 260 | |
| 261 if (fCurMCState->fMCStateID == fCurOpenStateID) { | |
| 262 // Required MC state is already active one - nothing to do | |
| 263 SkDEBUGCODE(this->validate();) | |
| 264 return false; | |
| 265 } | |
| 266 | |
| 267 if (kIdentityWideOpenStateID != fCurOpenStateID && | |
| 268 !this->isNestingMCState(fCurOpenStateID)) { | |
| 269 // Don't write a restore if the open state is one in which a saveLayer | |
| 270 // is nested. The save after the saveLayer's restore will close it. | |
| 271 fPicRecord->recordRestore(); // Close the open block | |
| 272 fCurMCState->fHasOpen = false; | |
| 273 #ifdef SK_DEBUG | |
| 274 SkASSERT(fActualDepth > 0); | |
| 275 fActualDepth--; | |
| 276 #endif | |
| 277 } | |
| 278 | |
| 279 // Install the required MC state as the active one | |
| 280 fCurOpenStateID = fCurMCState->fMCStateID; | |
| 281 | |
| 282 if (kIdentityWideOpenStateID == fCurOpenStateID) { | |
| 283 SkASSERT(0 == fActualDepth); | |
| 284 SkASSERT(!fCurMCState->fHasOpen); | |
| 285 SkASSERT(0 == fSkipOffsets->count()); | |
| 286 return false; | |
| 287 } | |
| 288 | |
| 289 SkASSERT(!fCurMCState->fHasOpen); | |
| 290 SkASSERT(0 == fSkipOffsets->count()); | |
| 291 fCurMCState->fHasOpen = true; | |
| 292 fPicRecord->recordSave(); | |
| 293 #ifdef SK_DEBUG | |
| 294 fActualDepth++; | |
| 295 SkASSERT(fActualDepth == fCurMCState->fExpectedDepth); | |
| 296 #endif | |
| 297 | |
| 298 // write out clips | |
| 299 SkDeque::Iter iter(fMatrixClipStack, SkDeque::Iter::kBack_IterStart); | |
| 300 const MatrixClipState* state; | |
| 301 // Loop back across the MC states until the last saveLayer. The MC | |
| 302 // state in front of the saveLayer has already been written out. | |
| 303 for (state = (const MatrixClipState*) iter.prev(); | |
| 304 state != NULL; | |
| 305 state = (const MatrixClipState*) iter.prev()) { | |
| 306 if (state->fIsSaveLayer) { | |
| 307 break; | |
| 308 } | |
| 309 } | |
| 310 | |
| 311 int curMatID; | |
| 312 | |
| 313 if (NULL == state) { | |
| 314 // There was no saveLayer in the MC stack so we need to output them all | |
| 315 iter.reset(fMatrixClipStack, SkDeque::Iter::kFront_IterStart); | |
| 316 state = (const MatrixClipState*) iter.next(); | |
| 317 curMatID = kIdentityMatID; | |
| 318 } else { | |
| 319 // SkDeque's iterators actually return the previous location so we | |
| 320 // need to reverse and go forward one to get back on track. | |
| 321 iter.next(); | |
| 322 SkDEBUGCODE(const MatrixClipState* test = (const MatrixClipState*)) iter
.next(); | |
| 323 SkASSERT(test == state); | |
| 324 | |
| 325 curMatID = state->fMatrixInfo->getID(this); | |
| 326 | |
| 327 // TODO: this assumes that, in the case of Save|SaveLayer when the SaveL
ayer | |
| 328 // doesn't save the clip, that the SaveLayer doesn't add any additional
clip state. | |
| 329 // This assumption will be removed when we explicitly store the clip sta
te in | |
| 330 // self-contained objects. It is valid for the small set of skps. | |
| 331 if (NULL != state->fPrev && state->fClipInfo == state->fPrev->fClipInfo)
{ | |
| 332 // By the above assumption the SaveLayer's MC state has already been | |
| 333 // written out by the prior Save so don't output it again. | |
| 334 state = (const MatrixClipState*) iter.next(); | |
| 335 } | |
| 336 } | |
| 337 | |
| 338 for ( ; state != NULL; state = (const MatrixClipState*) iter.next()) { | |
| 339 state->fClipInfo->writeClip(&curMatID, this); | |
| 340 } | |
| 341 | |
| 342 // write out matrix | |
| 343 // TODO: this test isn't quite right. It should be: | |
| 344 // if (curMatID != fCurMCState->fMatrixInfo->getID(this)) { | |
| 345 // but right now the testing harness always expects a matrix if | |
| 346 // the matrices are non-I | |
| 347 if (kIdentityMatID != fCurMCState->fMatrixInfo->getID(this)) { | |
| 348 // TODO: writing out the delta matrix here is an artifact of the writing | |
| 349 // out of the entire clip stack (with its matrices). Ultimately we will | |
| 350 // write out the CTM here when the clip state is collapsed to a single p
ath. | |
| 351 this->writeDeltaMat(curMatID, fCurMCState->fMatrixInfo->getID(this)); | |
| 352 } | |
| 353 | |
| 354 SkDEBUGCODE(this->validate();) | |
| 355 return true; | |
| 356 } | |
| 357 | |
| 358 // Fill in the skip offsets for all the clips written in the current block | |
| 359 void SkMatrixClipStateMgr::fillInSkips(SkWriter32* writer, int32_t restoreOffset
) { | |
| 360 for (int i = 0; i < fSkipOffsets->count(); ++i) { | |
| 361 SkDEBUGCODE(int32_t peek = writer->readTAt<int32_t>((*fSkipOffsets)[i]);
) | |
| 362 SkASSERT(-1 == peek); | |
| 363 writer->overwriteTAt<int32_t>((*fSkipOffsets)[i], restoreOffset); | |
| 364 } | |
| 365 | |
| 366 fSkipOffsets->rewind(); | |
| 367 SkASSERT(0 == fSkipOffsets->count()); | |
| 368 } | |
| 369 | |
| 370 void SkMatrixClipStateMgr::finish() { | |
| 371 if (kIdentityWideOpenStateID != fCurOpenStateID) { | |
| 372 fPicRecord->recordRestore(); // Close the open block | |
| 373 fCurMCState->fHasOpen = false; | |
| 374 #ifdef SK_DEBUG | |
| 375 SkASSERT(fActualDepth > 0); | |
| 376 fActualDepth--; | |
| 377 #endif | |
| 378 fCurOpenStateID = kIdentityWideOpenStateID; | |
| 379 SkASSERT(!fCurMCState->fHasOpen); | |
| 380 } | |
| 381 } | |
| 382 | |
| 383 #ifdef SK_DEBUG | |
| 384 void SkMatrixClipStateMgr::validate() { | |
| 385 if (fCurOpenStateID == fCurMCState->fMCStateID && !this->isNestingMCState(fC
urOpenStateID)) { | |
| 386 // The current state is the active one so it should have a skip | |
| 387 // offset for each clip | |
| 388 SkDeque::Iter iter(fMatrixClipStack, SkDeque::Iter::kBack_IterStart); | |
| 389 int clipCount = 0; | |
| 390 for (const MatrixClipState* state = (const MatrixClipState*) iter.prev()
; | |
| 391 state != NULL; | |
| 392 state = (const MatrixClipState*) iter.prev()) { | |
| 393 if (NULL == state->fPrev || state->fPrev->fClipInfo != state->fClipI
nfo) { | |
| 394 clipCount += state->fClipInfo->numClips(); | |
| 395 } | |
| 396 if (state->fIsSaveLayer) { | |
| 397 break; | |
| 398 } | |
| 399 } | |
| 400 | |
| 401 SkASSERT(fSkipOffsets->count() == clipCount); | |
| 402 } | |
| 403 } | |
| 404 #endif | |
| 405 | |
| 406 int SkMatrixClipStateMgr::addRegionToDict(const SkRegion& region) { | |
| 407 int index = fRegionDict.count(); | |
| 408 *fRegionDict.append() = SkNEW(SkRegion(region)); | |
| 409 return index; | |
| 410 } | |
| 411 | |
| 412 int SkMatrixClipStateMgr::addMatToDict(const SkMatrix& mat) { | |
| 413 if (mat.isIdentity()) { | |
| 414 return kIdentityMatID; | |
| 415 } | |
| 416 | |
| 417 *fMatrixDict.append() = mat; | |
| 418 return fMatrixDict.count()-1; | |
| 419 } | |
| OLD | NEW |