Home | History | Annotate | Download | only in core
      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 #ifndef SkMatrixClipStateMgr_DEFINED
      8 #define SkMatrixClipStateMgr_DEFINED
      9 
     10 #include "SkCanvas.h"
     11 #include "SkMatrix.h"
     12 #include "SkRegion.h"
     13 #include "SkRRect.h"
     14 #include "SkTypes.h"
     15 #include "SkTDArray.h"
     16 
     17 class SkPictureRecord;
     18 class SkWriter32;
     19 
     20 // The SkMatrixClipStateMgr collapses the matrix/clip state of an SkPicture into
     21 // a series of save/restore blocks of consistent matrix clip state, e.g.:
     22 //
     23 //   save
     24 //     clip(s)
     25 //     concat
     26 //     ... draw ops ...
     27 //   restore
     28 //
     29 // SaveLayers simply add another level, e.g.:
     30 //
     31 //   save
     32 //     clip(s)
     33 //     concat
     34 //     ... draw ops ...
     35 //     saveLayer
     36 //       save
     37 //         clip(s)
     38 //         concat
     39 //         ... draw ops ...
     40 //       restore
     41 //     restore
     42 //   restore
     43 //
     44 // As a side effect of this process all saves and saveLayers will become
     45 // kMatrixClip_SaveFlag style saves/saveLayers.
     46 
     47 // The SkMatrixClipStateMgr works by intercepting all the save*, restore, clip*,
     48 // and matrix calls sent to SkCanvas in order to track the current matrix/clip
     49 // state. All the other canvas calls get funnelled into a generic "call" entry
     50 // point that signals that a state block is required.
     51 class SkMatrixClipStateMgr {
     52 public:
     53     static const int32_t kIdentityWideOpenStateID = 0;
     54     static const int kIdentityMatID = 0;
     55 
     56     class MatrixClipState : SkNoncopyable {
     57     public:
     58         class MatrixInfo {
     59         public:
     60             void reset() {
     61                 fMatrixID = kIdentityMatID;
     62                 fMatrix.reset();
     63             }
     64 
     65             void preTranslate(SkScalar dx, SkScalar dy) {
     66                 fMatrixID = -1;
     67                 fMatrix.preTranslate(dx, dy);
     68             }
     69 
     70             void preScale(SkScalar sx, SkScalar sy) {
     71                 fMatrixID = -1;
     72                 fMatrix.preScale(sx, sy);
     73             }
     74 
     75             void preRotate(SkScalar degrees) {
     76                 fMatrixID = -1;
     77                 fMatrix.preRotate(degrees);
     78             }
     79 
     80             void preSkew(SkScalar sx, SkScalar sy) {
     81                 fMatrixID = -1;
     82                 fMatrix.preSkew(sx, sy);
     83             }
     84 
     85             void preConcat(const SkMatrix& matrix) {
     86                 fMatrixID = -1;
     87                 fMatrix.preConcat(matrix);
     88             }
     89 
     90             void setMatrix(const SkMatrix& matrix) {
     91                 fMatrixID = -1;
     92                 fMatrix = matrix;
     93             }
     94 
     95             int getID(SkMatrixClipStateMgr* mgr) {
     96                 if (fMatrixID >= 0) {
     97                     return fMatrixID;
     98                 }
     99 
    100                 fMatrixID = mgr->addMatToDict(fMatrix);
    101                 return fMatrixID;
    102             }
    103 
    104         private:
    105             SkMatrix fMatrix;
    106             int      fMatrixID;
    107 
    108             typedef SkNoncopyable INHERITED;
    109         };
    110 
    111         class ClipInfo : SkNoncopyable {
    112         public:
    113             ClipInfo() {}
    114 
    115             bool clipRect(const SkRect& rect,
    116                           SkRegion::Op op,
    117                           bool doAA,
    118                           int matrixID) {
    119                 ClipOp* newClip = fClips.append();
    120                 newClip->fClipType = kRect_ClipType;
    121                 newClip->fGeom.fRRect.setRect(rect);   // storing the clipRect in the RRect
    122                 newClip->fOp = op;
    123                 newClip->fDoAA = doAA;
    124                 newClip->fMatrixID = matrixID;
    125                 return false;
    126             }
    127 
    128             bool clipRRect(const SkRRect& rrect,
    129                            SkRegion::Op op,
    130                            bool doAA,
    131                            int matrixID) {
    132                 ClipOp* newClip = fClips.append();
    133                 newClip->fClipType = kRRect_ClipType;
    134                 newClip->fGeom.fRRect = rrect;
    135                 newClip->fOp = op;
    136                 newClip->fDoAA = doAA;
    137                 newClip->fMatrixID = matrixID;
    138                 return false;
    139             }
    140 
    141             bool clipPath(SkPictureRecord* picRecord,
    142                           const SkPath& path,
    143                           SkRegion::Op op,
    144                           bool doAA,
    145                           int matrixID);
    146             bool clipRegion(SkPictureRecord* picRecord,
    147                             int regionID,
    148                             SkRegion::Op op,
    149                             int matrixID);
    150             void writeClip(int* curMatID, SkMatrixClipStateMgr* mgr);
    151 
    152             SkDEBUGCODE(int numClips() const { return fClips.count(); })
    153 
    154         private:
    155             enum ClipType {
    156                 kRect_ClipType,
    157                 kRRect_ClipType,
    158                 kPath_ClipType,
    159                 kRegion_ClipType
    160             };
    161 
    162             class ClipOp {
    163             public:
    164                 ClipType     fClipType;
    165 
    166                 union {
    167                     SkRRect fRRect;        // also stores clip rect
    168                     int     fPathID;
    169                     int     fRegionID;
    170                 } fGeom;
    171 
    172                 bool         fDoAA;
    173                 SkRegion::Op fOp;
    174 
    175                 // The CTM in effect when this clip call was issued
    176                 int          fMatrixID;
    177             };
    178 
    179             SkTDArray<ClipOp> fClips;
    180 
    181             typedef SkNoncopyable INHERITED;
    182         };
    183 
    184         MatrixClipState(MatrixClipState* prev, int flags)
    185             : fPrev(prev)
    186         {
    187             fHasOpen = false;
    188 
    189             if (NULL == prev) {
    190                 fLayerID = 0;
    191 
    192                 fMatrixInfoStorage.reset();
    193                 fMatrixInfo = &fMatrixInfoStorage;
    194                 fClipInfo = &fClipInfoStorage;  // ctor handles init of fClipInfoStorage
    195 
    196                 // The identity/wide-open-clip state is current by default
    197                 fMCStateID = kIdentityWideOpenStateID;
    198 #ifdef SK_DEBUG
    199                 fExpectedDepth = 1;
    200 #endif
    201             }
    202             else {
    203                 fLayerID = prev->fLayerID;
    204 
    205                 if (flags & SkCanvas::kMatrix_SaveFlag) {
    206                     fMatrixInfoStorage = *prev->fMatrixInfo;
    207                     fMatrixInfo = &fMatrixInfoStorage;
    208                 } else {
    209                     fMatrixInfo = prev->fMatrixInfo;
    210                 }
    211 
    212                 if (flags & SkCanvas::kClip_SaveFlag) {
    213                     // We don't copy the ClipOps of the previous clip states
    214                     fClipInfo = &fClipInfoStorage;
    215                 } else {
    216                     fClipInfo = prev->fClipInfo;
    217                 }
    218 
    219                 // Initially a new save/saveLayer represents the same MC state
    220                 // as its predecessor.
    221                 fMCStateID = prev->fMCStateID;
    222 #ifdef SK_DEBUG
    223                 fExpectedDepth = prev->fExpectedDepth;
    224 #endif
    225             }
    226 
    227             fIsSaveLayer = false;
    228         }
    229 
    230         MatrixInfo*  fMatrixInfo;
    231         MatrixInfo   fMatrixInfoStorage;
    232 
    233         ClipInfo*    fClipInfo;
    234         ClipInfo     fClipInfoStorage;
    235 
    236         // Tracks the current depth of saveLayers to support the isDrawingToLayer call
    237         int          fLayerID;
    238         // Does this MC state represent a saveLayer call?
    239         bool         fIsSaveLayer;
    240 
    241         // The next field is only valid when fIsSaveLayer is set.
    242         SkTDArray<int>* fSavedSkipOffsets;
    243 
    244         // Does the MC state have an open block in the skp?
    245         bool         fHasOpen;
    246 
    247         MatrixClipState* fPrev;
    248 
    249 #ifdef SK_DEBUG
    250         int              fExpectedDepth;    // debugging aid
    251 #endif
    252 
    253         int32_t     fMCStateID;
    254     };
    255 
    256     enum CallType {
    257         kMatrix_CallType,
    258         kClip_CallType,
    259         kOther_CallType
    260     };
    261 
    262     SkMatrixClipStateMgr();
    263     ~SkMatrixClipStateMgr();
    264 
    265     void init(SkPictureRecord* picRecord) {
    266         // Note: we're not taking a ref here. It is expected that the SkMatrixClipStateMgr
    267         // is owned by the SkPictureRecord object
    268         fPicRecord = picRecord;
    269     }
    270 
    271     SkPictureRecord* getPicRecord() { return fPicRecord; }
    272 
    273     // TODO: need to override canvas' getSaveCount. Right now we pass the
    274     // save* and restore calls on to the base SkCanvas in SkPictureRecord but
    275     // this duplicates effort.
    276     int getSaveCount() const { return fMatrixClipStack.count(); }
    277 
    278     int save(SkCanvas::SaveFlags flags);
    279 
    280     int saveLayer(const SkRect* bounds, const SkPaint* paint, SkCanvas::SaveFlags flags);
    281 
    282     bool isDrawingToLayer() const {
    283         return fCurMCState->fLayerID > 0;
    284     }
    285 
    286     void restore();
    287 
    288     void translate(SkScalar dx, SkScalar dy) {
    289         this->call(kMatrix_CallType);
    290         fCurMCState->fMatrixInfo->preTranslate(dx, dy);
    291     }
    292 
    293     void scale(SkScalar sx, SkScalar sy) {
    294         this->call(kMatrix_CallType);
    295         fCurMCState->fMatrixInfo->preScale(sx, sy);
    296     }
    297 
    298     void rotate(SkScalar degrees) {
    299         this->call(kMatrix_CallType);
    300         fCurMCState->fMatrixInfo->preRotate(degrees);
    301     }
    302 
    303     void skew(SkScalar sx, SkScalar sy) {
    304         this->call(kMatrix_CallType);
    305         fCurMCState->fMatrixInfo->preSkew(sx, sy);
    306     }
    307 
    308     void concat(const SkMatrix& matrix) {
    309         this->call(kMatrix_CallType);
    310         fCurMCState->fMatrixInfo->preConcat(matrix);
    311     }
    312 
    313     void setMatrix(const SkMatrix& matrix) {
    314         this->call(kMatrix_CallType);
    315         fCurMCState->fMatrixInfo->setMatrix(matrix);
    316     }
    317 
    318     bool clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
    319         this->call(SkMatrixClipStateMgr::kClip_CallType);
    320         return fCurMCState->fClipInfo->clipRect(rect, op, doAA,
    321                                                 fCurMCState->fMatrixInfo->getID(this));
    322     }
    323 
    324     bool clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
    325         this->call(SkMatrixClipStateMgr::kClip_CallType);
    326         return fCurMCState->fClipInfo->clipRRect(rrect, op, doAA,
    327                                                  fCurMCState->fMatrixInfo->getID(this));
    328     }
    329 
    330     bool clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
    331         this->call(SkMatrixClipStateMgr::kClip_CallType);
    332         return fCurMCState->fClipInfo->clipPath(fPicRecord, path, op, doAA,
    333                                                 fCurMCState->fMatrixInfo->getID(this));
    334     }
    335 
    336     bool clipRegion(const SkRegion& region, SkRegion::Op op) {
    337         this->call(SkMatrixClipStateMgr::kClip_CallType);
    338         int regionID = this->addRegionToDict(region);
    339         return fCurMCState->fClipInfo->clipRegion(fPicRecord, regionID, op,
    340                                                   fCurMCState->fMatrixInfo->getID(this));
    341     }
    342 
    343     bool call(CallType callType);
    344 
    345     void fillInSkips(SkWriter32* writer, int32_t restoreOffset);
    346 
    347     void finish();
    348 
    349 protected:
    350     SkPictureRecord* fPicRecord;
    351 
    352     uint32_t         fMatrixClipStackStorage[43]; // sized to fit 2 clip states
    353     SkDeque          fMatrixClipStack;
    354     MatrixClipState* fCurMCState;
    355 
    356     // This dictionary doesn't actually de-duplicate the matrices (except for the
    357     // identity matrix). It merely stores the matrices and allows them to be looked
    358     // up by ID later. The de-duplication mainly falls upon the matrix/clip stack
    359     // which stores the ID so a revisited clip/matrix (via popping the stack) will
    360     // use the same ID.
    361     SkTDArray<SkMatrix> fMatrixDict;
    362 
    363     SkTDArray<SkRegion*> fRegionDict;
    364 
    365     // The MCStateID of the state currently in effect in the byte stream. 0 if none.
    366     int32_t          fCurOpenStateID;
    367     // The skip offsets for the current open state. These are the locations in the
    368     // skp that must be filled in when the current open state is closed. These are
    369     // here rather then distributed across the MatrixClipState's because saveLayers
    370     // can cause MC states to be nested.
    371     SkTDArray<int32_t>  *fSkipOffsets;  // TODO: should we store u32 or size_t instead?
    372 
    373     SkDEBUGCODE(void validate();)
    374 
    375     int MCStackPush(SkCanvas::SaveFlags flags);
    376 
    377     void addClipOffset(size_t offset) {
    378         SkASSERT(NULL != fSkipOffsets);
    379         SkASSERT(kIdentityWideOpenStateID != fCurOpenStateID);
    380         SkASSERT(fCurMCState->fHasOpen);
    381         SkASSERT(!fCurMCState->fIsSaveLayer);
    382 
    383         *fSkipOffsets->append() = SkToS32(offset);
    384     }
    385 
    386     void writeDeltaMat(int currentMatID, int desiredMatID);
    387     static int32_t   NewMCStateID();
    388 
    389     int addRegionToDict(const SkRegion& region);
    390     const SkRegion* lookupRegion(int index) {
    391         SkASSERT(index >= 0 && index < fRegionDict.count());
    392         return fRegionDict[index];
    393     }
    394 
    395     // TODO: add stats to check if the dictionary really does
    396     // reduce the size of the SkPicture.
    397     int addMatToDict(const SkMatrix& mat);
    398     const SkMatrix& lookupMat(int index) {
    399         SkASSERT(index >= 0 && index < fMatrixDict.count());
    400         return fMatrixDict[index];
    401     }
    402 
    403     bool isNestingMCState(int stateID);
    404 
    405 #ifdef SK_DEBUG
    406     int fActualDepth;
    407 #endif
    408 
    409     // save layers are nested within a specific MC state. This stack tracks
    410     // the nesting MC state's ID as save layers are pushed and popped.
    411     SkTDArray<int> fStateIDStack;
    412 };
    413 
    414 #endif
    415