gfx/skia/trunk/src/core/SkMatrixClipStateMgr.cpp

changeset 0
6474c204b198
     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 +}

mercurial