Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / core / SkMatrixClipStateMgr.cpp
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
8 #include "SkMatrixClipStateMgr.h"
9 #include "SkPictureRecord.h"
10
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);
17
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 }
26
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 }
39
40 void SkMatrixClipStateMgr::writeDeltaMat(int currentMatID, int desiredMatID) {
41     const SkMatrix& current = this->lookupMat(currentMatID);
42     const SkMatrix& desired = this->lookupMat(desiredMatID);
43
44     SkMatrix delta;
45     bool result = current.invert(&delta);
46     if (result) {
47         delta.preConcat(desired);
48     }
49     fPicRecord->recordConcat(delta);
50 }
51
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];
58
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;
71
72         size_t offset = 0;
73
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         }
95
96         mgr->addClipOffset(offset);
97     }
98 }
99
100 SkMatrixClipStateMgr::SkMatrixClipStateMgr()
101     : fPicRecord(NULL)
102     , fMatrixClipStack(sizeof(MatrixClipState),
103                        fMatrixClipStackStorage,
104                        sizeof(fMatrixClipStackStorage))
105     , fCurOpenStateID(kIdentityWideOpenStateID) {
106
107     fSkipOffsets = SkNEW(SkTDArray<int>);
108
109     // The first slot in the matrix dictionary is reserved for the identity matrix
110     fMatrixDict.append()->reset();
111
112     fCurMCState = (MatrixClipState*)fMatrixClipStack.push_back();
113     new (fCurMCState) MatrixClipState(NULL, 0);    // balanced in restore()
114
115 #ifdef SK_DEBUG
116     fActualDepth = 0;
117 #endif
118 }
119
120 SkMatrixClipStateMgr::~SkMatrixClipStateMgr() {
121     for (int i = 0; i < fRegionDict.count(); ++i) {
122         SkDELETE(fRegionDict[i]);
123     }
124
125     SkDELETE(fSkipOffsets);
126 }
127
128
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;
133
134     SkDEBUGCODE(this->validate();)
135
136     return fMatrixClipStack.count();
137 }
138
139 int SkMatrixClipStateMgr::save(SkCanvas::SaveFlags flags) {
140     SkDEBUGCODE(this->validate();)
141
142     return this->MCStackPush(flags);
143 }
144
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
152
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);
156
157     int result = this->MCStackPush(flags);
158     ++fCurMCState->fLayerID;
159     fCurMCState->fIsSaveLayer = true;
160
161 #ifdef SK_DEBUG
162     if (saved) {
163         fCurMCState->fExpectedDepth++; // 1 for nesting save
164     }
165     fCurMCState->fExpectedDepth++;   // 1 for saveLayer
166 #endif
167
168     *fStateIDStack.append() = fCurOpenStateID;
169     fCurMCState->fSavedSkipOffsets = fSkipOffsets;
170
171     // TODO: recycle these rather then new & deleting them on every saveLayer/
172     // restore
173     fSkipOffsets = SkNEW(SkTDArray<int>);
174
175     fPicRecord->recordSaveLayer(bounds, paint,
176                                 (SkCanvas::SaveFlags)(flags| SkCanvas::kMatrixClip_SaveFlag));
177 #ifdef SK_DEBUG
178     fActualDepth++;
179 #endif
180     return result;
181 }
182
183 void SkMatrixClipStateMgr::restore() {
184     SkDEBUGCODE(this->validate();)
185
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         }
197
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
206
207         SkASSERT(fStateIDStack.count() >= 1);
208         fCurOpenStateID = fStateIDStack[fStateIDStack.count()-1];
209         fStateIDStack.pop();
210
211         SkASSERT(0 == fSkipOffsets->count());
212         SkASSERT(NULL != fCurMCState->fSavedSkipOffsets);
213
214         SkDELETE(fSkipOffsets);
215         fSkipOffsets = fCurMCState->fSavedSkipOffsets;
216     }
217
218     bool prevHadOpen = fCurMCState->fHasOpen;
219     bool prevWasSaveLayer = fCurMCState->fIsSaveLayer;
220
221     fCurMCState->~MatrixClipState();       // balanced in save()
222     fMatrixClipStack.pop_back();
223     fCurMCState = (MatrixClipState*)fMatrixClipStack.back();
224
225     if (!prevWasSaveLayer) {
226         fCurMCState->fHasOpen = prevHadOpen;
227     }
228
229     if (fCurMCState->fIsSaveLayer) {
230         if (0 != fSkipOffsets->count()) {
231             SkASSERT(fCurMCState->fHasOpen);
232         }
233     }
234
235     SkDEBUGCODE(this->validate();)
236 }
237
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 }
246
247 bool SkMatrixClipStateMgr::isNestingMCState(int stateID) {
248     return fStateIDStack.count() > 0 && fStateIDStack[fStateIDStack.count()-1] == fCurOpenStateID;
249 }
250
251 bool SkMatrixClipStateMgr::call(CallType callType) {
252     SkDEBUGCODE(this->validate();)
253
254     if (kMatrix_CallType == callType || kClip_CallType == callType) {
255         fCurMCState->fMCStateID = NewMCStateID();
256         SkDEBUGCODE(this->validate();)
257         return false;
258     }
259
260     SkASSERT(kOther_CallType == callType);
261
262     if (fCurMCState->fMCStateID == fCurOpenStateID) {
263         // Required MC state is already active one - nothing to do
264         SkDEBUGCODE(this->validate();)
265         return false;
266     }
267
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     }
279
280     // Install the required MC state as the active one
281     fCurOpenStateID = fCurMCState->fMCStateID;
282
283     if (kIdentityWideOpenStateID == fCurOpenStateID) {
284         SkASSERT(0 == fActualDepth);
285         SkASSERT(!fCurMCState->fHasOpen);
286         SkASSERT(0 == fSkipOffsets->count());
287         return false;
288     }
289
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
298
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     }
311
312     int curMatID;
313
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);
325
326         curMatID = state->fMatrixInfo->getID(this);
327
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     }
338
339     for ( ; state != NULL; state = (const MatrixClipState*) iter.next()) {
340          state->fClipInfo->writeClip(&curMatID, this);
341     }
342
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     }
354
355     SkDEBUGCODE(this->validate();)
356     return true;
357 }
358
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     }
366
367     fSkipOffsets->rewind();
368     SkASSERT(0 == fSkipOffsets->count());
369 }
370
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 }
383
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         }
401
402         SkASSERT(fSkipOffsets->count() == clipCount);
403     }
404 }
405 #endif
406
407 int SkMatrixClipStateMgr::addRegionToDict(const SkRegion& region) {
408     int index = fRegionDict.count();
409     *fRegionDict.append() = SkNEW(SkRegion(region));
410     return index;
411 }
412
413 int SkMatrixClipStateMgr::addMatToDict(const SkMatrix& mat) {
414     if (mat.isIdentity()) {
415         return kIdentityMatID;
416     }
417
418     *fMatrixDict.append() = mat;
419     return fMatrixDict.count()-1;
420 }