OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 #ifndef SkMatrixClipStateMgr_DEFINED | 7 #ifndef SkMatrixClipStateMgr_DEFINED |
8 #define SkMatrixClipStateMgr_DEFINED | 8 #define SkMatrixClipStateMgr_DEFINED |
9 | 9 |
10 #include "SkCanvas.h" | 10 #include "SkCanvas.h" |
11 #include "SkMatrix.h" | 11 #include "SkMatrix.h" |
12 #include "SkRegion.h" | 12 #include "SkRegion.h" |
13 #include "SkRRect.h" | 13 #include "SkRRect.h" |
14 #include "SkTypes.h" | 14 #include "SkTypes.h" |
15 #include "SkTArray.h" | 15 #include "SkTArray.h" |
| 16 #include "SkTDArray.h" |
16 | 17 |
17 class SkPictureRecord; | 18 class SkPictureRecord; |
18 class SkWriter32; | 19 class SkWriter32; |
19 | 20 |
20 // The SkMatrixClipStateMgr collapses the matrix/clip state of an SkPicture into | 21 // 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 // a series of save/restore blocks of consistent matrix clip state, e.g.: |
22 // | 23 // |
23 // save | 24 // save |
24 // clip(s) | 25 // clip(s) |
25 // concat | 26 // concat |
(...skipping 18 matching lines...) Expand all Loading... |
44 // As a side effect of this process all saves and saveLayers will become | 45 // As a side effect of this process all saves and saveLayers will become |
45 // kMatrixClip_SaveFlag style saves/saveLayers. | 46 // kMatrixClip_SaveFlag style saves/saveLayers. |
46 | 47 |
47 // The SkMatrixClipStateMgr works by intercepting all the save*, restore, clip*, | 48 // 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 // 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 // state. All the other canvas calls get funnelled into a generic "call" entry |
50 // point that signals that a state block is required. | 51 // point that signals that a state block is required. |
51 class SkMatrixClipStateMgr { | 52 class SkMatrixClipStateMgr { |
52 public: | 53 public: |
53 static const int32_t kIdentityWideOpenStateID = 0; | 54 static const int32_t kIdentityWideOpenStateID = 0; |
| 55 static const int kIdentityMatID = 0; |
54 | 56 |
55 class MatrixClipState { | 57 class MatrixClipState { |
56 public: | 58 public: |
57 class MatrixInfo { | 59 class MatrixInfo { |
58 public: | 60 public: |
| 61 void reset() { |
| 62 fMatrixID = kIdentityMatID; |
| 63 fMatrix.reset(); |
| 64 } |
| 65 |
| 66 bool preTranslate(SkScalar dx, SkScalar dy) { |
| 67 fMatrixID = -1; |
| 68 return fMatrix.preTranslate(dx, dy); |
| 69 } |
| 70 |
| 71 bool preScale(SkScalar sx, SkScalar sy) { |
| 72 fMatrixID = -1; |
| 73 return fMatrix.preScale(sx, sy); |
| 74 } |
| 75 |
| 76 bool preRotate(SkScalar degrees) { |
| 77 fMatrixID = -1; |
| 78 return fMatrix.preRotate(degrees); |
| 79 } |
| 80 |
| 81 bool preSkew(SkScalar sx, SkScalar sy) { |
| 82 fMatrixID = -1; |
| 83 return fMatrix.preSkew(sx, sy); |
| 84 } |
| 85 |
| 86 bool preConcat(const SkMatrix& matrix) { |
| 87 fMatrixID = -1; |
| 88 return fMatrix.preConcat(matrix); |
| 89 } |
| 90 |
| 91 void setMatrix(const SkMatrix& matrix) { |
| 92 fMatrixID = -1; |
| 93 fMatrix = matrix; |
| 94 } |
| 95 |
| 96 int getID(SkMatrixClipStateMgr* mgr) { |
| 97 if (fMatrixID >= 0) { |
| 98 return fMatrixID; |
| 99 } |
| 100 |
| 101 fMatrixID = mgr->addMatToDict(fMatrix); |
| 102 return fMatrixID; |
| 103 } |
| 104 |
| 105 private: |
59 SkMatrix fMatrix; | 106 SkMatrix fMatrix; |
60 // TODO: add an internal dictionary and an ID here | 107 int fMatrixID; |
61 }; | 108 }; |
62 | 109 |
63 class ClipInfo : public SkNoncopyable { | 110 class ClipInfo : public SkNoncopyable { |
64 public: | 111 public: |
65 ClipInfo() {} | 112 ClipInfo() {} |
66 | 113 |
67 bool clipRect(const SkRect& rect, | 114 bool clipRect(const SkRect& rect, |
68 SkRegion::Op op, | 115 SkRegion::Op op, |
69 bool doAA, | 116 bool doAA, |
70 const SkMatrix& matrix) { | 117 int matrixID) { |
71 ClipOp& newClip = fClips.push_back(); | 118 ClipOp& newClip = fClips.push_back(); |
72 newClip.fClipType = kRect_ClipType; | 119 newClip.fClipType = kRect_ClipType; |
73 newClip.fGeom.fRRect.setRect(rect); // storing the clipRect in
the RRect | 120 newClip.fGeom.fRRect.setRect(rect); // storing the clipRect in
the RRect |
74 newClip.fOp = op; | 121 newClip.fOp = op; |
75 newClip.fDoAA = doAA; | 122 newClip.fDoAA = doAA; |
76 newClip.fMatrix = matrix; | 123 newClip.fMatrixID = matrixID; |
77 newClip.fOffset = kInvalidJumpOffset; | 124 newClip.fOffset = kInvalidJumpOffset; |
78 return false; | 125 return false; |
79 } | 126 } |
80 | 127 |
81 bool clipRRect(const SkRRect& rrect, | 128 bool clipRRect(const SkRRect& rrect, |
82 SkRegion::Op op, | 129 SkRegion::Op op, |
83 bool doAA, | 130 bool doAA, |
84 const SkMatrix& matrix) { | 131 int matrixID) { |
85 ClipOp& newClip = fClips.push_back(); | 132 ClipOp& newClip = fClips.push_back(); |
86 newClip.fClipType = kRRect_ClipType; | 133 newClip.fClipType = kRRect_ClipType; |
87 newClip.fGeom.fRRect = rrect; | 134 newClip.fGeom.fRRect = rrect; |
88 newClip.fOp = op; | 135 newClip.fOp = op; |
89 newClip.fDoAA = doAA; | 136 newClip.fDoAA = doAA; |
90 newClip.fMatrix = matrix; | 137 newClip.fMatrixID = matrixID; |
91 newClip.fOffset = kInvalidJumpOffset; | 138 newClip.fOffset = kInvalidJumpOffset; |
92 return false; | 139 return false; |
93 } | 140 } |
94 | 141 |
95 bool clipPath(SkPictureRecord* picRecord, | 142 bool clipPath(SkPictureRecord* picRecord, |
96 const SkPath& path, | 143 const SkPath& path, |
97 SkRegion::Op op, | 144 SkRegion::Op op, |
98 bool doAA, | 145 bool doAA, |
99 const SkMatrix& matrix); | 146 int matrixID); |
100 bool clipRegion(SkPictureRecord* picRecord, | 147 bool clipRegion(SkPictureRecord* picRecord, |
101 const SkRegion& region, | 148 const SkRegion& region, |
102 SkRegion::Op op, | 149 SkRegion::Op op, |
103 const SkMatrix& matrix); | 150 int matrixID); |
104 void writeClip(SkMatrix* curMat, | 151 void writeClip(int* curMatID, |
105 SkPictureRecord* picRecord, | 152 SkMatrixClipStateMgr* mgr, |
106 bool* overrideFirstOp); | 153 bool* overrideFirstOp); |
107 void fillInSkips(SkWriter32* writer, int32_t restoreOffset); | 154 void fillInSkips(SkWriter32* writer, int32_t restoreOffset); |
108 | 155 |
109 #ifdef SK_DEBUG | 156 #ifdef SK_DEBUG |
110 void checkOffsetNotEqual(int32_t offset) { | 157 void checkOffsetNotEqual(int32_t offset) { |
111 for (int i = 0; i < fClips.count(); ++i) { | 158 for (int i = 0; i < fClips.count(); ++i) { |
112 ClipOp& curClip = fClips[i]; | 159 ClipOp& curClip = fClips[i]; |
113 SkASSERT(offset != curClip.fOffset); | 160 SkASSERT(offset != curClip.fOffset); |
114 } | 161 } |
115 } | 162 } |
(...skipping 25 matching lines...) Expand all Loading... |
141 // TODO: add internal dictionary of regions | 188 // TODO: add internal dictionary of regions |
142 // This parameter forces us to have a dtor and thus use | 189 // This parameter forces us to have a dtor and thus use |
143 // SkTArray rather then SkTDArray! | 190 // SkTArray rather then SkTDArray! |
144 const SkRegion* fRegion; | 191 const SkRegion* fRegion; |
145 } fGeom; | 192 } fGeom; |
146 | 193 |
147 bool fDoAA; | 194 bool fDoAA; |
148 SkRegion::Op fOp; | 195 SkRegion::Op fOp; |
149 | 196 |
150 // The CTM in effect when this clip call was issued | 197 // The CTM in effect when this clip call was issued |
151 // TODO: add an internal dictionary and replace with ID | 198 int fMatrixID; |
152 SkMatrix fMatrix; | |
153 | 199 |
154 // The offset of this clipOp's "jump-to-offset" location in the
skp. | 200 // The offset of this clipOp's "jump-to-offset" location in the
skp. |
155 // -1 means the offset hasn't been written. | 201 // -1 means the offset hasn't been written. |
156 int32_t fOffset; | 202 int32_t fOffset; |
157 }; | 203 }; |
158 | 204 |
159 SkTArray<ClipOp> fClips; | 205 SkTArray<ClipOp> fClips; |
160 | 206 |
161 typedef SkNoncopyable INHERITED; | 207 typedef SkNoncopyable INHERITED; |
162 }; | 208 }; |
163 | 209 |
164 MatrixClipState(MatrixClipState* prev, int flags) | 210 MatrixClipState(MatrixClipState* prev, int flags) |
165 #ifdef SK_DEBUG | 211 #ifdef SK_DEBUG |
166 : fPrev(prev) | 212 : fPrev(prev) |
167 #endif | 213 #endif |
168 { | 214 { |
169 if (NULL == prev) { | 215 if (NULL == prev) { |
170 fLayerID = 0; | 216 fLayerID = 0; |
171 | 217 |
172 fMatrixInfoStorage.fMatrix.reset(); | 218 fMatrixInfoStorage.reset(); |
173 fMatrixInfo = &fMatrixInfoStorage; | 219 fMatrixInfo = &fMatrixInfoStorage; |
174 fClipInfo = &fClipInfoStorage; // ctor handles init of fClipInf
oStorage | 220 fClipInfo = &fClipInfoStorage; // ctor handles init of fClipInf
oStorage |
175 | 221 |
176 // The identity/wide-open-clip state is current by default | 222 // The identity/wide-open-clip state is current by default |
177 fMCStateID = kIdentityWideOpenStateID; | 223 fMCStateID = kIdentityWideOpenStateID; |
178 } | 224 } |
179 else { | 225 else { |
180 fLayerID = prev->fLayerID; | 226 fLayerID = prev->fLayerID; |
181 | 227 |
182 if (flags & SkCanvas::kMatrix_SaveFlag) { | 228 if (flags & SkCanvas::kMatrix_SaveFlag) { |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
230 }; | 276 }; |
231 | 277 |
232 SkMatrixClipStateMgr(); | 278 SkMatrixClipStateMgr(); |
233 | 279 |
234 void init(SkPictureRecord* picRecord) { | 280 void init(SkPictureRecord* picRecord) { |
235 // Note: we're not taking a ref here. It is expected that the SkMatrixCl
ipStateMgr | 281 // Note: we're not taking a ref here. It is expected that the SkMatrixCl
ipStateMgr |
236 // is owned by the SkPictureRecord object | 282 // is owned by the SkPictureRecord object |
237 fPicRecord = picRecord; | 283 fPicRecord = picRecord; |
238 } | 284 } |
239 | 285 |
| 286 SkPictureRecord* getPicRecord() { return fPicRecord; } |
| 287 |
240 // TODO: need to override canvas' getSaveCount. Right now we pass the | 288 // TODO: need to override canvas' getSaveCount. Right now we pass the |
241 // save* and restore calls on to the base SkCanvas in SkPictureRecord but | 289 // save* and restore calls on to the base SkCanvas in SkPictureRecord but |
242 // this duplicates effort. | 290 // this duplicates effort. |
243 int getSaveCount() const { return fMatrixClipStack.count(); } | 291 int getSaveCount() const { return fMatrixClipStack.count(); } |
244 | 292 |
245 int save(SkCanvas::SaveFlags flags); | 293 int save(SkCanvas::SaveFlags flags); |
246 | 294 |
247 int saveLayer(const SkRect* bounds, const SkPaint* paint, SkCanvas::SaveFlag
s flags); | 295 int saveLayer(const SkRect* bounds, const SkPaint* paint, SkCanvas::SaveFlag
s flags); |
248 | 296 |
249 bool isDrawingToLayer() const { | 297 bool isDrawingToLayer() const { |
250 return fCurMCState->fLayerID > 0; | 298 return fCurMCState->fLayerID > 0; |
251 } | 299 } |
252 | 300 |
253 void restore(); | 301 void restore(); |
254 | 302 |
255 bool translate(SkScalar dx, SkScalar dy) { | 303 bool translate(SkScalar dx, SkScalar dy) { |
256 this->call(kMatrix_CallType); | 304 this->call(kMatrix_CallType); |
257 return fCurMCState->fMatrixInfo->fMatrix.preTranslate(dx, dy); | 305 return fCurMCState->fMatrixInfo->preTranslate(dx, dy); |
258 } | 306 } |
259 | 307 |
260 bool scale(SkScalar sx, SkScalar sy) { | 308 bool scale(SkScalar sx, SkScalar sy) { |
261 this->call(kMatrix_CallType); | 309 this->call(kMatrix_CallType); |
262 return fCurMCState->fMatrixInfo->fMatrix.preScale(sx, sy); | 310 return fCurMCState->fMatrixInfo->preScale(sx, sy); |
263 } | 311 } |
264 | 312 |
265 bool rotate(SkScalar degrees) { | 313 bool rotate(SkScalar degrees) { |
266 this->call(kMatrix_CallType); | 314 this->call(kMatrix_CallType); |
267 return fCurMCState->fMatrixInfo->fMatrix.preRotate(degrees); | 315 return fCurMCState->fMatrixInfo->preRotate(degrees); |
268 } | 316 } |
269 | 317 |
270 bool skew(SkScalar sx, SkScalar sy) { | 318 bool skew(SkScalar sx, SkScalar sy) { |
271 this->call(kMatrix_CallType); | 319 this->call(kMatrix_CallType); |
272 return fCurMCState->fMatrixInfo->fMatrix.preSkew(sx, sy); | 320 return fCurMCState->fMatrixInfo->preSkew(sx, sy); |
273 } | 321 } |
274 | 322 |
275 bool concat(const SkMatrix& matrix) { | 323 bool concat(const SkMatrix& matrix) { |
276 this->call(kMatrix_CallType); | 324 this->call(kMatrix_CallType); |
277 return fCurMCState->fMatrixInfo->fMatrix.preConcat(matrix); | 325 return fCurMCState->fMatrixInfo->preConcat(matrix); |
278 } | 326 } |
279 | 327 |
280 void setMatrix(const SkMatrix& matrix) { | 328 void setMatrix(const SkMatrix& matrix) { |
281 this->call(kMatrix_CallType); | 329 this->call(kMatrix_CallType); |
282 fCurMCState->fMatrixInfo->fMatrix = matrix; | 330 fCurMCState->fMatrixInfo->setMatrix(matrix); |
283 } | 331 } |
284 | 332 |
285 bool clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { | 333 bool clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { |
286 this->call(SkMatrixClipStateMgr::kClip_CallType); | 334 this->call(SkMatrixClipStateMgr::kClip_CallType); |
287 return fCurMCState->fClipInfo->clipRect(rect, op, doAA, | 335 return fCurMCState->fClipInfo->clipRect(rect, op, doAA, |
288 fCurMCState->fMatrixInfo->fMatri
x); | 336 fCurMCState->fMatrixInfo->getID(
this)); |
289 } | 337 } |
290 | 338 |
291 bool clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { | 339 bool clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { |
292 this->call(SkMatrixClipStateMgr::kClip_CallType); | 340 this->call(SkMatrixClipStateMgr::kClip_CallType); |
293 return fCurMCState->fClipInfo->clipRRect(rrect, op, doAA, | 341 return fCurMCState->fClipInfo->clipRRect(rrect, op, doAA, |
294 fCurMCState->fMatrixInfo->fMatr
ix); | 342 fCurMCState->fMatrixInfo->getID
(this)); |
295 } | 343 } |
296 | 344 |
297 bool clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { | 345 bool clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { |
298 this->call(SkMatrixClipStateMgr::kClip_CallType); | 346 this->call(SkMatrixClipStateMgr::kClip_CallType); |
299 return fCurMCState->fClipInfo->clipPath(fPicRecord, path, op, doAA, | 347 return fCurMCState->fClipInfo->clipPath(fPicRecord, path, op, doAA, |
300 fCurMCState->fMatrixInfo->fMatri
x); | 348 fCurMCState->fMatrixInfo->getID(
this)); |
301 } | 349 } |
302 | 350 |
303 bool clipRegion(const SkRegion& region, SkRegion::Op op) { | 351 bool clipRegion(const SkRegion& region, SkRegion::Op op) { |
304 this->call(SkMatrixClipStateMgr::kClip_CallType); | 352 this->call(SkMatrixClipStateMgr::kClip_CallType); |
305 return fCurMCState->fClipInfo->clipRegion(fPicRecord, region, op, | 353 return fCurMCState->fClipInfo->clipRegion(fPicRecord, region, op, |
306 fCurMCState->fMatrixInfo->fMat
rix); | 354 fCurMCState->fMatrixInfo->getI
D(this)); |
307 } | 355 } |
308 | 356 |
309 bool call(CallType callType); | 357 bool call(CallType callType); |
310 | 358 |
311 void fillInSkips(SkWriter32* writer, int32_t restoreOffset) { | 359 void fillInSkips(SkWriter32* writer, int32_t restoreOffset) { |
312 // Since we write out the entire clip stack at each block start we | 360 // 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. | 361 // need to update the skips for the entire stack each time too. |
314 SkDeque::F2BIter iter(fMatrixClipStack); | 362 SkDeque::F2BIter iter(fMatrixClipStack); |
315 | 363 |
316 for (const MatrixClipState* state = (const MatrixClipState*) iter.next()
; | 364 for (const MatrixClipState* state = (const MatrixClipState*) iter.next()
; |
317 state != NULL; | 365 state != NULL; |
318 state = (const MatrixClipState*) iter.next()) { | 366 state = (const MatrixClipState*) iter.next()) { |
319 state->fClipInfo->fillInSkips(writer, restoreOffset); | 367 state->fClipInfo->fillInSkips(writer, restoreOffset); |
320 } | 368 } |
321 } | 369 } |
322 | 370 |
323 void finish(); | 371 void finish(); |
324 | 372 |
325 protected: | 373 protected: |
326 SkPictureRecord* fPicRecord; | 374 SkPictureRecord* fPicRecord; |
327 | 375 |
328 uint32_t fMatrixClipStackStorage[43]; // sized to fit 2 clip states | 376 uint32_t fMatrixClipStackStorage[43]; // sized to fit 2 clip states |
329 SkDeque fMatrixClipStack; | 377 SkDeque fMatrixClipStack; |
330 MatrixClipState* fCurMCState; | 378 MatrixClipState* fCurMCState; |
331 | 379 |
| 380 // This dictionary doesn't actually de-duplicate the matrices (except for th
e |
| 381 // identity matrix). It merely stores the matrices and allows them to be loo
ked |
| 382 // up by ID later. The de-duplication mainly falls upon the matrix/clip stac
k |
| 383 // which stores the ID so a revisited clip/matrix (via popping the stack) wi
ll |
| 384 // use the same ID. |
| 385 SkTDArray<SkMatrix> fMatrixDict; |
| 386 |
332 // The MCStateID of the state currently in effect in the byte stream. 0 if n
one. | 387 // The MCStateID of the state currently in effect in the byte stream. 0 if n
one. |
333 int32_t fCurOpenStateID; | 388 int32_t fCurOpenStateID; |
334 | 389 |
335 SkDEBUGCODE(void validate();) | 390 SkDEBUGCODE(void validate();) |
336 | 391 |
337 static void WriteDeltaMat(SkPictureRecord* picRecord, | 392 void writeDeltaMat(int currentMatID, int desiredMatID); |
338 const SkMatrix& current, | |
339 const SkMatrix& desired); | |
340 static int32_t NewMCStateID(); | 393 static int32_t NewMCStateID(); |
| 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 } |
341 }; | 402 }; |
342 | 403 |
343 #endif | 404 #endif |
OLD | NEW |