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; | |
bsalomon
2014/02/12 14:52:47
Should we use a hash here or does matrix deduping
mtklein
2014/02/12 14:54:47
We stopped deduping matrices seen during recording
robertphillips
2014/02/12 15:05:39
Once this is more functional I will check the stat
| |
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 |