| OLD | NEW | 
|---|
| 1 /* | 1 /* | 
| 2  * Copyright 2016 Google Inc. | 2  * Copyright 2016 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 | 7 | 
| 8 #include "GrReducedClip.h" | 8 #include "GrReducedClip.h" | 
| 9 | 9 | 
| 10 #include "GrClip.h" | 10 #include "GrClip.h" | 
| 11 | 11 | 
| 12 typedef SkClipStack::Element Element; | 12 typedef SkClipStack::Element Element; | 
| 13 | 13 | 
| 14 static GrReducedClip::InitialState reduced_stack_walker(const SkClipStack& stack
     , | 14 /** | 
| 15                                                         const SkRect& queryBound
     s, | 15  * There are plenty of optimizations that could be added here. Maybe flips could
      be folded into | 
| 16                                                         const SkIRect& clipIBoun
     ds, | 16  * earlier operations. Or would inserting flips and reversing earlier ops ever b
     e a win? Perhaps | 
| 17                                                         GrReducedClip::ElementLi
     st* result, | 17  * for the case where the bounds are kInsideOut_BoundsType. We could restrict ea
     rlier operations | 
| 18                                                         int32_t* resultGenID, | 18  * based on later intersect operations, and perhaps remove intersect-rects. We c
     ould optionally | 
| 19                                                         bool* requiresAA) { | 19  * take a rect in case the caller knows a bound on what is to be drawn through t
     his clip. | 
|  | 20  */ | 
|  | 21 GrReducedClip::GrReducedClip(const SkClipStack& stack, const SkRect& queryBounds
     ) { | 
|  | 22     SkASSERT(!queryBounds.isEmpty()); | 
|  | 23     fHasIBounds = false; | 
| 20 | 24 | 
|  | 25     if (stack.isWideOpen()) { | 
|  | 26         fInitialState = InitialState::kAllIn; | 
|  | 27         return; | 
|  | 28     } | 
|  | 29 | 
|  | 30     SkClipStack::BoundsType stackBoundsType; | 
|  | 31     SkRect stackBounds; | 
|  | 32     bool iior; | 
|  | 33     stack.getBounds(&stackBounds, &stackBoundsType, &iior); | 
|  | 34 | 
|  | 35     if (stackBounds.isEmpty() || GrClip::IsOutsideClip(stackBounds, queryBounds)
     ) { | 
|  | 36         bool insideOut = SkClipStack::kInsideOut_BoundsType == stackBoundsType; | 
|  | 37         fInitialState = insideOut ? InitialState::kAllIn : InitialState::kAllOut
     ; | 
|  | 38         return; | 
|  | 39     } | 
|  | 40 | 
|  | 41     if (iior) { | 
|  | 42         // "Is intersection of rects" means the clip is a single rect indicated 
     by the stack bounds. | 
|  | 43         // This should only be true if aa/non-aa status matches among all elemen
     ts. | 
|  | 44         SkASSERT(SkClipStack::kNormal_BoundsType == stackBoundsType); | 
|  | 45         SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart); | 
|  | 46         if (!iter.prev()->isAA() || GrClip::IsPixelAligned(stackBounds)) { | 
|  | 47             // The clip is a non-aa rect. This is the one spot where we can actu
     ally implement the | 
|  | 48             // clip (using fIBounds) rather than just telling the caller what it
      should be. | 
|  | 49             stackBounds.round(&fIBounds); | 
|  | 50             fHasIBounds = true; | 
|  | 51             fInitialState = fIBounds.isEmpty() ? InitialState::kAllOut : Initial
     State::kAllIn; | 
|  | 52             return; | 
|  | 53         } | 
|  | 54         if (GrClip::IsInsideClip(stackBounds, queryBounds)) { | 
|  | 55             fInitialState = InitialState::kAllIn; | 
|  | 56             return; | 
|  | 57         } | 
|  | 58 | 
|  | 59         SkRect tightBounds; | 
|  | 60         SkAssertResult(tightBounds.intersect(stackBounds, queryBounds)); | 
|  | 61         fIBounds = GrClip::GetPixelIBounds(tightBounds); | 
|  | 62         SkASSERT(!fIBounds.isEmpty()); // Empty should have been blocked by IsOu
     tsideClip above. | 
|  | 63         fHasIBounds = true; | 
|  | 64 | 
|  | 65         // Implement the clip with an AA rect element. | 
|  | 66         fElements.addToHead(stackBounds, SkRegion::kReplace_Op, true/*doAA*/); | 
|  | 67         fElementsGenID = stack.getTopmostGenID(); | 
|  | 68         fRequiresAA = true; | 
|  | 69 | 
|  | 70         fInitialState = InitialState::kAllOut; | 
|  | 71         return; | 
|  | 72     } | 
|  | 73 | 
|  | 74     SkRect tighterQuery = queryBounds; | 
|  | 75     if (SkClipStack::kNormal_BoundsType == stackBoundsType) { | 
|  | 76         // Tighten the query by introducing a new clip at the stack's pixel boun
     daries. (This new | 
|  | 77         // clip will be enforced by the scissor through fIBounds.) | 
|  | 78         SkAssertResult(tighterQuery.intersect(GrClip::GetPixelBounds(stackBounds
     ))); | 
|  | 79     } | 
|  | 80 | 
|  | 81     fIBounds = GrClip::GetPixelIBounds(tighterQuery); | 
|  | 82     SkASSERT(!fIBounds.isEmpty()); // Empty should have been blocked by IsOutsid
     eClip above. | 
|  | 83     fHasIBounds = true; | 
|  | 84 | 
|  | 85     // Now that we have determined the bounds to use and filtered out the trivia
     l cases, call the | 
|  | 86     // helper that actually walks the stack. | 
|  | 87     this->walkStack(stack, tighterQuery); | 
|  | 88 } | 
|  | 89 | 
|  | 90 void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBound
     s) { | 
| 21     // walk backwards until we get to: | 91     // walk backwards until we get to: | 
| 22     //  a) the beginning | 92     //  a) the beginning | 
| 23     //  b) an operation that is known to make the bounds all inside/outside | 93     //  b) an operation that is known to make the bounds all inside/outside | 
| 24     //  c) a replace operation | 94     //  c) a replace operation | 
| 25 | 95 | 
| 26     enum class InitialTriState { | 96     enum class InitialTriState { | 
| 27         kUnknown = -1, | 97         kUnknown = -1, | 
| 28         kAllIn = (int)GrReducedClip::InitialState::kAllIn, | 98         kAllIn = (int)GrReducedClip::InitialState::kAllIn, | 
| 29         kAllOut = (int)GrReducedClip::InitialState::kAllOut | 99         kAllOut = (int)GrReducedClip::InitialState::kAllOut | 
| 30     } initialState = InitialTriState::kUnknown; | 100     } initialTriState = InitialTriState::kUnknown; | 
| 31 | 101 | 
| 32     // During our backwards walk, track whether we've seen ops that either grow 
     or shrink the clip. | 102     // During our backwards walk, track whether we've seen ops that either grow 
     or shrink the clip. | 
| 33     // TODO: track these per saved clip so that we can consider them on the forw
     ard pass. | 103     // TODO: track these per saved clip so that we can consider them on the forw
     ard pass. | 
| 34     bool embiggens = false; | 104     bool embiggens = false; | 
| 35     bool emsmallens = false; | 105     bool emsmallens = false; | 
| 36 | 106 | 
| 37     // We use a slightly relaxed set of query bounds for element containment tes
     ts. This is to | 107     // We use a slightly relaxed set of query bounds for element containment tes
     ts. This is to | 
| 38     // account for floating point rounding error that may have occurred during c
     oord transforms. | 108     // account for floating point rounding error that may have occurred during c
     oord transforms. | 
| 39     SkRect relaxedQueryBounds = queryBounds.makeInset(GrClip::kBoundsTolerance, | 109     SkRect relaxedQueryBounds = queryBounds.makeInset(GrClip::kBoundsTolerance, | 
| 40                                                       GrClip::kBoundsTolerance); | 110                                                       GrClip::kBoundsTolerance); | 
| 41 | 111 | 
| 42     SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart); | 112     SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart); | 
| 43     int numAAElements = 0; | 113     int numAAElements = 0; | 
| 44     while (InitialTriState::kUnknown == initialState) { | 114     while (InitialTriState::kUnknown == initialTriState) { | 
| 45         const Element* element = iter.prev(); | 115         const Element* element = iter.prev(); | 
| 46         if (nullptr == element) { | 116         if (nullptr == element) { | 
| 47             initialState = InitialTriState::kAllIn; | 117             initialTriState = InitialTriState::kAllIn; | 
| 48             break; | 118             break; | 
| 49         } | 119         } | 
| 50         if (SkClipStack::kEmptyGenID == element->getGenID()) { | 120         if (SkClipStack::kEmptyGenID == element->getGenID()) { | 
| 51             initialState = InitialTriState::kAllOut; | 121             initialTriState = InitialTriState::kAllOut; | 
| 52             break; | 122             break; | 
| 53         } | 123         } | 
| 54         if (SkClipStack::kWideOpenGenID == element->getGenID()) { | 124         if (SkClipStack::kWideOpenGenID == element->getGenID()) { | 
| 55             initialState = InitialTriState::kAllIn; | 125             initialTriState = InitialTriState::kAllIn; | 
| 56             break; | 126             break; | 
| 57         } | 127         } | 
| 58 | 128 | 
| 59         bool skippable = false; | 129         bool skippable = false; | 
| 60         bool isFlip = false; // does this op just flip the in/out state of every
      point in the bounds | 130         bool isFlip = false; // does this op just flip the in/out state of every
      point in the bounds | 
| 61 | 131 | 
| 62         switch (element->getOp()) { | 132         switch (element->getOp()) { | 
| 63             case SkRegion::kDifference_Op: | 133             case SkRegion::kDifference_Op: | 
| 64                 // check if the shape subtracted either contains the entire boun
     ds (and makes | 134                 // check if the shape subtracted either contains the entire boun
     ds (and makes | 
| 65                 // the clip empty) or is outside the bounds and therefore can be
      skipped. | 135                 // the clip empty) or is outside the bounds and therefore can be
      skipped. | 
| 66                 if (element->isInverseFilled()) { | 136                 if (element->isInverseFilled()) { | 
| 67                     if (element->contains(relaxedQueryBounds)) { | 137                     if (element->contains(relaxedQueryBounds)) { | 
| 68                         skippable = true; | 138                         skippable = true; | 
| 69                     } else if (GrClip::IsOutsideClip(element->getBounds(), query
     Bounds)) { | 139                     } else if (GrClip::IsOutsideClip(element->getBounds(), query
     Bounds)) { | 
| 70                         initialState = InitialTriState::kAllOut; | 140                         initialTriState = InitialTriState::kAllOut; | 
| 71                         skippable = true; | 141                         skippable = true; | 
| 72                     } | 142                     } | 
| 73                 } else { | 143                 } else { | 
| 74                     if (element->contains(relaxedQueryBounds)) { | 144                     if (element->contains(relaxedQueryBounds)) { | 
| 75                         initialState = InitialTriState::kAllOut; | 145                         initialTriState = InitialTriState::kAllOut; | 
| 76                         skippable = true; | 146                         skippable = true; | 
| 77                     } else if (GrClip::IsOutsideClip(element->getBounds(), query
     Bounds)) { | 147                     } else if (GrClip::IsOutsideClip(element->getBounds(), query
     Bounds)) { | 
| 78                         skippable = true; | 148                         skippable = true; | 
| 79                     } | 149                     } | 
| 80                 } | 150                 } | 
| 81                 if (!skippable) { | 151                 if (!skippable) { | 
| 82                     emsmallens = true; | 152                     emsmallens = true; | 
| 83                 } | 153                 } | 
| 84                 break; | 154                 break; | 
| 85             case SkRegion::kIntersect_Op: | 155             case SkRegion::kIntersect_Op: | 
| 86                 // check if the shape intersected contains the entire bounds and
      therefore can | 156                 // check if the shape intersected contains the entire bounds and
      therefore can | 
| 87                 // be skipped or it is outside the entire bounds and therefore m
     akes the clip | 157                 // be skipped or it is outside the entire bounds and therefore m
     akes the clip | 
| 88                 // empty. | 158                 // empty. | 
| 89                 if (element->isInverseFilled()) { | 159                 if (element->isInverseFilled()) { | 
| 90                     if (element->contains(relaxedQueryBounds)) { | 160                     if (element->contains(relaxedQueryBounds)) { | 
| 91                         initialState = InitialTriState::kAllOut; | 161                         initialTriState = InitialTriState::kAllOut; | 
| 92                         skippable = true; | 162                         skippable = true; | 
| 93                     } else if (GrClip::IsOutsideClip(element->getBounds(), query
     Bounds)) { | 163                     } else if (GrClip::IsOutsideClip(element->getBounds(), query
     Bounds)) { | 
| 94                         skippable = true; | 164                         skippable = true; | 
| 95                     } | 165                     } | 
| 96                 } else { | 166                 } else { | 
| 97                     if (element->contains(relaxedQueryBounds)) { | 167                     if (element->contains(relaxedQueryBounds)) { | 
| 98                         skippable = true; | 168                         skippable = true; | 
| 99                     } else if (GrClip::IsOutsideClip(element->getBounds(), query
     Bounds)) { | 169                     } else if (GrClip::IsOutsideClip(element->getBounds(), query
     Bounds)) { | 
| 100                         initialState = InitialTriState::kAllOut; | 170                         initialTriState = InitialTriState::kAllOut; | 
|  | 171                         skippable = true; | 
|  | 172                     } else if (!embiggens && !element->isAA() && | 
|  | 173                                Element::kRect_Type == element->getType()) { | 
|  | 174                         // fIBounds and queryBounds have already acccounted for 
     this element via | 
|  | 175                         // clip stack bounds; here we just apply the non-aa roun
     ding effect. | 
|  | 176                         SkIRect nonaaRect; | 
|  | 177                         element->getRect().round(&nonaaRect); | 
|  | 178                         if (!this->intersectIBounds(nonaaRect)) { | 
|  | 179                             return; | 
|  | 180                         } | 
| 101                         skippable = true; | 181                         skippable = true; | 
| 102                     } | 182                     } | 
| 103                 } | 183                 } | 
| 104                 if (!skippable) { | 184                 if (!skippable) { | 
| 105                     emsmallens = true; | 185                     emsmallens = true; | 
| 106                 } | 186                 } | 
| 107                 break; | 187                 break; | 
| 108             case SkRegion::kUnion_Op: | 188             case SkRegion::kUnion_Op: | 
| 109                 // If the union-ed shape contains the entire bounds then after t
     his element | 189                 // If the union-ed shape contains the entire bounds then after t
     his element | 
| 110                 // the bounds is entirely inside the clip. If the union-ed shape
      is outside the | 190                 // the bounds is entirely inside the clip. If the union-ed shape
      is outside the | 
| 111                 // bounds then this op can be skipped. | 191                 // bounds then this op can be skipped. | 
| 112                 if (element->isInverseFilled()) { | 192                 if (element->isInverseFilled()) { | 
| 113                     if (element->contains(relaxedQueryBounds)) { | 193                     if (element->contains(relaxedQueryBounds)) { | 
| 114                         skippable = true; | 194                         skippable = true; | 
| 115                     } else if (GrClip::IsOutsideClip(element->getBounds(), query
     Bounds)) { | 195                     } else if (GrClip::IsOutsideClip(element->getBounds(), query
     Bounds)) { | 
| 116                         initialState = InitialTriState::kAllIn; | 196                         initialTriState = InitialTriState::kAllIn; | 
| 117                         skippable = true; | 197                         skippable = true; | 
| 118                     } | 198                     } | 
| 119                 } else { | 199                 } else { | 
| 120                     if (element->contains(relaxedQueryBounds)) { | 200                     if (element->contains(relaxedQueryBounds)) { | 
| 121                         initialState = InitialTriState::kAllIn; | 201                         initialTriState = InitialTriState::kAllIn; | 
| 122                         skippable = true; | 202                         skippable = true; | 
| 123                     } else if (GrClip::IsOutsideClip(element->getBounds(), query
     Bounds)) { | 203                     } else if (GrClip::IsOutsideClip(element->getBounds(), query
     Bounds)) { | 
| 124                         skippable = true; | 204                         skippable = true; | 
| 125                     } | 205                     } | 
| 126                 } | 206                 } | 
| 127                 if (!skippable) { | 207                 if (!skippable) { | 
| 128                     embiggens = true; | 208                     embiggens = true; | 
| 129                 } | 209                 } | 
| 130                 break; | 210                 break; | 
| 131             case SkRegion::kXOR_Op: | 211             case SkRegion::kXOR_Op: | 
| (...skipping 18 matching lines...) Expand all  Loading... | 
| 150                     emsmallens = embiggens = true; | 230                     emsmallens = embiggens = true; | 
| 151                 } | 231                 } | 
| 152                 break; | 232                 break; | 
| 153             case SkRegion::kReverseDifference_Op: | 233             case SkRegion::kReverseDifference_Op: | 
| 154                 // When the bounds is entirely within the rev-diff shape then th
     is behaves like xor | 234                 // When the bounds is entirely within the rev-diff shape then th
     is behaves like xor | 
| 155                 // and reverses every point inside the bounds. If the shape is c
     ompletely outside | 235                 // and reverses every point inside the bounds. If the shape is c
     ompletely outside | 
| 156                 // the bounds then we know after this element is applied that th
     e bounds will be | 236                 // the bounds then we know after this element is applied that th
     e bounds will be | 
| 157                 // all outside the current clip.B | 237                 // all outside the current clip.B | 
| 158                 if (element->isInverseFilled()) { | 238                 if (element->isInverseFilled()) { | 
| 159                     if (element->contains(relaxedQueryBounds)) { | 239                     if (element->contains(relaxedQueryBounds)) { | 
| 160                         initialState = InitialTriState::kAllOut; | 240                         initialTriState = InitialTriState::kAllOut; | 
| 161                         skippable = true; | 241                         skippable = true; | 
| 162                     } else if (GrClip::IsOutsideClip(element->getBounds(), query
     Bounds)) { | 242                     } else if (GrClip::IsOutsideClip(element->getBounds(), query
     Bounds)) { | 
| 163                         isFlip = true; | 243                         isFlip = true; | 
| 164                     } | 244                     } | 
| 165                 } else { | 245                 } else { | 
| 166                     if (element->contains(relaxedQueryBounds)) { | 246                     if (element->contains(relaxedQueryBounds)) { | 
| 167                         isFlip = true; | 247                         isFlip = true; | 
| 168                     } else if (GrClip::IsOutsideClip(element->getBounds(), query
     Bounds)) { | 248                     } else if (GrClip::IsOutsideClip(element->getBounds(), query
     Bounds)) { | 
| 169                         initialState = InitialTriState::kAllOut; | 249                         initialTriState = InitialTriState::kAllOut; | 
| 170                         skippable = true; | 250                         skippable = true; | 
| 171                     } | 251                     } | 
| 172                 } | 252                 } | 
| 173                 if (!skippable) { | 253                 if (!skippable) { | 
| 174                     emsmallens = embiggens = true; | 254                     emsmallens = embiggens = true; | 
| 175                 } | 255                 } | 
| 176                 break; | 256                 break; | 
| 177 | 257 | 
| 178             case SkRegion::kReplace_Op: | 258             case SkRegion::kReplace_Op: | 
| 179                 // Replace will always terminate our walk. We will either begin 
     the forward walk | 259                 // Replace will always terminate our walk. We will either begin 
     the forward walk | 
| 180                 // at the replace op or detect here than the shape is either com
     pletely inside | 260                 // at the replace op or detect here than the shape is either com
     pletely inside | 
| 181                 // or completely outside the bounds. In this latter case it can 
     be skipped by | 261                 // or completely outside the bounds. In this latter case it can 
     be skipped by | 
| 182                 // setting the correct value for initialState. | 262                 // setting the correct value for initialTriState. | 
| 183                 if (element->isInverseFilled()) { | 263                 if (element->isInverseFilled()) { | 
| 184                     if (element->contains(relaxedQueryBounds)) { | 264                     if (element->contains(relaxedQueryBounds)) { | 
| 185                         initialState = InitialTriState::kAllOut; | 265                         initialTriState = InitialTriState::kAllOut; | 
| 186                         skippable = true; | 266                         skippable = true; | 
| 187                     } else if (GrClip::IsOutsideClip(element->getBounds(), query
     Bounds)) { | 267                     } else if (GrClip::IsOutsideClip(element->getBounds(), query
     Bounds)) { | 
| 188                         initialState = InitialTriState::kAllIn; | 268                         initialTriState = InitialTriState::kAllIn; | 
| 189                         skippable = true; | 269                         skippable = true; | 
| 190                     } | 270                     } | 
| 191                 } else { | 271                 } else { | 
| 192                     if (element->contains(relaxedQueryBounds)) { | 272                     if (element->contains(relaxedQueryBounds)) { | 
| 193                         initialState = InitialTriState::kAllIn; | 273                         initialTriState = InitialTriState::kAllIn; | 
| 194                         skippable = true; | 274                         skippable = true; | 
| 195                     } else if (GrClip::IsOutsideClip(element->getBounds(), query
     Bounds)) { | 275                     } else if (GrClip::IsOutsideClip(element->getBounds(), query
     Bounds)) { | 
| 196                         initialState = InitialTriState::kAllOut; | 276                         initialTriState = InitialTriState::kAllOut; | 
|  | 277                         skippable = true; | 
|  | 278                     } else if (!embiggens && !element->isAA() && | 
|  | 279                                Element::kRect_Type == element->getType()) { | 
|  | 280                         // fIBounds and queryBounds have already acccounted for 
     this element via | 
|  | 281                         // clip stack bounds; here we just apply the non-aa roun
     ding effect. | 
|  | 282                         SkIRect nonaaRect; | 
|  | 283                         element->getRect().round(&nonaaRect); | 
|  | 284                         if (!this->intersectIBounds(nonaaRect)) { | 
|  | 285                             return; | 
|  | 286                         } | 
|  | 287                         initialTriState = InitialTriState::kAllIn; | 
| 197                         skippable = true; | 288                         skippable = true; | 
| 198                     } | 289                     } | 
| 199                 } | 290                 } | 
| 200                 if (!skippable) { | 291                 if (!skippable) { | 
| 201                     initialState = InitialTriState::kAllOut; | 292                     initialTriState = InitialTriState::kAllOut; | 
| 202                     embiggens = emsmallens = true; | 293                     embiggens = emsmallens = true; | 
| 203                 } | 294                 } | 
| 204                 break; | 295                 break; | 
| 205             default: | 296             default: | 
| 206                 SkDEBUGFAIL("Unexpected op."); | 297                 SkDEBUGFAIL("Unexpected op."); | 
| 207                 break; | 298                 break; | 
| 208         } | 299         } | 
| 209         if (!skippable) { | 300         if (!skippable) { | 
| 210             if (0 == result->count()) { | 301             if (0 == fElements.count()) { | 
| 211                 // This will be the last element. Record the stricter genID. | 302                 // This will be the last element. Record the stricter genID. | 
| 212                 *resultGenID = element->getGenID(); | 303                 fElementsGenID = element->getGenID(); | 
| 213             } | 304             } | 
| 214 | 305 | 
| 215             // if it is a flip, change it to a bounds-filling rect | 306             // if it is a flip, change it to a bounds-filling rect | 
| 216             if (isFlip) { | 307             if (isFlip) { | 
| 217                 SkASSERT(SkRegion::kXOR_Op == element->getOp() || | 308                 SkASSERT(SkRegion::kXOR_Op == element->getOp() || | 
| 218                          SkRegion::kReverseDifference_Op == element->getOp()); | 309                          SkRegion::kReverseDifference_Op == element->getOp()); | 
| 219                 result->addToHead(SkRect::Make(clipIBounds), SkRegion::kReverseD
     ifference_Op, | 310                 fElements.addToHead(SkRect::Make(fIBounds), SkRegion::kReverseDi
     fference_Op, false); | 
| 220                                   false); |  | 
| 221             } else { | 311             } else { | 
| 222                 Element* newElement = result->addToHead(*element); | 312                 Element* newElement = fElements.addToHead(*element); | 
| 223                 if (newElement->isAA()) { | 313                 if (newElement->isAA()) { | 
| 224                     ++numAAElements; | 314                     ++numAAElements; | 
| 225                 } | 315                 } | 
| 226                 // Intersecting an inverse shape is the same as differencing the
      non-inverse shape. | 316                 // Intersecting an inverse shape is the same as differencing the
      non-inverse shape. | 
| 227                 // Replacing with an inverse shape is the same as setting initia
     lState=kAllIn and | 317                 // Replacing with an inverse shape is the same as setting initia
     lState=kAllIn and | 
| 228                 // differencing the non-inverse shape. | 318                 // differencing the non-inverse shape. | 
| 229                 bool isReplace = SkRegion::kReplace_Op == newElement->getOp(); | 319                 bool isReplace = SkRegion::kReplace_Op == newElement->getOp(); | 
| 230                 if (newElement->isInverseFilled() && | 320                 if (newElement->isInverseFilled() && | 
| 231                     (SkRegion::kIntersect_Op == newElement->getOp() || isReplace
     )) { | 321                     (SkRegion::kIntersect_Op == newElement->getOp() || isReplace
     )) { | 
| 232                     newElement->invertShapeFillType(); | 322                     newElement->invertShapeFillType(); | 
| 233                     newElement->setOp(SkRegion::kDifference_Op); | 323                     newElement->setOp(SkRegion::kDifference_Op); | 
| 234                     if (isReplace) { | 324                     if (isReplace) { | 
| 235                         SkASSERT(InitialTriState::kAllOut == initialState); | 325                         SkASSERT(InitialTriState::kAllOut == initialTriState); | 
| 236                         initialState = InitialTriState::kAllIn; | 326                         initialTriState = InitialTriState::kAllIn; | 
| 237                     } | 327                     } | 
| 238                 } | 328                 } | 
| 239             } | 329             } | 
| 240         } | 330         } | 
| 241     } | 331     } | 
| 242 | 332 | 
| 243     if ((InitialTriState::kAllOut == initialState && !embiggens) || | 333     if ((InitialTriState::kAllOut == initialTriState && !embiggens) || | 
| 244         (InitialTriState::kAllIn == initialState && !emsmallens)) { | 334         (InitialTriState::kAllIn == initialTriState && !emsmallens)) { | 
| 245         result->reset(); | 335         fElements.reset(); | 
| 246         numAAElements = 0; | 336         numAAElements = 0; | 
| 247     } else { | 337     } else { | 
| 248         Element* element = result->headIter().get(); | 338         Element* element = fElements.headIter().get(); | 
| 249         while (element) { | 339         while (element) { | 
| 250             bool skippable = false; | 340             bool skippable = false; | 
| 251             switch (element->getOp()) { | 341             switch (element->getOp()) { | 
| 252                 case SkRegion::kDifference_Op: | 342                 case SkRegion::kDifference_Op: | 
| 253                     // subtracting from the empty set yields the empty set. | 343                     // subtracting from the empty set yields the empty set. | 
| 254                     skippable = InitialTriState::kAllOut == initialState; | 344                     skippable = InitialTriState::kAllOut == initialTriState; | 
| 255                     break; | 345                     break; | 
| 256                 case SkRegion::kIntersect_Op: | 346                 case SkRegion::kIntersect_Op: | 
| 257                     // intersecting with the empty set yields the empty set | 347                     // intersecting with the empty set yields the empty set | 
| 258                     if (InitialTriState::kAllOut == initialState) { | 348                     if (InitialTriState::kAllOut == initialTriState) { | 
| 259                         skippable = true; | 349                         skippable = true; | 
| 260                     } else { | 350                     } else { | 
| 261                         // We can clear to zero and then simply draw the clip el
     ement. | 351                         // We can clear to zero and then simply draw the clip el
     ement. | 
| 262                         initialState = InitialTriState::kAllOut; | 352                         initialTriState = InitialTriState::kAllOut; | 
| 263                         element->setOp(SkRegion::kReplace_Op); | 353                         element->setOp(SkRegion::kReplace_Op); | 
| 264                     } | 354                     } | 
| 265                     break; | 355                     break; | 
| 266                 case SkRegion::kUnion_Op: | 356                 case SkRegion::kUnion_Op: | 
| 267                     if (InitialTriState::kAllIn == initialState) { | 357                     if (InitialTriState::kAllIn == initialTriState) { | 
| 268                         // unioning the infinite plane with anything is a no-op. | 358                         // unioning the infinite plane with anything is a no-op. | 
| 269                         skippable = true; | 359                         skippable = true; | 
| 270                     } else { | 360                     } else { | 
| 271                         // unioning the empty set with a shape is the shape. | 361                         // unioning the empty set with a shape is the shape. | 
| 272                         element->setOp(SkRegion::kReplace_Op); | 362                         element->setOp(SkRegion::kReplace_Op); | 
| 273                     } | 363                     } | 
| 274                     break; | 364                     break; | 
| 275                 case SkRegion::kXOR_Op: | 365                 case SkRegion::kXOR_Op: | 
| 276                     if (InitialTriState::kAllOut == initialState) { | 366                     if (InitialTriState::kAllOut == initialTriState) { | 
| 277                         // xor could be changed to diff in the kAllIn case, not 
     sure it's a win. | 367                         // xor could be changed to diff in the kAllIn case, not 
     sure it's a win. | 
| 278                         element->setOp(SkRegion::kReplace_Op); | 368                         element->setOp(SkRegion::kReplace_Op); | 
| 279                     } | 369                     } | 
| 280                     break; | 370                     break; | 
| 281                 case SkRegion::kReverseDifference_Op: | 371                 case SkRegion::kReverseDifference_Op: | 
| 282                     if (InitialTriState::kAllIn == initialState) { | 372                     if (InitialTriState::kAllIn == initialTriState) { | 
| 283                         // subtracting the whole plane will yield the empty set. | 373                         // subtracting the whole plane will yield the empty set. | 
| 284                         skippable = true; | 374                         skippable = true; | 
| 285                         initialState = InitialTriState::kAllOut; | 375                         initialTriState = InitialTriState::kAllOut; | 
| 286                     } else { | 376                     } else { | 
| 287                         // this picks up flips inserted in the backwards pass. | 377                         // this picks up flips inserted in the backwards pass. | 
| 288                         skippable = element->isInverseFilled() ? | 378                         skippable = element->isInverseFilled() ? | 
| 289                             GrClip::IsOutsideClip(element->getBounds(), queryBou
     nds) : | 379                             GrClip::IsOutsideClip(element->getBounds(), queryBou
     nds) : | 
| 290                             element->contains(relaxedQueryBounds); | 380                             element->contains(relaxedQueryBounds); | 
| 291                         if (skippable) { | 381                         if (skippable) { | 
| 292                             initialState = InitialTriState::kAllIn; | 382                             initialTriState = InitialTriState::kAllIn; | 
| 293                         } else { | 383                         } else { | 
| 294                             element->setOp(SkRegion::kReplace_Op); | 384                             element->setOp(SkRegion::kReplace_Op); | 
| 295                         } | 385                         } | 
| 296                     } | 386                     } | 
| 297                     break; | 387                     break; | 
| 298                 case SkRegion::kReplace_Op: | 388                 case SkRegion::kReplace_Op: | 
| 299                     skippable = false; // we would have skipped it in the backwa
     rds walk if we | 389                     skippable = false; // we would have skipped it in the backwa
     rds walk if we | 
| 300                                        // could've. | 390                                        // could've. | 
| 301                     break; | 391                     break; | 
| 302                 default: | 392                 default: | 
| 303                     SkDEBUGFAIL("Unexpected op."); | 393                     SkDEBUGFAIL("Unexpected op."); | 
| 304                     break; | 394                     break; | 
| 305             } | 395             } | 
| 306             if (!skippable) { | 396             if (!skippable) { | 
| 307                 break; | 397                 break; | 
| 308             } else { | 398             } else { | 
| 309                 if (element->isAA()) { | 399                 if (element->isAA()) { | 
| 310                     --numAAElements; | 400                     --numAAElements; | 
| 311                 } | 401                 } | 
| 312                 result->popHead(); | 402                 fElements.popHead(); | 
| 313                 element = result->headIter().get(); | 403                 element = fElements.headIter().get(); | 
| 314             } | 404             } | 
| 315         } | 405         } | 
| 316     } | 406     } | 
| 317     *requiresAA = numAAElements > 0; | 407     fRequiresAA = numAAElements > 0; | 
| 318 | 408 | 
| 319     SkASSERT(InitialTriState::kUnknown != initialState); | 409     SkASSERT(InitialTriState::kUnknown != initialTriState); | 
| 320     return static_cast<GrReducedClip::InitialState>(initialState); | 410     fInitialState = static_cast<GrReducedClip::InitialState>(initialTriState); | 
| 321 } | 411 } | 
| 322 | 412 | 
| 323 /* | 413 inline bool GrReducedClip::intersectIBounds(const SkIRect& irect) { | 
| 324 There are plenty of optimizations that could be added here. Maybe flips could be
      folded into | 414     SkASSERT(fHasIBounds); | 
| 325 earlier operations. Or would inserting flips and reversing earlier ops ever be a
      win? Perhaps | 415     if (!fIBounds.intersect(irect)) { | 
| 326 for the case where the bounds are kInsideOut_BoundsType. We could restrict earli
     er operations | 416         fHasIBounds = false; | 
| 327 based on later intersect operations, and perhaps remove intersect-rects. We coul
     d optionally | 417         fElements.reset(); | 
| 328 take a rect in case the caller knows a bound on what is to be drawn through this
      clip. | 418         fRequiresAA = false; | 
| 329 */ | 419         fInitialState = InitialState::kAllOut; | 
| 330 GrReducedClip::GrReducedClip(const SkClipStack& stack, const SkRect& queryBounds
     ) { | 420         return false; | 
| 331     SkASSERT(!queryBounds.isEmpty()); |  | 
| 332     fHasIBounds = false; |  | 
| 333 |  | 
| 334     if (stack.isWideOpen()) { |  | 
| 335         fInitialState = InitialState::kAllIn; |  | 
| 336         return; |  | 
| 337     } | 421     } | 
| 338 | 422     return true; | 
| 339     SkClipStack::BoundsType stackBoundsType; |  | 
| 340     SkRect stackBounds; |  | 
| 341     bool iior; |  | 
| 342     stack.getBounds(&stackBounds, &stackBoundsType, &iior); |  | 
| 343 |  | 
| 344     if (stackBounds.isEmpty() || GrClip::IsOutsideClip(stackBounds, queryBounds)
     ) { |  | 
| 345         bool insideOut = SkClipStack::kInsideOut_BoundsType == stackBoundsType; |  | 
| 346         fInitialState = insideOut ? InitialState::kAllIn : InitialState::kAllOut
     ; |  | 
| 347         return; |  | 
| 348     } |  | 
| 349 |  | 
| 350     if (iior) { |  | 
| 351         // "Is intersection of rects" means the clip is a single rect indicated 
     by the stack bounds. |  | 
| 352         // This should only be true if aa/non-aa status matches among all elemen
     ts. |  | 
| 353         SkASSERT(SkClipStack::kNormal_BoundsType == stackBoundsType); |  | 
| 354         SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart); |  | 
| 355         if (!iter.prev()->isAA() || GrClip::IsPixelAligned(stackBounds)) { |  | 
| 356             // The clip is a non-aa rect. This is the one spot where we can actu
     ally implement the |  | 
| 357             // clip (using fIBounds) rather than just telling the caller what it
      should be. |  | 
| 358             stackBounds.round(&fIBounds); |  | 
| 359             fHasIBounds = true; |  | 
| 360             fInitialState = fIBounds.isEmpty() ? InitialState::kAllOut : Initial
     State::kAllIn; |  | 
| 361             return; |  | 
| 362         } |  | 
| 363         if (GrClip::IsInsideClip(stackBounds, queryBounds)) { |  | 
| 364             fInitialState = InitialState::kAllIn; |  | 
| 365             return; |  | 
| 366         } |  | 
| 367 |  | 
| 368         SkRect tightBounds; |  | 
| 369         SkAssertResult(tightBounds.intersect(stackBounds, queryBounds)); |  | 
| 370         fIBounds = GrClip::GetPixelIBounds(tightBounds); |  | 
| 371         SkASSERT(!fIBounds.isEmpty()); // Empty should have been blocked by IsOu
     tsideClip above. |  | 
