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

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

     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  */
     8 #include "SkMatrixClipStateMgr.h"
     9 #include "SkPictureRecord.h"
    11 bool SkMatrixClipStateMgr::MatrixClipState::ClipInfo::clipPath(SkPictureRecord* picRecord,
    12                                                                const SkPath& path,
    13                                                                SkRegion::Op op,
    14                                                                bool doAA,
    15                                                                int matrixID) {
    16     int pathID = picRecord->addPathToHeap(path);
    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 }
    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 }
    40 void SkMatrixClipStateMgr::writeDeltaMat(int currentMatID, int desiredMatID) {
    41     const SkMatrix& current = this->lookupMat(currentMatID);
    42     const SkMatrix& desired = this->lookupMat(desiredMatID);
    44     SkMatrix delta;
    45     bool result = current.invert(&delta);
    46     if (result) {
    47         delta.preConcat(desired);
    48     }
    49     fPicRecord->recordConcat(delta);
    50 }
    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                                                                 SkMatrixClipStateMgr* mgr) {
    56     for (int i = 0; i < fClips.count(); ++i) {
    57         ClipOp& curClip = fClips[i];
    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;
    72         int offset = 0;
    74         switch (curClip.fClipType) {
    75         case kRect_ClipType:
    76             offset = mgr->getPicRecord()->recordClipRect(curClip.fGeom.fRRect.rect(),
    77                                                          curClip.fOp, curClip.fDoAA);
    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         }
    96         mgr->addClipOffset(offset);
    97     }
    98 }
   100 SkMatrixClipStateMgr::SkMatrixClipStateMgr()
   101     : fPicRecord(NULL)
   102     , fMatrixClipStack(sizeof(MatrixClipState),
   103                        fMatrixClipStackStorage,
   104                        sizeof(fMatrixClipStackStorage))
   105     , fCurOpenStateID(kIdentityWideOpenStateID) {
   107     fSkipOffsets = SkNEW(SkTDArray<int>);
   109     // The first slot in the matrix dictionary is reserved for the identity matrix
   110     fMatrixDict.append()->reset();
   112     fCurMCState = (MatrixClipState*)fMatrixClipStack.push_back();
   113     new (fCurMCState) MatrixClipState(NULL, 0);    // balanced in restore()
   115 #ifdef SK_DEBUG
   116     fActualDepth = 0;
   117 #endif
   118 }
   120 SkMatrixClipStateMgr::~SkMatrixClipStateMgr() {
   121     for (int i = 0; i < fRegionDict.count(); ++i) {
   122         SkDELETE(fRegionDict[i]);
   123     }
   125     SkDELETE(fSkipOffsets);
   126 }
   129 int SkMatrixClipStateMgr::MCStackPush(SkCanvas::SaveFlags flags) {
   130     MatrixClipState* newTop = (MatrixClipState*)fMatrixClipStack.push_back();
   131     new (newTop) MatrixClipState(fCurMCState, flags); // balanced in restore()
   132     fCurMCState = newTop;
   134     SkDEBUGCODE(this->validate();)
   136     return fMatrixClipStack.count();
   137 }
   139 int SkMatrixClipStateMgr::save(SkCanvas::SaveFlags flags) {
   140     SkDEBUGCODE(this->validate();)
   142     return this->MCStackPush(flags);
   143 }
   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
   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);
   157     int result = this->MCStackPush(flags);
   158     ++fCurMCState->fLayerID;
   159     fCurMCState->fIsSaveLayer = true;
   161 #ifdef SK_DEBUG
   162     if (saved) {
   163         fCurMCState->fExpectedDepth++; // 1 for nesting save
   164     }
   165     fCurMCState->fExpectedDepth++;   // 1 for saveLayer
   166 #endif
   168     *fStateIDStack.append() = fCurOpenStateID;
   169     fCurMCState->fSavedSkipOffsets = fSkipOffsets;
   171     // TODO: recycle these rather then new & deleting them on every saveLayer/
   172     // restore
   173     fSkipOffsets = SkNEW(SkTDArray<int>);
   175     fPicRecord->recordSaveLayer(bounds, paint,
   176                                 (SkCanvas::SaveFlags)(flags| SkCanvas::kMatrixClip_SaveFlag));
   177 #ifdef SK_DEBUG
   178     fActualDepth++;
   179 #endif
   180     return result;
   181 }
   183 void SkMatrixClipStateMgr::restore() {
   184     SkDEBUGCODE(this->validate();)
   186     if (fCurMCState->fIsSaveLayer) {
   187         if (fCurMCState->fHasOpen) {
   188             fCurMCState->fHasOpen = false;
   189             fPicRecord->recordRestore(); // Close the open block inside the saveLayer
   190 #ifdef SK_DEBUG
   191             SkASSERT(fActualDepth > 0);
   192             fActualDepth--;
   193 #endif
   194         } else {
   195             SkASSERT(0 == fSkipOffsets->count());
   196         }
   198         // The saveLayer's don't carry any matrix or clip state in the
   199         // new scheme so make sure the saveLayer's recordRestore doesn't
   200         // try to finalize them (i.e., fill in their skip offsets).
   201         fPicRecord->recordRestore(false); // close of saveLayer
   202 #ifdef SK_DEBUG
   203         SkASSERT(fActualDepth > 0);
   204         fActualDepth--;
   205 #endif
   207         SkASSERT(fStateIDStack.count() >= 1);
   208         fCurOpenStateID = fStateIDStack[fStateIDStack.count()-1];
   209         fStateIDStack.pop();
   211         SkASSERT(0 == fSkipOffsets->count());
   212         SkASSERT(NULL != fCurMCState->fSavedSkipOffsets);
   214         SkDELETE(fSkipOffsets);
   215         fSkipOffsets = fCurMCState->fSavedSkipOffsets;
   216     }
   218     bool prevHadOpen = fCurMCState->fHasOpen;
   219     bool prevWasSaveLayer = fCurMCState->fIsSaveLayer;
   221     fCurMCState->~MatrixClipState();       // balanced in save()
   222     fMatrixClipStack.pop_back();
   223     fCurMCState = (MatrixClipState*)fMatrixClipStack.back();
   225     if (!prevWasSaveLayer) {
   226         fCurMCState->fHasOpen = prevHadOpen;
   227     }
   229     if (fCurMCState->fIsSaveLayer) {
   230         if (0 != fSkipOffsets->count()) {
   231             SkASSERT(fCurMCState->fHasOpen);
   232         }
   233     }
   235     SkDEBUGCODE(this->validate();)
   236 }
   238 // kIdentityWideOpenStateID (0) is reserved for the identity/wide-open clip state
   239 int32_t SkMatrixClipStateMgr::NewMCStateID() {
   240     // TODO: guard against wrap around
   241     // TODO: make uint32_t
   242     static int32_t gMCStateID = kIdentityWideOpenStateID;
   243     ++gMCStateID;
   244     return gMCStateID;
   245 }
   247 bool SkMatrixClipStateMgr::isNestingMCState(int stateID) {
   248     return fStateIDStack.count() > 0 && fStateIDStack[fStateIDStack.count()-1] == fCurOpenStateID;
   249 }
   251 bool SkMatrixClipStateMgr::call(CallType callType) {
   252     SkDEBUGCODE(this->validate();)
   254     if (kMatrix_CallType == callType || kClip_CallType == callType) {
   255         fCurMCState->fMCStateID = NewMCStateID();
   256         SkDEBUGCODE(this->validate();)
   257         return false;
   258     }
   260     SkASSERT(kOther_CallType == callType);
   262     if (fCurMCState->fMCStateID == fCurOpenStateID) {
   263         // Required MC state is already active one - nothing to do
   264         SkDEBUGCODE(this->validate();)
   265         return false;
   266     }
   268     if (kIdentityWideOpenStateID != fCurOpenStateID &&
   269         !this->isNestingMCState(fCurOpenStateID)) {
   270         // Don't write a restore if the open state is one in which a saveLayer
   271         // is nested. The save after the saveLayer's restore will close it.
   272         fPicRecord->recordRestore();    // Close the open block
   273         fCurMCState->fHasOpen = false;
   274 #ifdef SK_DEBUG
   275         SkASSERT(fActualDepth > 0);
   276         fActualDepth--;
   277 #endif
   278     }
   280     // Install the required MC state as the active one
   281     fCurOpenStateID = fCurMCState->fMCStateID;
   283     if (kIdentityWideOpenStateID == fCurOpenStateID) {
   284         SkASSERT(0 == fActualDepth);
   285         SkASSERT(!fCurMCState->fHasOpen);
   286         SkASSERT(0 == fSkipOffsets->count());
   287         return false;
   288     }
   290     SkASSERT(!fCurMCState->fHasOpen);
   291     SkASSERT(0 == fSkipOffsets->count());
   292     fCurMCState->fHasOpen = true;
   293     fPicRecord->recordSave(SkCanvas::kMatrixClip_SaveFlag);
   294 #ifdef SK_DEBUG
   295     fActualDepth++;
   296     SkASSERT(fActualDepth == fCurMCState->fExpectedDepth);
   297 #endif
   299     // write out clips
   300     SkDeque::Iter iter(fMatrixClipStack, SkDeque::Iter::kBack_IterStart);
   301     const MatrixClipState* state;
   302     // Loop back across the MC states until the last saveLayer. The MC
   303     // state in front of the saveLayer has already been written out.
   304     for (state = (const MatrixClipState*) iter.prev();
   305          state != NULL;
   306          state = (const MatrixClipState*) iter.prev()) {
   307         if (state->fIsSaveLayer) {
   308             break;
   309         }
   310     }
   312     int curMatID;
   314     if (NULL == state) {
   315         // There was no saveLayer in the MC stack so we need to output them all
   316         iter.reset(fMatrixClipStack, SkDeque::Iter::kFront_IterStart);
   317         state = (const MatrixClipState*) iter.next();
   318         curMatID = kIdentityMatID;
   319     } else {
   320         // SkDeque's iterators actually return the previous location so we
   321         // need to reverse and go forward one to get back on track.
   322         iter.next();
   323         SkDEBUGCODE(const MatrixClipState* test = (const MatrixClipState*)) iter.next();
   324         SkASSERT(test == state);
   326         curMatID = state->fMatrixInfo->getID(this);
   328         // TODO: this assumes that, in the case of Save|SaveLayer when the SaveLayer
   329         // doesn't save the clip, that the SaveLayer doesn't add any additional clip state.
   330         // This assumption will be removed when we explicitly store the clip state in
   331         // self-contained objects. It is valid for the small set of skps.
   332         if (NULL != state->fPrev && state->fClipInfo == state->fPrev->fClipInfo) {
   333             // By the above assumption the SaveLayer's MC state has already been
   334             // written out by the prior Save so don't output it again.
   335             state = (const MatrixClipState*) iter.next();
   336         }
   337     }
   339     for ( ; state != NULL; state = (const MatrixClipState*) iter.next()) {
   340          state->fClipInfo->writeClip(&curMatID, this);
   341     }
   343     // write out matrix
   344     // TODO: this test isn't quite right. It should be:
   345     //   if (curMatID != fCurMCState->fMatrixInfo->getID(this)) {
   346     // but right now the testing harness always expects a matrix if
   347     // the matrices are non-I
   348     if (kIdentityMatID != fCurMCState->fMatrixInfo->getID(this)) {
   349         // TODO: writing out the delta matrix here is an artifact of the writing
   350         // out of the entire clip stack (with its matrices). Ultimately we will
   351         // write out the CTM here when the clip state is collapsed to a single path.
   352         this->writeDeltaMat(curMatID, fCurMCState->fMatrixInfo->getID(this));
   353     }
   355     SkDEBUGCODE(this->validate();)
   356     return true;
   357 }
   359 // Fill in the skip offsets for all the clips written in the current block
   360 void SkMatrixClipStateMgr::fillInSkips(SkWriter32* writer, int32_t restoreOffset) {
   361     for (int i = 0; i < fSkipOffsets->count(); ++i) {
   362         SkDEBUGCODE(int32_t peek = writer->readTAt<int32_t>((*fSkipOffsets)[i]);)
   363         SkASSERT(-1 == peek);
   364         writer->overwriteTAt<int32_t>((*fSkipOffsets)[i], restoreOffset);
   365     }
   367     fSkipOffsets->rewind();
   368     SkASSERT(0 == fSkipOffsets->count());
   369 }
   371 void SkMatrixClipStateMgr::finish() {
   372     if (kIdentityWideOpenStateID != fCurOpenStateID) {
   373         fPicRecord->recordRestore();    // Close the open block
   374         fCurMCState->fHasOpen = false;
   375 #ifdef SK_DEBUG
   376         SkASSERT(fActualDepth > 0);
   377         fActualDepth--;
   378 #endif
   379         fCurOpenStateID = kIdentityWideOpenStateID;
   380         SkASSERT(!fCurMCState->fHasOpen);
   381     }
   382 }
   384 #ifdef SK_DEBUG
   385 void SkMatrixClipStateMgr::validate() {
   386     if (fCurOpenStateID == fCurMCState->fMCStateID && !this->isNestingMCState(fCurOpenStateID)) {
   387         // The current state is the active one so it should have a skip
   388         // offset for each clip
   389         SkDeque::Iter iter(fMatrixClipStack, SkDeque::Iter::kBack_IterStart);
   390         int clipCount = 0;
   391         for (const MatrixClipState* state = (const MatrixClipState*) iter.prev();
   392              state != NULL;
   393              state = (const MatrixClipState*) iter.prev()) {
   394             if (NULL == state->fPrev || state->fPrev->fClipInfo != state->fClipInfo) {
   395                 clipCount += state->fClipInfo->numClips();
   396             }
   397             if (state->fIsSaveLayer) {
   398                 break;
   399             }
   400         }
   402         SkASSERT(fSkipOffsets->count() == clipCount);
   403     }
   404 }
   405 #endif
   407 int SkMatrixClipStateMgr::addRegionToDict(const SkRegion& region) {
   408     int index = fRegionDict.count();
   409     *fRegionDict.append() = SkNEW(SkRegion(region));
   410     return index;
   411 }
   413 int SkMatrixClipStateMgr::addMatToDict(const SkMatrix& mat) {
   414     if (mat.isIdentity()) {
   415         return kIdentityMatID;
   416     }
   418     *fMatrixDict.append() = mat;
   419     return fMatrixDict.count()-1;
   420 }

mercurial