SkClipStack.cpp revision 5836b6dec5563e6273099fcf23984dd3818a168f
1 2/* 3 * Copyright 2011 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8#include "SkClipStack.h" 9#include "SkPath.h" 10#include <new> 11 12struct SkClipStack::Rec { 13 enum State { 14 kEmpty_State, 15 kRect_State, 16 kPath_State 17 }; 18 19 SkPath fPath; 20 SkRect fRect; 21 int fSaveCount; 22 SkRegion::Op fOp; 23 State fState; 24 bool fDoAA; 25 26 Rec(int saveCount, const SkRect& rect, SkRegion::Op op, bool doAA) : fRect(rect) { 27 fSaveCount = saveCount; 28 fOp = op; 29 fState = kRect_State; 30 fDoAA = doAA; 31 } 32 33 Rec(int saveCount, const SkPath& path, SkRegion::Op op, bool doAA) : fPath(path) { 34 fRect.setEmpty(); 35 fSaveCount = saveCount; 36 fOp = op; 37 fState = kPath_State; 38 fDoAA = doAA; 39 } 40 41 bool operator==(const Rec& b) const { 42 if (fSaveCount != b.fSaveCount || fOp != b.fOp || fState != b.fState || 43 fDoAA != b.fDoAA) { 44 return false; 45 } 46 switch (fState) { 47 case kEmpty_State: 48 return true; 49 case kRect_State: 50 return fRect == b.fRect; 51 case kPath_State: 52 return fPath == b.fPath; 53 } 54 return false; // Silence the compiler. 55 } 56 57 bool operator!=(const Rec& b) const { 58 return !(*this == b); 59 } 60 61 62 /** 63 * Returns true if this Rec can be intersected in place with a new clip 64 */ 65 bool canBeIntersected(int saveCount, SkRegion::Op op) const { 66 if (kEmpty_State == fState && ( 67 SkRegion::kDifference_Op == op || 68 SkRegion::kIntersect_Op == op)) { 69 return true; 70 } 71 return fSaveCount == saveCount && 72 SkRegion::kIntersect_Op == fOp && 73 SkRegion::kIntersect_Op == op; 74 } 75}; 76 77SkClipStack::SkClipStack() : fDeque(sizeof(Rec)) { 78 fSaveCount = 0; 79} 80 81SkClipStack::SkClipStack(const SkClipStack& b) : fDeque(sizeof(Rec)) { 82 *this = b; 83} 84 85SkClipStack::~SkClipStack() { 86 reset(); 87} 88 89SkClipStack& SkClipStack::operator=(const SkClipStack& b) { 90 if (this == &b) { 91 return *this; 92 } 93 reset(); 94 95 fSaveCount = b.fSaveCount; 96 SkDeque::F2BIter recIter(b.fDeque); 97 for (const Rec* rec = (const Rec*)recIter.next(); 98 rec != NULL; 99 rec = (const Rec*)recIter.next()) { 100 new (fDeque.push_back()) Rec(*rec); 101 } 102 103 return *this; 104} 105 106bool SkClipStack::operator==(const SkClipStack& b) const { 107 if (fSaveCount != b.fSaveCount || fDeque.count() != b.fDeque.count()) { 108 return false; 109 } 110 SkDeque::F2BIter myIter(fDeque); 111 SkDeque::F2BIter bIter(b.fDeque); 112 const Rec* myRec = (const Rec*)myIter.next(); 113 const Rec* bRec = (const Rec*)bIter.next(); 114 115 while (myRec != NULL && bRec != NULL) { 116 if (*myRec != *bRec) { 117 return false; 118 } 119 myRec = (const Rec*)myIter.next(); 120 bRec = (const Rec*)bIter.next(); 121 } 122 return myRec == NULL && bRec == NULL; 123} 124 125void SkClipStack::reset() { 126 // We used a placement new for each object in fDeque, so we're responsible 127 // for calling the destructor on each of them as well. 128 while (!fDeque.empty()) { 129 Rec* rec = (Rec*)fDeque.back(); 130 rec->~Rec(); 131 fDeque.pop_back(); 132 } 133 134 fSaveCount = 0; 135} 136 137void SkClipStack::save() { 138 fSaveCount += 1; 139} 140 141void SkClipStack::restore() { 142 fSaveCount -= 1; 143 while (!fDeque.empty()) { 144 Rec* rec = (Rec*)fDeque.back(); 145 if (rec->fSaveCount <= fSaveCount) { 146 break; 147 } 148 rec->~Rec(); 149 fDeque.pop_back(); 150 } 151} 152 153void SkClipStack::clipDevRect(const SkRect& rect, SkRegion::Op op, bool doAA) { 154 Rec* rec = (Rec*)fDeque.back(); 155 if (rec && rec->canBeIntersected(fSaveCount, op)) { 156 switch (rec->fState) { 157 case Rec::kEmpty_State: 158 return; 159 case Rec::kRect_State: 160 if (!rec->fRect.intersect(rect)) { 161 rec->fState = Rec::kEmpty_State; 162 } 163 return; 164 case Rec::kPath_State: 165 if (!SkRect::Intersects(rec->fPath.getBounds(), rect)) { 166 rec->fState = Rec::kEmpty_State; 167 return; 168 } 169 break; 170 } 171 } 172 new (fDeque.push_back()) Rec(fSaveCount, rect, op, doAA); 173} 174 175void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op, bool doAA) { 176 SkRect alt; 177 if (path.isRect(&alt)) { 178 return this->clipDevRect(alt, op, doAA); 179 } 180 Rec* rec = (Rec*)fDeque.back(); 181 if (rec && rec->canBeIntersected(fSaveCount, op)) { 182 const SkRect& pathBounds = path.getBounds(); 183 switch (rec->fState) { 184 case Rec::kEmpty_State: 185 return; 186 case Rec::kRect_State: 187 if (!SkRect::Intersects(rec->fRect, pathBounds)) { 188 rec->fState = Rec::kEmpty_State; 189 return; 190 } 191 break; 192 case Rec::kPath_State: 193 if (!SkRect::Intersects(rec->fPath.getBounds(), pathBounds)) { 194 rec->fState = Rec::kEmpty_State; 195 return; 196 } 197 break; 198 } 199 } 200 new (fDeque.push_back()) Rec(fSaveCount, path, op, doAA); 201} 202 203/////////////////////////////////////////////////////////////////////////////// 204 205SkClipStack::Iter::Iter() : fStack(NULL) { 206} 207 208bool operator==(const SkClipStack::Iter::Clip& a, 209 const SkClipStack::Iter::Clip& b) { 210 return a.fOp == b.fOp && a.fDoAA == b.fDoAA && 211 ((a.fRect == NULL && b.fRect == NULL) || 212 (a.fRect != NULL && b.fRect != NULL && *a.fRect == *b.fRect)) && 213 ((a.fPath == NULL && b.fPath == NULL) || 214 (a.fPath != NULL && b.fPath != NULL && *a.fPath == *b.fPath)); 215} 216 217bool operator!=(const SkClipStack::Iter::Clip& a, 218 const SkClipStack::Iter::Clip& b) { 219 return !(a == b); 220} 221 222SkClipStack::Iter::Iter(const SkClipStack& stack, IterStart startLoc) 223 : fStack(&stack) { 224 this->reset(stack, startLoc); 225} 226 227const SkClipStack::Iter::Clip* SkClipStack::Iter::updateClip( 228 const SkClipStack::Rec* rec) { 229 switch (rec->fState) { 230 case SkClipStack::Rec::kEmpty_State: 231 fClip.fRect = NULL; 232 fClip.fPath = NULL; 233 break; 234 case SkClipStack::Rec::kRect_State: 235 fClip.fRect = &rec->fRect; 236 fClip.fPath = NULL; 237 break; 238 case SkClipStack::Rec::kPath_State: 239 fClip.fRect = NULL; 240 fClip.fPath = &rec->fPath; 241 break; 242 } 243 fClip.fOp = rec->fOp; 244 fClip.fDoAA = rec->fDoAA; 245 return &fClip; 246} 247 248const SkClipStack::Iter::Clip* SkClipStack::Iter::next() { 249 const SkClipStack::Rec* rec = (const SkClipStack::Rec*)fIter.next(); 250 if (NULL == rec) { 251 return NULL; 252 } 253 254 return this->updateClip(rec); 255} 256 257const SkClipStack::Iter::Clip* SkClipStack::Iter::prev() { 258 const SkClipStack::Rec* rec = (const SkClipStack::Rec*)fIter.prev(); 259 if (NULL == rec) { 260 return NULL; 261 } 262 263 return this->updateClip(rec); 264} 265 266const SkClipStack::Iter::Clip* SkClipStack::Iter::skipToLast(SkRegion::Op op) { 267 268 if (NULL == fStack) { 269 return NULL; 270 } 271 272 fIter.reset(fStack->fDeque, SkDeque::Iter::kBack_IterStart); 273 274 const SkClipStack::Rec* rec = NULL; 275 276 for (rec = (const SkClipStack::Rec*) fIter.prev(); 277 NULL != rec; 278 rec = (const SkClipStack::Rec*) fIter.prev()) { 279 280 if (op == rec->fOp) { 281 // The Deque's iterator is actually one pace ahead of the 282 // returned value. So while "rec" is the element we want to 283 // return, the iterator is actually pointing at (and will 284 // return on the next "next" or "prev" call) the element 285 // in front of it in the deque. Bump the iterator forward a 286 // step so we get the expected result. 287 if (NULL == fIter.next()) { 288 // The reverse iterator has run off the front of the deque 289 // (i.e., the "op" clip is the first clip) and can't 290 // recover. Reset the iterator to start at the front. 291 fIter.reset(fStack->fDeque, SkDeque::Iter::kFront_IterStart); 292 } 293 break; 294 } 295 } 296 297 if (NULL == rec) { 298 // There were no "op" clips 299 fIter.reset(fStack->fDeque, SkDeque::Iter::kFront_IterStart); 300 } 301 302 return this->next(); 303} 304 305void SkClipStack::Iter::reset(const SkClipStack& stack, IterStart startLoc) { 306 fIter.reset(stack.fDeque, static_cast<SkDeque::Iter::IterStart>(startLoc)); 307} 308