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 #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 "SkTArray.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 |
| 55 class MatrixClipState { |
| 56 public: |
| 57 class MatrixInfo { |
| 58 public: |
| 59 SkMatrix fMatrix; |
| 60 // TODO: add an internal dictionary and an ID here |
| 61 }; |
| 62 |
| 63 class ClipInfo : public SkNoncopyable { |
| 64 public: |
| 65 ClipInfo() {} |
| 66 |
| 67 bool clipRect(const SkRect& rect, |
| 68 SkRegion::Op op, |
| 69 bool doAA, |
| 70 const SkMatrix& matrix) { |
| 71 ClipOp& newClip = fClips.push_back(); |
| 72 newClip.fClipType = kRect_ClipType; |
| 73 newClip.fGeom.fRRect.setRect(rect); // storing the clipRect in
the RRect |
| 74 newClip.fOp = op; |
| 75 newClip.fDoAA = doAA; |
| 76 newClip.fMatrix = matrix; |
| 77 newClip.fOffset = kInvalidJumpOffset; |
| 78 return false; |
| 79 } |
| 80 |
| 81 bool clipRRect(const SkRRect& rrect, |
| 82 SkRegion::Op op, |
| 83 bool doAA, |
| 84 const SkMatrix& matrix) { |
| 85 ClipOp& newClip = fClips.push_back(); |
| 86 newClip.fClipType = kRRect_ClipType; |
| 87 newClip.fGeom.fRRect = rrect; |
| 88 newClip.fOp = op; |
| 89 newClip.fDoAA = doAA; |
| 90 newClip.fMatrix = matrix; |
| 91 newClip.fOffset = kInvalidJumpOffset; |
| 92 return false; |
| 93 } |
| 94 |
| 95 bool clipPath(SkPictureRecord* picRecord, |
| 96 const SkPath& path, |
| 97 SkRegion::Op op, |
| 98 bool doAA, |
| 99 const SkMatrix& matrix); |
| 100 bool clipRegion(SkPictureRecord* picRecord, |
| 101 const SkRegion& region, |
| 102 SkRegion::Op op, |
| 103 const SkMatrix& matrix); |
| 104 void writeClip(SkMatrix* curMat, |
| 105 SkPictureRecord* picRecord, |
| 106 bool* overrideFirstOp); |
| 107 void fillInSkips(SkWriter32* writer, int32_t restoreOffset); |
| 108 |
| 109 #ifdef SK_DEBUG |
| 110 void checkOffsetNotEqual(int32_t offset) { |
| 111 for (int i = 0; i < fClips.count(); ++i) { |
| 112 ClipOp& curClip = fClips[i]; |
| 113 SkASSERT(offset != curClip.fOffset); |
| 114 } |
| 115 } |
| 116 #endif |
| 117 private: |
| 118 enum ClipType { |
| 119 kRect_ClipType, |
| 120 kRRect_ClipType, |
| 121 kPath_ClipType, |
| 122 kRegion_ClipType |
| 123 }; |
| 124 |
| 125 static const int kInvalidJumpOffset = -1; |
| 126 |
| 127 class ClipOp { |
| 128 public: |
| 129 ClipOp() {} |
| 130 ~ClipOp() { |
| 131 if (kRegion_ClipType == fClipType) { |
| 132 SkDELETE(fGeom.fRegion); |
| 133 } |
| 134 } |
| 135 |
| 136 ClipType fClipType; |
| 137 |
| 138 union { |
| 139 SkRRect fRRect; // also stores clipRect |
| 140 int fPathID; |
| 141 // TODO: add internal dictionary of regions |
| 142 // This parameter forces us to have a dtor and thus use |
| 143 // SkTArray rather then SkTDArray! |
| 144 const SkRegion* fRegion; |
| 145 } fGeom; |
| 146 |
| 147 bool fDoAA; |
| 148 SkRegion::Op fOp; |
| 149 |
| 150 // The CTM in effect when this clip call was issued |
| 151 // TODO: add an internal dictionary and replace with ID |
| 152 SkMatrix fMatrix; |
| 153 |
| 154 // The offset of this clipOp's "jump-to-offset" location in the
skp. |
| 155 // -1 means the offset hasn't been written. |
| 156 int32_t fOffset; |
| 157 }; |
| 158 |
| 159 SkTArray<ClipOp> fClips; |
| 160 |
| 161 typedef SkNoncopyable INHERITED; |
| 162 }; |
| 163 |
| 164 MatrixClipState(MatrixClipState* prev, int flags) |
| 165 #ifdef SK_DEBUG |
| 166 : fPrev(prev) |
| 167 #endif |
| 168 { |
| 169 if (NULL == prev) { |
| 170 fLayerID = 0; |
| 171 |
| 172 fMatrixInfoStorage.fMatrix.reset(); |
| 173 fMatrixInfo = &fMatrixInfoStorage; |
| 174 fClipInfo = &fClipInfoStorage; // ctor handles init of fClipInf
oStorage |
| 175 |
| 176 // The identity/wide-open-clip state is current by default |
| 177 fMCStateID = kIdentityWideOpenStateID; |
| 178 } |
| 179 else { |
| 180 fLayerID = prev->fLayerID; |
| 181 |
| 182 if (flags & SkCanvas::kMatrix_SaveFlag) { |
| 183 fMatrixInfoStorage = *prev->fMatrixInfo; |
| 184 fMatrixInfo = &fMatrixInfoStorage; |
| 185 } else { |
| 186 fMatrixInfo = prev->fMatrixInfo; |
| 187 } |
| 188 |
| 189 if (flags & SkCanvas::kClip_SaveFlag) { |
| 190 // We don't copy the ClipOps of the previous clip states |
| 191 fClipInfo = &fClipInfoStorage; |
| 192 } else { |
| 193 fClipInfo = prev->fClipInfo; |
| 194 } |
| 195 |
| 196 // Initially a new save/saveLayer represents the same MC state |
| 197 // as its predecessor. |
| 198 fMCStateID = prev->fMCStateID; |
| 199 } |
| 200 |
| 201 fIsSaveLayer = false; |
| 202 } |
| 203 |
| 204 MatrixInfo* fMatrixInfo; |
| 205 MatrixInfo fMatrixInfoStorage; |
| 206 |
| 207 ClipInfo* fClipInfo; |
| 208 ClipInfo fClipInfoStorage; |
| 209 |
| 210 // Tracks the current depth of saveLayers to support the isDrawingToLaye
r call |
| 211 int fLayerID; |
| 212 // Does this MC state represent a saveLayer call? |
| 213 bool fIsSaveLayer; |
| 214 |
| 215 // The next two fields are only valid when fIsSaveLayer is set. |
| 216 int32_t fSaveLayerBaseStateID; |
| 217 bool fSaveLayerBracketed; |
| 218 |
| 219 #ifdef SK_DEBUG |
| 220 MatrixClipState* fPrev; // debugging aid |
| 221 #endif |
| 222 |
| 223 int32_t fMCStateID; |
| 224 }; |
| 225 |
| 226 enum CallType { |
| 227 kMatrix_CallType, |
| 228 kClip_CallType, |
| 229 kOther_CallType |
| 230 }; |
| 231 |
| 232 SkMatrixClipStateMgr(); |
| 233 |
| 234 void init(SkPictureRecord* picRecord) { |
| 235 // Note: we're not taking a ref here. It is expected that the SkMatrixCl
ipStateMgr |
| 236 // is owned by the SkPictureRecord object |
| 237 fPicRecord = picRecord; |
| 238 } |
| 239 |
| 240 // TODO: need to override canvas' getSaveCount. Right now we pass the |
| 241 // save* and restore calls on to the base SkCanvas in SkPictureRecord but |
| 242 // this duplicates effort. |
| 243 int getSaveCount() const { return fMatrixClipStack.count(); } |
| 244 |
| 245 int save(SkCanvas::SaveFlags flags); |
| 246 |
| 247 int saveLayer(const SkRect* bounds, const SkPaint* paint, SkCanvas::SaveFlag
s flags); |
| 248 |
| 249 bool isDrawingToLayer() const { |
| 250 return fCurMCState->fLayerID > 0; |
| 251 } |
| 252 |
| 253 void restore(); |
| 254 |
| 255 bool translate(SkScalar dx, SkScalar dy) { |
| 256 this->call(kMatrix_CallType); |
| 257 return fCurMCState->fMatrixInfo->fMatrix.preTranslate(dx, dy); |
| 258 } |
| 259 |
| 260 bool scale(SkScalar sx, SkScalar sy) { |
| 261 this->call(kMatrix_CallType); |
| 262 return fCurMCState->fMatrixInfo->fMatrix.preScale(sx, sy); |
| 263 } |
| 264 |
| 265 bool rotate(SkScalar degrees) { |
| 266 this->call(kMatrix_CallType); |
| 267 return fCurMCState->fMatrixInfo->fMatrix.preRotate(degrees); |
| 268 } |
| 269 |
| 270 bool skew(SkScalar sx, SkScalar sy) { |
| 271 this->call(kMatrix_CallType); |
| 272 return fCurMCState->fMatrixInfo->fMatrix.preSkew(sx, sy); |
| 273 } |
| 274 |
| 275 bool concat(const SkMatrix& matrix) { |
| 276 this->call(kMatrix_CallType); |
| 277 return fCurMCState->fMatrixInfo->fMatrix.preConcat(matrix); |
| 278 } |
| 279 |
| 280 void setMatrix(const SkMatrix& matrix) { |
| 281 this->call(kMatrix_CallType); |
| 282 fCurMCState->fMatrixInfo->fMatrix = matrix; |
| 283 } |
| 284 |
| 285 bool clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { |
| 286 this->call(SkMatrixClipStateMgr::kClip_CallType); |
| 287 return fCurMCState->fClipInfo->clipRect(rect, op, doAA, |
| 288 fCurMCState->fMatrixInfo->fMatri
x); |
| 289 } |
| 290 |
| 291 bool clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { |
| 292 this->call(SkMatrixClipStateMgr::kClip_CallType); |
| 293 return fCurMCState->fClipInfo->clipRRect(rrect, op, doAA, |
| 294 fCurMCState->fMatrixInfo->fMatr
ix); |
| 295 } |
| 296 |
| 297 bool clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { |
| 298 this->call(SkMatrixClipStateMgr::kClip_CallType); |
| 299 return fCurMCState->fClipInfo->clipPath(fPicRecord, path, op, doAA, |
| 300 fCurMCState->fMatrixInfo->fMatri
x); |
| 301 } |
| 302 |
| 303 bool clipRegion(const SkRegion& region, SkRegion::Op op) { |
| 304 this->call(SkMatrixClipStateMgr::kClip_CallType); |
| 305 return fCurMCState->fClipInfo->clipRegion(fPicRecord, region, op, |
| 306 fCurMCState->fMatrixInfo->fMat
rix); |
| 307 } |
| 308 |
| 309 bool call(CallType callType); |
| 310 |
| 311 void fillInSkips(SkWriter32* writer, int32_t restoreOffset) { |
| 312 // Since we write out the entire clip stack at each block start we |
| 313 // need to update the skips for the entire stack each time too. |
| 314 SkDeque::F2BIter iter(fMatrixClipStack); |
| 315 |
| 316 for (const MatrixClipState* state = (const MatrixClipState*) iter.next()
; |
| 317 state != NULL; |
| 318 state = (const MatrixClipState*) iter.next()) { |
| 319 state->fClipInfo->fillInSkips(writer, restoreOffset); |
| 320 } |
| 321 } |
| 322 |
| 323 void finish(); |
| 324 |
| 325 protected: |
| 326 SkPictureRecord* fPicRecord; |
| 327 |
| 328 uint32_t fMatrixClipStackStorage[43]; // sized to fit 2 clip states |
| 329 SkDeque fMatrixClipStack; |
| 330 MatrixClipState* fCurMCState; |
| 331 |
| 332 // The MCStateID of the state currently in effect in the byte stream. 0 if n
one. |
| 333 int32_t fCurOpenStateID; |
| 334 |
| 335 SkDEBUGCODE(void validate();) |
| 336 |
| 337 static void WriteDeltaMat(SkPictureRecord* picRecord, |
| 338 const SkMatrix& current, |
| 339 const SkMatrix& desired); |
| 340 static int32_t NewMCStateID(); |
| 341 }; |
| 342 |
| 343 #endif |
OLD | NEW |