| 372         fHasIBounds = true; |  | 
| 373 |  | 
| 374         // Implement the clip with an AA rect element. |  | 
| 375         fElements.addToHead(stackBounds, SkRegion::kReplace_Op, true/*doAA*/); |  | 
| 376         fElementsGenID = stack.getTopmostGenID(); |  | 
| 377         fRequiresAA = true; |  | 
| 378 |  | 
| 379         fInitialState = InitialState::kAllOut; |  | 
| 380         return; |  | 
| 381     } |  | 
| 382 |  | 
| 383     SkRect tighterQuery = queryBounds; |  | 
| 384     if (SkClipStack::kNormal_BoundsType == stackBoundsType) { |  | 
| 385         // Tighten the query by introducing a new clip at the stack's pixel boun
     daries. (This new |  | 
| 386         // clip will be enforced by the scissor through fIBounds.) |  | 
| 387         SkAssertResult(tighterQuery.intersect(GrClip::GetPixelBounds(stackBounds
     ))); |  | 
| 388     } |  | 
| 389 |  | 
| 390     fIBounds = GrClip::GetPixelIBounds(tighterQuery); |  | 
| 391     SkASSERT(!fIBounds.isEmpty()); // Empty should have been blocked by IsOutsid
     eClip above. |  | 
| 392     fHasIBounds = true; |  | 
| 393 |  | 
| 394     // Now that we have determined the bounds to use and filtered out the trivia
     l cases, call the |  | 
| 395     // helper that actually walks the stack. |  | 
| 396     fInitialState = reduced_stack_walker(stack, tighterQuery, fIBounds, &fElemen
     ts, &fElementsGenID, |  | 
| 397                                          &fRequiresAA); |  | 
| 398 } | 423 } | 
| OLD | NEW | 
|---|