Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / core / SkRasterClip.cpp
1 /*
2  * Copyright 2010 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 "SkRasterClip.h"
9 #include "SkPath.h"
10
11 SkRasterClip::SkRasterClip(const SkRasterClip& src) {
12     AUTO_RASTERCLIP_VALIDATE(src);
13
14     fForceConservativeRects = src.fForceConservativeRects;
15     fIsBW = src.fIsBW;
16     if (fIsBW) {
17         fBW = src.fBW;
18     } else {
19         fAA = src.fAA;
20     }
21
22     fIsEmpty = src.isEmpty();
23     fIsRect = src.isRect();
24     SkDEBUGCODE(this->validate();)
25 }
26
27 SkRasterClip::SkRasterClip(const SkIRect& bounds, bool forceConservativeRects) : fBW(bounds) {
28     fForceConservativeRects = forceConservativeRects;
29     fIsBW = true;
30     fIsEmpty = this->computeIsEmpty();  // bounds might be empty, so compute
31     fIsRect = !fIsEmpty;
32     SkDEBUGCODE(this->validate();)
33 }
34
35 SkRasterClip::SkRasterClip(bool forceConservativeRects) {
36     fForceConservativeRects = forceConservativeRects;
37     fIsBW = true;
38     fIsEmpty = true;
39     fIsRect = false;
40     SkDEBUGCODE(this->validate();)
41 }
42
43 SkRasterClip::~SkRasterClip() {
44     SkDEBUGCODE(this->validate();)
45 }
46
47 bool SkRasterClip::isComplex() const {
48     return fIsBW ? fBW.isComplex() : !fAA.isEmpty();
49 }
50
51 const SkIRect& SkRasterClip::getBounds() const {
52     return fIsBW ? fBW.getBounds() : fAA.getBounds();
53 }
54
55 bool SkRasterClip::setEmpty() {
56     AUTO_RASTERCLIP_VALIDATE(*this);
57
58     fIsBW = true;
59     fBW.setEmpty();
60     fAA.setEmpty();
61     fIsEmpty = true;
62     fIsRect = false;
63     return false;
64 }
65
66 bool SkRasterClip::setRect(const SkIRect& rect) {
67     AUTO_RASTERCLIP_VALIDATE(*this);
68
69     fIsBW = true;
70     fAA.setEmpty();
71     fIsRect = fBW.setRect(rect);
72     fIsEmpty = !fIsRect;
73     return fIsRect;
74 }
75
76 /////////////////////////////////////////////////////////////////////////////////////
77
78 bool SkRasterClip::setConservativeRect(const SkRect& r, const SkIRect& clipR, bool isInverse) {
79     SkIRect ir;
80     r.roundOut(&ir);
81
82     SkRegion::Op op;
83     if (isInverse) {
84         op = SkRegion::kDifference_Op;
85     } else {
86         op = SkRegion::kIntersect_Op;
87     }
88     fBW.setRect(clipR);
89     fBW.op(ir, op);
90     return this->updateCacheAndReturnNonEmpty();
91 }
92
93 /////////////////////////////////////////////////////////////////////////////////////
94
95 enum MutateResult {
96     kDoNothing_MutateResult,
97     kReplaceClippedAgainstGlobalBounds_MutateResult,
98     kContinue_MutateResult,
99 };
100
101 static MutateResult mutate_conservative_op(SkRegion::Op* op, bool inverseFilled) {
102     if (inverseFilled) {
103         switch (*op) {
104             case SkRegion::kIntersect_Op:
105             case SkRegion::kDifference_Op:
106                 // These ops can only shrink the current clip. So leaving
107                 // the clip unchanged conservatively respects the contract.
108                 return kDoNothing_MutateResult;
109             case SkRegion::kUnion_Op:
110             case SkRegion::kReplace_Op:
111             case SkRegion::kReverseDifference_Op:
112             case SkRegion::kXOR_Op: {
113                 // These ops can grow the current clip up to the extents of
114                 // the input clip, which is inverse filled, so we just set
115                 // the current clip to the device bounds.
116                 *op = SkRegion::kReplace_Op;
117                 return kReplaceClippedAgainstGlobalBounds_MutateResult;
118             }
119         }
120     } else {
121         // Not inverse filled
122         switch (*op) {
123             case SkRegion::kIntersect_Op:
124             case SkRegion::kUnion_Op:
125             case SkRegion::kReplace_Op:
126                 return kContinue_MutateResult;
127             case SkRegion::kDifference_Op:
128                 // Difference can only shrink the current clip.
129                 // Leaving clip unchanged conservatively fullfills the contract.
130                 return kDoNothing_MutateResult;
131             case SkRegion::kReverseDifference_Op:
132                 // To reverse, we swap in the bounds with a replace op.
133                 // As with difference, leave it unchanged.
134                 *op = SkRegion::kReplace_Op;
135                 return kContinue_MutateResult;
136             case SkRegion::kXOR_Op:
137                 // Be conservative, based on (A XOR B) always included in (A union B),
138                 // which is always included in (bounds(A) union bounds(B))
139                 *op = SkRegion::kUnion_Op;
140                 return kContinue_MutateResult;
141         }
142     }
143     SkFAIL("should not get here");
144     return kDoNothing_MutateResult;
145 }
146
147 bool SkRasterClip::setPath(const SkPath& path, const SkRegion& clip, bool doAA) {
148     AUTO_RASTERCLIP_VALIDATE(*this);
149
150     if (fForceConservativeRects) {
151         return this->setConservativeRect(path.getBounds(), clip.getBounds(), path.isInverseFillType());
152     }
153
154     if (this->isBW() && !doAA) {
155         (void)fBW.setPath(path, clip);
156     } else {
157         // TODO: since we are going to over-write fAA completely (aren't we?)
158         // we should just clear our BW data (if any) and set fIsAA=true
159         if (this->isBW()) {
160             this->convertToAA();
161         }
162         (void)fAA.setPath(path, &clip, doAA);
163     }
164     return this->updateCacheAndReturnNonEmpty();
165 }
166
167 bool SkRasterClip::op(const SkPath& path, const SkISize& size, SkRegion::Op op, bool doAA) {
168     // base is used to limit the size (and therefore memory allocation) of the
169     // region that results from scan converting devPath.
170     SkRegion base;
171
172     if (fForceConservativeRects) {
173         SkIRect ir;
174         switch (mutate_conservative_op(&op, path.isInverseFillType())) {
175             case kDoNothing_MutateResult:
176                 return !this->isEmpty();
177             case kReplaceClippedAgainstGlobalBounds_MutateResult:
178                 ir = SkIRect::MakeSize(size);
179                 break;
180             case kContinue_MutateResult:
181                 path.getBounds().roundOut(&ir);
182                 break;
183         }
184         return this->op(ir, op);
185     }
186
187     if (SkRegion::kIntersect_Op == op) {
188         // since we are intersect, we can do better (tighter) with currRgn's
189         // bounds, than just using the device. However, if currRgn is complex,
190         // our region blitter may hork, so we do that case in two steps.
191         if (this->isRect()) {
192             // FIXME: we should also be able to do this when this->isBW(),
193             // but relaxing the test above triggers GM asserts in
194             // SkRgnBuilder::blitH(). We need to investigate what's going on.
195             return this->setPath(path, this->bwRgn(), doAA);
196         } else {
197             base.setRect(this->getBounds());
198             SkRasterClip clip(fForceConservativeRects);
199             clip.setPath(path, base, doAA);
200             return this->op(clip, op);
201         }
202     } else {
203         base.setRect(0, 0, size.width(), size.height());
204         
205         if (SkRegion::kReplace_Op == op) {
206             return this->setPath(path, base, doAA);
207         } else {
208             SkRasterClip clip(fForceConservativeRects);
209             clip.setPath(path, base, doAA);
210             return this->op(clip, op);
211         }
212     }
213 }
214
215 bool SkRasterClip::setPath(const SkPath& path, const SkIRect& clip, bool doAA) {
216     SkRegion tmp;
217     tmp.setRect(clip);
218     return this->setPath(path, tmp, doAA);
219 }
220
221 bool SkRasterClip::op(const SkIRect& rect, SkRegion::Op op) {
222     AUTO_RASTERCLIP_VALIDATE(*this);
223
224     fIsBW ? fBW.op(rect, op) : fAA.op(rect, op);
225     return this->updateCacheAndReturnNonEmpty();
226 }
227
228 bool SkRasterClip::op(const SkRegion& rgn, SkRegion::Op op) {
229     AUTO_RASTERCLIP_VALIDATE(*this);
230
231     if (fIsBW) {
232         (void)fBW.op(rgn, op);
233     } else {
234         SkAAClip tmp;
235         tmp.setRegion(rgn);
236         (void)fAA.op(tmp, op);
237     }
238     return this->updateCacheAndReturnNonEmpty();
239 }
240
241 bool SkRasterClip::op(const SkRasterClip& clip, SkRegion::Op op) {
242     AUTO_RASTERCLIP_VALIDATE(*this);
243     clip.validate();
244
245     if (this->isBW() && clip.isBW()) {
246         (void)fBW.op(clip.fBW, op);
247     } else {
248         SkAAClip tmp;
249         const SkAAClip* other;
250
251         if (this->isBW()) {
252             this->convertToAA();
253         }
254         if (clip.isBW()) {
255             tmp.setRegion(clip.bwRgn());
256             other = &tmp;
257         } else {
258             other = &clip.aaRgn();
259         }
260         (void)fAA.op(*other, op);
261     }
262     return this->updateCacheAndReturnNonEmpty();
263 }
264
265 /**
266  *  Our antialiasing currently has a granularity of 1/4 of a pixel along each
267  *  axis. Thus we can treat an axis coordinate as an integer if it differs
268  *  from its nearest int by < half of that value (1.8 in this case).
269  */
270 static bool nearly_integral(SkScalar x) {
271     static const SkScalar domain = SK_Scalar1 / 4;
272     static const SkScalar halfDomain = domain / 2;
273
274     x += halfDomain;
275     return x - SkScalarFloorToScalar(x) < domain;
276 }
277
278 bool SkRasterClip::op(const SkRect& r, const SkISize& size, SkRegion::Op op, bool doAA) {
279     AUTO_RASTERCLIP_VALIDATE(*this);
280
281     if (fForceConservativeRects) {
282         SkIRect ir;
283         switch (mutate_conservative_op(&op, false)) {
284             case kDoNothing_MutateResult:
285                 return !this->isEmpty();
286             case kReplaceClippedAgainstGlobalBounds_MutateResult:
287                 ir = SkIRect::MakeSize(size);
288                 break;
289             case kContinue_MutateResult:
290                 r.roundOut(&ir);
291                 break;
292         }
293         return this->op(ir, op);
294     }
295     
296     if (fIsBW && doAA) {
297         // check that the rect really needs aa, or is it close enought to
298         // integer boundaries that we can just treat it as a BW rect?
299         if (nearly_integral(r.fLeft) && nearly_integral(r.fTop) &&
300             nearly_integral(r.fRight) && nearly_integral(r.fBottom)) {
301             doAA = false;
302         }
303     }
304
305     if (fIsBW && !doAA) {
306         SkIRect ir;
307         r.round(&ir);
308         (void)fBW.op(ir, op);
309     } else {
310         if (fIsBW) {
311             this->convertToAA();
312         }
313         (void)fAA.op(r, op, doAA);
314     }
315     return this->updateCacheAndReturnNonEmpty();
316 }
317
318 void SkRasterClip::translate(int dx, int dy, SkRasterClip* dst) const {
319     if (NULL == dst) {
320         return;
321     }
322
323     AUTO_RASTERCLIP_VALIDATE(*this);
324
325     if (this->isEmpty()) {
326         dst->setEmpty();
327         return;
328     }
329     if (0 == (dx | dy)) {
330         *dst = *this;
331         return;
332     }
333
334     dst->fIsBW = fIsBW;
335     if (fIsBW) {
336         fBW.translate(dx, dy, &dst->fBW);
337         dst->fAA.setEmpty();
338     } else {
339         fAA.translate(dx, dy, &dst->fAA);
340         dst->fBW.setEmpty();
341     }
342     dst->updateCacheAndReturnNonEmpty();
343 }
344
345 bool SkRasterClip::quickContains(const SkIRect& ir) const {
346     return fIsBW ? fBW.quickContains(ir) : fAA.quickContains(ir);
347 }
348
349 ///////////////////////////////////////////////////////////////////////////////
350
351 const SkRegion& SkRasterClip::forceGetBW() {
352     AUTO_RASTERCLIP_VALIDATE(*this);
353
354     if (!fIsBW) {
355         fBW.setRect(fAA.getBounds());
356     }
357     return fBW;
358 }
359
360 void SkRasterClip::convertToAA() {
361     AUTO_RASTERCLIP_VALIDATE(*this);
362     
363     SkASSERT(!fForceConservativeRects);
364     
365     SkASSERT(fIsBW);
366     fAA.setRegion(fBW);
367     fIsBW = false;
368     
369     // since we are being explicitly asked to convert-to-aa, we pass false so we don't "optimize"
370     // ourselves back to BW.
371     (void)this->updateCacheAndReturnNonEmpty(false);
372 }
373
374 #ifdef SK_DEBUG
375 void SkRasterClip::validate() const {
376     // can't ever assert that fBW is empty, since we may have called forceGetBW
377     if (fIsBW) {
378         SkASSERT(fAA.isEmpty());
379     }
380
381     fBW.validate();
382     fAA.validate();
383
384     SkASSERT(this->computeIsEmpty() == fIsEmpty);
385     SkASSERT(this->computeIsRect() == fIsRect);
386 }
387 #endif
388
389 ///////////////////////////////////////////////////////////////////////////////
390
391 SkAAClipBlitterWrapper::SkAAClipBlitterWrapper() {
392     SkDEBUGCODE(fClipRgn = NULL;)
393     SkDEBUGCODE(fBlitter = NULL;)
394 }
395
396 SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkRasterClip& clip,
397                                                SkBlitter* blitter) {
398     this->init(clip, blitter);
399 }
400
401 SkAAClipBlitterWrapper::SkAAClipBlitterWrapper(const SkAAClip* aaclip,
402                                                SkBlitter* blitter) {
403     SkASSERT(blitter);
404     SkASSERT(aaclip);
405     fBWRgn.setRect(aaclip->getBounds());
406     fAABlitter.init(blitter, aaclip);
407     // now our return values
408     fClipRgn = &fBWRgn;
409     fBlitter = &fAABlitter;
410 }
411
412 void SkAAClipBlitterWrapper::init(const SkRasterClip& clip, SkBlitter* blitter) {
413     SkASSERT(blitter);
414     if (clip.isBW()) {
415         fClipRgn = &clip.bwRgn();
416         fBlitter = blitter;
417     } else {
418         const SkAAClip& aaclip = clip.aaRgn();
419         fBWRgn.setRect(aaclip.getBounds());
420         fAABlitter.init(blitter, &aaclip);
421         // now our return values
422         fClipRgn = &fBWRgn;
423         fBlitter = &fAABlitter;
424     }
425 }