Home | History | Annotate | Download | only in core
      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 
     12 struct 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 
     77 SkClipStack::SkClipStack() : fDeque(sizeof(Rec)) {
     78     fSaveCount = 0;
     79 }
     80 
     81 SkClipStack::SkClipStack(const SkClipStack& b) : fDeque(sizeof(Rec)) {
     82     *this = b;
     83 }
     84 
     85 SkClipStack& SkClipStack::operator=(const SkClipStack& b) {
     86     if (this == &b) {
     87         return *this;
     88     }
     89     reset();
     90 
     91     fSaveCount = b.fSaveCount;
     92     SkDeque::F2BIter recIter(b.fDeque);
     93     for (const Rec* rec = (const Rec*)recIter.next();
     94             rec != NULL;
     95             rec = (const Rec*)recIter.next()) {
     96         new (fDeque.push_back()) Rec(*rec);
     97     }
     98 
     99     return *this;
    100 }
    101 
    102 bool SkClipStack::operator==(const SkClipStack& b) const {
    103     if (fSaveCount != b.fSaveCount || fDeque.count() != b.fDeque.count()) {
    104         return false;
    105     }
    106     SkDeque::F2BIter myIter(fDeque);
    107     SkDeque::F2BIter bIter(b.fDeque);
    108     const Rec* myRec = (const Rec*)myIter.next();
    109     const Rec* bRec = (const Rec*)bIter.next();
    110 
    111     while (myRec != NULL && bRec != NULL) {
    112         if (*myRec != *bRec) {
    113             return false;
    114         }
    115         myRec = (const Rec*)myIter.next();
    116         bRec = (const Rec*)bIter.next();
    117     }
    118     return myRec == NULL && bRec == NULL;
    119 }
    120 
    121 void SkClipStack::reset() {
    122     // don't have a reset() on SkDeque, so fake it here
    123     fDeque.~SkDeque();
    124     new (&fDeque) SkDeque(sizeof(Rec));
    125 
    126     fSaveCount = 0;
    127 }
    128 
    129 void SkClipStack::save() {
    130     fSaveCount += 1;
    131 }
    132 
    133 void SkClipStack::restore() {
    134     fSaveCount -= 1;
    135     while (!fDeque.empty()) {
    136         Rec* rec = (Rec*)fDeque.back();
    137         if (rec->fSaveCount <= fSaveCount) {
    138             break;
    139         }
    140         rec->~Rec();
    141         fDeque.pop_back();
    142     }
    143 }
    144 
    145 void SkClipStack::clipDevRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
    146     Rec* rec = (Rec*)fDeque.back();
    147     if (rec && rec->canBeIntersected(fSaveCount, op)) {
    148         switch (rec->fState) {
    149             case Rec::kEmpty_State:
    150                 return;
    151             case Rec::kRect_State:
    152                 if (!rec->fRect.intersect(rect)) {
    153                     rec->fState = Rec::kEmpty_State;
    154                 }
    155                 return;
    156             case Rec::kPath_State:
    157                 if (!SkRect::Intersects(rec->fPath.getBounds(), rect)) {
    158                     rec->fState = Rec::kEmpty_State;
    159                     return;
    160                 }
    161                 break;
    162         }
    163     }
    164     new (fDeque.push_back()) Rec(fSaveCount, rect, op, doAA);
    165 }
    166 
    167 void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op, bool doAA) {
    168     Rec* rec = (Rec*)fDeque.back();
    169     if (rec && rec->canBeIntersected(fSaveCount, op)) {
    170         const SkRect& pathBounds = path.getBounds();
    171         switch (rec->fState) {
    172             case Rec::kEmpty_State:
    173                 return;
    174             case Rec::kRect_State:
    175                 if (!SkRect::Intersects(rec->fRect, pathBounds)) {
    176                     rec->fState = Rec::kEmpty_State;
    177                     return;
    178                 }
    179                 break;
    180             case Rec::kPath_State:
    181                 if (!SkRect::Intersects(rec->fPath.getBounds(), pathBounds)) {
    182                     rec->fState = Rec::kEmpty_State;
    183                     return;
    184                 }
    185                 break;
    186         }
    187     }
    188     new (fDeque.push_back()) Rec(fSaveCount, path, op, doAA);
    189 }
    190 
    191 ///////////////////////////////////////////////////////////////////////////////
    192 
    193 SkClipStack::B2FIter::B2FIter() {
    194 }
    195 
    196 bool operator==(const SkClipStack::B2FIter::Clip& a,
    197                const SkClipStack::B2FIter::Clip& b) {
    198     return a.fOp == b.fOp && a.fDoAA == b.fDoAA &&
    199            ((a.fRect == NULL && b.fRect == NULL) ||
    200                (a.fRect != NULL && b.fRect != NULL && *a.fRect == *b.fRect)) &&
    201            ((a.fPath == NULL && b.fPath == NULL) ||
    202                (a.fPath != NULL && b.fPath != NULL && *a.fPath == *b.fPath));
    203 }
    204 
    205 bool operator!=(const SkClipStack::B2FIter::Clip& a,
    206                const SkClipStack::B2FIter::Clip& b) {
    207     return !(a == b);
    208 }
    209 
    210 SkClipStack::B2FIter::B2FIter(const SkClipStack& stack) {
    211     this->reset(stack);
    212 }
    213 
    214 const SkClipStack::B2FIter::Clip* SkClipStack::B2FIter::next() {
    215     const SkClipStack::Rec* rec = (const SkClipStack::Rec*)fIter.next();
    216     if (NULL == rec) {
    217         return NULL;
    218     }
    219 
    220     switch (rec->fState) {
    221         case SkClipStack::Rec::kEmpty_State:
    222             fClip.fRect = NULL;
    223             fClip.fPath = NULL;
    224             break;
    225         case SkClipStack::Rec::kRect_State:
    226             fClip.fRect = &rec->fRect;
    227             fClip.fPath = NULL;
    228             break;
    229         case SkClipStack::Rec::kPath_State:
    230             fClip.fRect = NULL;
    231             fClip.fPath = &rec->fPath;
    232             break;
    233     }
    234     fClip.fOp = rec->fOp;
    235     fClip.fDoAA = rec->fDoAA;
    236     return &fClip;
    237 }
    238 
    239 void SkClipStack::B2FIter::reset(const SkClipStack& stack) {
    240     fIter.reset(stack.fDeque);
    241 }
    242