| bsalomon@google.com | 170bd79 | 2012-12-05 22:26:11 +0000 | [diff] [blame] | 1 | /* | 
| csmartdalton | 77f2fae | 2016-08-08 09:55:06 -0700 | [diff] [blame] | 2 |  * Copyright 2016 Google Inc. | 
| bsalomon@google.com | 170bd79 | 2012-12-05 22:26:11 +0000 | [diff] [blame] | 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 "GrReducedClip.h" | 
 | 9 |  | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 10 | #include "GrAppliedClip.h" | 
| csmartdalton | cbecb08 | 2016-07-22 08:59:08 -0700 | [diff] [blame] | 11 | #include "GrClip.h" | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 12 | #include "GrColor.h" | 
 | 13 | #include "GrContextPriv.h" | 
| Brian Osman | 1105224 | 2016-10-27 14:47:55 -0400 | [diff] [blame] | 14 | #include "GrRenderTargetContext.h" | 
 | 15 | #include "GrRenderTargetContextPriv.h" | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 16 | #include "GrDrawingManager.h" | 
 | 17 | #include "GrFixedClip.h" | 
 | 18 | #include "GrPathRenderer.h" | 
| csmartdalton | c633abb | 2016-11-01 08:55:55 -0700 | [diff] [blame] | 19 | #include "GrStencilSettings.h" | 
| Chris Dalton | bbfd516 | 2017-11-07 13:35:22 -0700 | [diff] [blame] | 20 | #include "GrStencilClip.h" | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 21 | #include "GrStyle.h" | 
 | 22 | #include "GrUserStencilSettings.h" | 
| Mike Reed | ebfce6d | 2016-12-12 10:02:12 -0500 | [diff] [blame] | 23 | #include "SkClipOpPriv.h" | 
| Chris Dalton | 584a79a | 2017-11-15 13:14:01 -0700 | [diff] [blame] | 24 | #include "effects/GrConvexPolyEffect.h" | 
 | 25 | #include "effects/GrRRectEffect.h" | 
| csmartdalton | cbecb08 | 2016-07-22 08:59:08 -0700 | [diff] [blame] | 26 |  | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 27 | /** | 
 | 28 |  * There are plenty of optimizations that could be added here. Maybe flips could be folded into | 
 | 29 |  * earlier operations. Or would inserting flips and reversing earlier ops ever be a win? Perhaps | 
 | 30 |  * for the case where the bounds are kInsideOut_BoundsType. We could restrict earlier operations | 
 | 31 |  * based on later intersect operations, and perhaps remove intersect-rects. We could optionally | 
 | 32 |  * take a rect in case the caller knows a bound on what is to be drawn through this clip. | 
 | 33 |  */ | 
| csmartdalton | bf4a8f9 | 2016-09-06 10:01:06 -0700 | [diff] [blame] | 34 | GrReducedClip::GrReducedClip(const SkClipStack& stack, const SkRect& queryBounds, | 
| Chris Dalton | 584a79a | 2017-11-15 13:14:01 -0700 | [diff] [blame] | 35 |                              int maxWindowRectangles, int maxAnalyticFPs) | 
 | 36 |         : fMaxWindowRectangles(maxWindowRectangles) | 
 | 37 |         , fMaxAnalyticFPs(maxAnalyticFPs) { | 
| csmartdalton | cbecb08 | 2016-07-22 08:59:08 -0700 | [diff] [blame] | 38 |     SkASSERT(!queryBounds.isEmpty()); | 
| Chris Dalton | 584a79a | 2017-11-15 13:14:01 -0700 | [diff] [blame] | 39 |     SkASSERT(fMaxWindowRectangles <= GrWindowRectangles::kMaxWindows); | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 40 |     fHasScissor = false; | 
 | 41 |     fAAClipRectGenID = SK_InvalidGenID; | 
| csmartdalton | cbecb08 | 2016-07-22 08:59:08 -0700 | [diff] [blame] | 42 |  | 
| bsalomon@google.com | 170bd79 | 2012-12-05 22:26:11 +0000 | [diff] [blame] | 43 |     if (stack.isWideOpen()) { | 
| csmartdalton | 77f2fae | 2016-08-08 09:55:06 -0700 | [diff] [blame] | 44 |         fInitialState = InitialState::kAllIn; | 
 | 45 |         return; | 
| bsalomon@google.com | 170bd79 | 2012-12-05 22:26:11 +0000 | [diff] [blame] | 46 |     } | 
 | 47 |  | 
 | 48 |     SkClipStack::BoundsType stackBoundsType; | 
 | 49 |     SkRect stackBounds; | 
 | 50 |     bool iior; | 
 | 51 |     stack.getBounds(&stackBounds, &stackBoundsType, &iior); | 
 | 52 |  | 
| Chris Dalton | 348060f | 2017-06-05 13:15:37 -0600 | [diff] [blame] | 53 |     if (GrClip::IsOutsideClip(stackBounds, queryBounds)) { | 
| csmartdalton | cbecb08 | 2016-07-22 08:59:08 -0700 | [diff] [blame] | 54 |         bool insideOut = SkClipStack::kInsideOut_BoundsType == stackBoundsType; | 
| csmartdalton | 77f2fae | 2016-08-08 09:55:06 -0700 | [diff] [blame] | 55 |         fInitialState = insideOut ? InitialState::kAllIn : InitialState::kAllOut; | 
 | 56 |         return; | 
| bsalomon@google.com | 170bd79 | 2012-12-05 22:26:11 +0000 | [diff] [blame] | 57 |     } | 
 | 58 |  | 
| csmartdalton | cbecb08 | 2016-07-22 08:59:08 -0700 | [diff] [blame] | 59 |     if (iior) { | 
 | 60 |         // "Is intersection of rects" means the clip is a single rect indicated by the stack bounds. | 
 | 61 |         // This should only be true if aa/non-aa status matches among all elements. | 
 | 62 |         SkASSERT(SkClipStack::kNormal_BoundsType == stackBoundsType); | 
 | 63 |         SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart); | 
 | 64 |         if (!iter.prev()->isAA() || GrClip::IsPixelAligned(stackBounds)) { | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 65 |             // The clip is a non-aa rect. Here we just implement the entire thing using fScissor. | 
| Mike Klein | e26062a | 2017-10-31 20:56:54 +0000 | [diff] [blame] | 66 |             stackBounds.round(&fScissor); | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 67 |             fHasScissor = true; | 
 | 68 |             fInitialState = fScissor.isEmpty() ? InitialState::kAllOut : InitialState::kAllIn; | 
| csmartdalton | 77f2fae | 2016-08-08 09:55:06 -0700 | [diff] [blame] | 69 |             return; | 
| csmartdalton | cbecb08 | 2016-07-22 08:59:08 -0700 | [diff] [blame] | 70 |         } | 
 | 71 |         if (GrClip::IsInsideClip(stackBounds, queryBounds)) { | 
| csmartdalton | 77f2fae | 2016-08-08 09:55:06 -0700 | [diff] [blame] | 72 |             fInitialState = InitialState::kAllIn; | 
 | 73 |             return; | 
| csmartdalton | cbecb08 | 2016-07-22 08:59:08 -0700 | [diff] [blame] | 74 |         } | 
 | 75 |  | 
| csmartdalton | d211e78 | 2016-08-15 11:17:19 -0700 | [diff] [blame] | 76 |         SkRect tightBounds; | 
 | 77 |         SkAssertResult(tightBounds.intersect(stackBounds, queryBounds)); | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 78 |         fScissor = GrClip::GetPixelIBounds(tightBounds); | 
 | 79 |         if (fScissor.isEmpty()) { | 
| Chris Dalton | 348060f | 2017-06-05 13:15:37 -0600 | [diff] [blame] | 80 |             fInitialState = InitialState::kAllOut; | 
 | 81 |             return; | 
 | 82 |         } | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 83 |         fHasScissor = true; | 
| csmartdalton | cbecb08 | 2016-07-22 08:59:08 -0700 | [diff] [blame] | 84 |  | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 85 |         fAAClipRect = stackBounds; | 
 | 86 |         fAAClipRectGenID = stack.getTopmostGenID(); | 
 | 87 |         SkASSERT(SK_InvalidGenID != fAAClipRectGenID); | 
| csmartdalton | 77f2fae | 2016-08-08 09:55:06 -0700 | [diff] [blame] | 88 |  | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 89 |         fInitialState = InitialState::kAllIn; | 
 | 90 |     } else { | 
 | 91 |         SkRect tighterQuery = queryBounds; | 
 | 92 |         if (SkClipStack::kNormal_BoundsType == stackBoundsType) { | 
 | 93 |             // Tighten the query by introducing a new clip at the stack's pixel boundaries. (This | 
 | 94 |             // new clip will be enforced by the scissor.) | 
 | 95 |             SkAssertResult(tighterQuery.intersect(GrClip::GetPixelBounds(stackBounds))); | 
 | 96 |         } | 
 | 97 |  | 
 | 98 |         fScissor = GrClip::GetPixelIBounds(tighterQuery); | 
 | 99 |         if (fScissor.isEmpty()) { | 
 | 100 |             fInitialState = InitialState::kAllOut; | 
 | 101 |             return; | 
 | 102 |         } | 
 | 103 |         fHasScissor = true; | 
 | 104 |  | 
| Chris Dalton | 584a79a | 2017-11-15 13:14:01 -0700 | [diff] [blame] | 105 |         // Now that we have determined the bounds to use and filtered out the trivial cases, call | 
 | 106 |         // the helper that actually walks the stack. | 
 | 107 |         this->walkStack(stack, tighterQuery); | 
| csmartdalton | cbecb08 | 2016-07-22 08:59:08 -0700 | [diff] [blame] | 108 |     } | 
 | 109 |  | 
| Chris Dalton | 584a79a | 2017-11-15 13:14:01 -0700 | [diff] [blame] | 110 |     if (SK_InvalidGenID != fAAClipRectGenID && // Is there an AA clip rect? | 
| Chris Dalton | 3b51df1 | 2017-11-27 14:33:06 -0700 | [diff] [blame^] | 111 |         ClipResult::kNotClipped == this->addAnalyticFP(fAAClipRect, Invert::kNo, GrAA::kYes)) { | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 112 |         if (fMaskElements.isEmpty()) { | 
 | 113 |             // Use a replace since it is faster than intersect. | 
 | 114 |             fMaskElements.addToHead(fAAClipRect, SkMatrix::I(), kReplace_SkClipOp, true /*doAA*/); | 
 | 115 |             fInitialState = InitialState::kAllOut; | 
 | 116 |         } else { | 
 | 117 |             fMaskElements.addToTail(fAAClipRect, SkMatrix::I(), kIntersect_SkClipOp, true /*doAA*/); | 
 | 118 |         } | 
 | 119 |         fMaskRequiresAA = true; | 
 | 120 |         fMaskGenID = fAAClipRectGenID; | 
| csmartdalton | bf4a8f9 | 2016-09-06 10:01:06 -0700 | [diff] [blame] | 121 |     } | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 122 | } | 
 | 123 |  | 
| Chris Dalton | 584a79a | 2017-11-15 13:14:01 -0700 | [diff] [blame] | 124 | void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBounds) { | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 125 |     // walk backwards until we get to: | 
 | 126 |     //  a) the beginning | 
 | 127 |     //  b) an operation that is known to make the bounds all inside/outside | 
 | 128 |     //  c) a replace operation | 
 | 129 |  | 
 | 130 |     enum class InitialTriState { | 
 | 131 |         kUnknown = -1, | 
 | 132 |         kAllIn = (int)GrReducedClip::InitialState::kAllIn, | 
 | 133 |         kAllOut = (int)GrReducedClip::InitialState::kAllOut | 
 | 134 |     } initialTriState = InitialTriState::kUnknown; | 
 | 135 |  | 
 | 136 |     // During our backwards walk, track whether we've seen ops that either grow or shrink the clip. | 
 | 137 |     // TODO: track these per saved clip so that we can consider them on the forward pass. | 
 | 138 |     bool embiggens = false; | 
 | 139 |     bool emsmallens = false; | 
 | 140 |  | 
 | 141 |     // We use a slightly relaxed set of query bounds for element containment tests. This is to | 
 | 142 |     // account for floating point rounding error that may have occurred during coord transforms. | 
 | 143 |     SkRect relaxedQueryBounds = queryBounds.makeInset(GrClip::kBoundsTolerance, | 
 | 144 |                                                       GrClip::kBoundsTolerance); | 
| Chris Dalton | 6982400 | 2017-10-31 00:37:52 -0600 | [diff] [blame] | 145 |     if (relaxedQueryBounds.isEmpty()) { | 
 | 146 |         relaxedQueryBounds = queryBounds; | 
 | 147 |     } | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 148 |  | 
 | 149 |     SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart); | 
 | 150 |     int numAAElements = 0; | 
 | 151 |     while (InitialTriState::kUnknown == initialTriState) { | 
 | 152 |         const Element* element = iter.prev(); | 
 | 153 |         if (nullptr == element) { | 
 | 154 |             initialTriState = InitialTriState::kAllIn; | 
 | 155 |             break; | 
 | 156 |         } | 
 | 157 |         if (SkClipStack::kEmptyGenID == element->getGenID()) { | 
 | 158 |             initialTriState = InitialTriState::kAllOut; | 
 | 159 |             break; | 
 | 160 |         } | 
 | 161 |         if (SkClipStack::kWideOpenGenID == element->getGenID()) { | 
 | 162 |             initialTriState = InitialTriState::kAllIn; | 
 | 163 |             break; | 
 | 164 |         } | 
 | 165 |  | 
 | 166 |         bool skippable = false; | 
 | 167 |         bool isFlip = false; // does this op just flip the in/out state of every point in the bounds | 
 | 168 |  | 
 | 169 |         switch (element->getOp()) { | 
| Mike Reed | c1f7774 | 2016-12-09 09:00:50 -0500 | [diff] [blame] | 170 |             case kDifference_SkClipOp: | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 171 |                 // check if the shape subtracted either contains the entire bounds (and makes | 
 | 172 |                 // the clip empty) or is outside the bounds and therefore can be skipped. | 
 | 173 |                 if (element->isInverseFilled()) { | 
 | 174 |                     if (element->contains(relaxedQueryBounds)) { | 
 | 175 |                         skippable = true; | 
 | 176 |                     } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) { | 
 | 177 |                         initialTriState = InitialTriState::kAllOut; | 
 | 178 |                         skippable = true; | 
 | 179 |                     } | 
 | 180 |                 } else { | 
 | 181 |                     if (element->contains(relaxedQueryBounds)) { | 
 | 182 |                         initialTriState = InitialTriState::kAllOut; | 
 | 183 |                         skippable = true; | 
 | 184 |                     } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) { | 
 | 185 |                         skippable = true; | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 186 |                     } else if (!embiggens) { | 
| Chris Dalton | 584a79a | 2017-11-15 13:14:01 -0700 | [diff] [blame] | 187 |                         ClipResult result = this->clipOutsideElement(element); | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 188 |                         if (ClipResult::kMadeEmpty == result) { | 
 | 189 |                             return; | 
 | 190 |                         } | 
 | 191 |                         skippable = (ClipResult::kClipped == result); | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 192 |                     } | 
 | 193 |                 } | 
 | 194 |                 if (!skippable) { | 
 | 195 |                     emsmallens = true; | 
 | 196 |                 } | 
 | 197 |                 break; | 
| Mike Reed | c1f7774 | 2016-12-09 09:00:50 -0500 | [diff] [blame] | 198 |             case kIntersect_SkClipOp: | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 199 |                 // check if the shape intersected contains the entire bounds and therefore can | 
 | 200 |                 // be skipped or it is outside the entire bounds and therefore makes the clip | 
 | 201 |                 // empty. | 
 | 202 |                 if (element->isInverseFilled()) { | 
 | 203 |                     if (element->contains(relaxedQueryBounds)) { | 
 | 204 |                         initialTriState = InitialTriState::kAllOut; | 
 | 205 |                         skippable = true; | 
 | 206 |                     } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) { | 
 | 207 |                         skippable = true; | 
 | 208 |                     } | 
 | 209 |                 } else { | 
 | 210 |                     if (element->contains(relaxedQueryBounds)) { | 
 | 211 |                         skippable = true; | 
 | 212 |                     } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) { | 
 | 213 |                         initialTriState = InitialTriState::kAllOut; | 
 | 214 |                         skippable = true; | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 215 |                     } else if (!embiggens) { | 
 | 216 |                         ClipResult result = this->clipInsideElement(element); | 
 | 217 |                         if (ClipResult::kMadeEmpty == result) { | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 218 |                             return; | 
 | 219 |                         } | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 220 |                         skippable = (ClipResult::kClipped == result); | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 221 |                     } | 
 | 222 |                 } | 
 | 223 |                 if (!skippable) { | 
 | 224 |                     emsmallens = true; | 
 | 225 |                 } | 
 | 226 |                 break; | 
| Mike Reed | c1f7774 | 2016-12-09 09:00:50 -0500 | [diff] [blame] | 227 |             case kUnion_SkClipOp: | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 228 |                 // If the union-ed shape contains the entire bounds then after this element | 
 | 229 |                 // the bounds is entirely inside the clip. If the union-ed shape is outside the | 
 | 230 |                 // bounds then this op can be skipped. | 
 | 231 |                 if (element->isInverseFilled()) { | 
 | 232 |                     if (element->contains(relaxedQueryBounds)) { | 
 | 233 |                         skippable = true; | 
 | 234 |                     } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) { | 
 | 235 |                         initialTriState = InitialTriState::kAllIn; | 
 | 236 |                         skippable = true; | 
 | 237 |                     } | 
 | 238 |                 } else { | 
 | 239 |                     if (element->contains(relaxedQueryBounds)) { | 
 | 240 |                         initialTriState = InitialTriState::kAllIn; | 
 | 241 |                         skippable = true; | 
 | 242 |                     } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) { | 
 | 243 |                         skippable = true; | 
 | 244 |                     } | 
 | 245 |                 } | 
 | 246 |                 if (!skippable) { | 
 | 247 |                     embiggens = true; | 
 | 248 |                 } | 
 | 249 |                 break; | 
| Mike Reed | c1f7774 | 2016-12-09 09:00:50 -0500 | [diff] [blame] | 250 |             case kXOR_SkClipOp: | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 251 |                 // If the bounds is entirely inside the shape being xor-ed then the effect is | 
 | 252 |                 // to flip the inside/outside state of every point in the bounds. We may be | 
 | 253 |                 // able to take advantage of this in the forward pass. If the xor-ed shape | 
 | 254 |                 // doesn't intersect the bounds then it can be skipped. | 
 | 255 |                 if (element->isInverseFilled()) { | 
 | 256 |                     if (element->contains(relaxedQueryBounds)) { | 
 | 257 |                         skippable = true; | 
 | 258 |                     } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) { | 
 | 259 |                         isFlip = true; | 
 | 260 |                     } | 
 | 261 |                 } else { | 
 | 262 |                     if (element->contains(relaxedQueryBounds)) { | 
 | 263 |                         isFlip = true; | 
 | 264 |                     } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) { | 
 | 265 |                         skippable = true; | 
 | 266 |                     } | 
 | 267 |                 } | 
 | 268 |                 if (!skippable) { | 
 | 269 |                     emsmallens = embiggens = true; | 
 | 270 |                 } | 
 | 271 |                 break; | 
| Mike Reed | c1f7774 | 2016-12-09 09:00:50 -0500 | [diff] [blame] | 272 |             case kReverseDifference_SkClipOp: | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 273 |                 // When the bounds is entirely within the rev-diff shape then this behaves like xor | 
 | 274 |                 // and reverses every point inside the bounds. If the shape is completely outside | 
 | 275 |                 // the bounds then we know after this element is applied that the bounds will be | 
 | 276 |                 // all outside the current clip.B | 
 | 277 |                 if (element->isInverseFilled()) { | 
 | 278 |                     if (element->contains(relaxedQueryBounds)) { | 
 | 279 |                         initialTriState = InitialTriState::kAllOut; | 
 | 280 |                         skippable = true; | 
 | 281 |                     } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) { | 
 | 282 |                         isFlip = true; | 
 | 283 |                     } | 
 | 284 |                 } else { | 
 | 285 |                     if (element->contains(relaxedQueryBounds)) { | 
 | 286 |                         isFlip = true; | 
 | 287 |                     } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) { | 
 | 288 |                         initialTriState = InitialTriState::kAllOut; | 
 | 289 |                         skippable = true; | 
 | 290 |                     } | 
 | 291 |                 } | 
 | 292 |                 if (!skippable) { | 
 | 293 |                     emsmallens = embiggens = true; | 
 | 294 |                 } | 
 | 295 |                 break; | 
 | 296 |  | 
| Mike Reed | c1f7774 | 2016-12-09 09:00:50 -0500 | [diff] [blame] | 297 |             case kReplace_SkClipOp: | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 298 |                 // Replace will always terminate our walk. We will either begin the forward walk | 
 | 299 |                 // at the replace op or detect here than the shape is either completely inside | 
 | 300 |                 // or completely outside the bounds. In this latter case it can be skipped by | 
 | 301 |                 // setting the correct value for initialTriState. | 
 | 302 |                 if (element->isInverseFilled()) { | 
 | 303 |                     if (element->contains(relaxedQueryBounds)) { | 
 | 304 |                         initialTriState = InitialTriState::kAllOut; | 
 | 305 |                         skippable = true; | 
 | 306 |                     } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) { | 
 | 307 |                         initialTriState = InitialTriState::kAllIn; | 
 | 308 |                         skippable = true; | 
 | 309 |                     } | 
 | 310 |                 } else { | 
 | 311 |                     if (element->contains(relaxedQueryBounds)) { | 
 | 312 |                         initialTriState = InitialTriState::kAllIn; | 
 | 313 |                         skippable = true; | 
 | 314 |                     } else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) { | 
 | 315 |                         initialTriState = InitialTriState::kAllOut; | 
 | 316 |                         skippable = true; | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 317 |                     } else if (!embiggens) { | 
 | 318 |                         ClipResult result = this->clipInsideElement(element); | 
 | 319 |                         if (ClipResult::kMadeEmpty == result) { | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 320 |                             return; | 
 | 321 |                         } | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 322 |                         if (ClipResult::kClipped == result) { | 
 | 323 |                             initialTriState = InitialTriState::kAllIn; | 
 | 324 |                             skippable = true; | 
 | 325 |                         } | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 326 |                     } | 
 | 327 |                 } | 
 | 328 |                 if (!skippable) { | 
 | 329 |                     initialTriState = InitialTriState::kAllOut; | 
 | 330 |                     embiggens = emsmallens = true; | 
 | 331 |                 } | 
 | 332 |                 break; | 
 | 333 |             default: | 
 | 334 |                 SkDEBUGFAIL("Unexpected op."); | 
 | 335 |                 break; | 
 | 336 |         } | 
 | 337 |         if (!skippable) { | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 338 |             if (fMaskElements.isEmpty()) { | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 339 |                 // This will be the last element. Record the stricter genID. | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 340 |                 fMaskGenID = element->getGenID(); | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 341 |             } | 
 | 342 |  | 
 | 343 |             // if it is a flip, change it to a bounds-filling rect | 
 | 344 |             if (isFlip) { | 
| Mike Reed | c1f7774 | 2016-12-09 09:00:50 -0500 | [diff] [blame] | 345 |                 SkASSERT(kXOR_SkClipOp == element->getOp() || | 
 | 346 |                          kReverseDifference_SkClipOp == element->getOp()); | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 347 |                 fMaskElements.addToHead(SkRect::Make(fScissor), SkMatrix::I(), | 
 | 348 |                                         kReverseDifference_SkClipOp, false); | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 349 |             } else { | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 350 |                 Element* newElement = fMaskElements.addToHead(*element); | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 351 |                 if (newElement->isAA()) { | 
 | 352 |                     ++numAAElements; | 
 | 353 |                 } | 
 | 354 |                 // Intersecting an inverse shape is the same as differencing the non-inverse shape. | 
 | 355 |                 // Replacing with an inverse shape is the same as setting initialState=kAllIn and | 
 | 356 |                 // differencing the non-inverse shape. | 
| Mike Reed | c1f7774 | 2016-12-09 09:00:50 -0500 | [diff] [blame] | 357 |                 bool isReplace = kReplace_SkClipOp == newElement->getOp(); | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 358 |                 if (newElement->isInverseFilled() && | 
| Mike Reed | c1f7774 | 2016-12-09 09:00:50 -0500 | [diff] [blame] | 359 |                     (kIntersect_SkClipOp == newElement->getOp() || isReplace)) { | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 360 |                     newElement->invertShapeFillType(); | 
| Mike Reed | c1f7774 | 2016-12-09 09:00:50 -0500 | [diff] [blame] | 361 |                     newElement->setOp(kDifference_SkClipOp); | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 362 |                     if (isReplace) { | 
 | 363 |                         SkASSERT(InitialTriState::kAllOut == initialTriState); | 
 | 364 |                         initialTriState = InitialTriState::kAllIn; | 
 | 365 |                     } | 
 | 366 |                 } | 
 | 367 |             } | 
 | 368 |         } | 
 | 369 |     } | 
 | 370 |  | 
 | 371 |     if ((InitialTriState::kAllOut == initialTriState && !embiggens) || | 
 | 372 |         (InitialTriState::kAllIn == initialTriState && !emsmallens)) { | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 373 |         fMaskElements.reset(); | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 374 |         numAAElements = 0; | 
 | 375 |     } else { | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 376 |         Element* element = fMaskElements.headIter().get(); | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 377 |         while (element) { | 
 | 378 |             bool skippable = false; | 
 | 379 |             switch (element->getOp()) { | 
| Mike Reed | c1f7774 | 2016-12-09 09:00:50 -0500 | [diff] [blame] | 380 |                 case kDifference_SkClipOp: | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 381 |                     // subtracting from the empty set yields the empty set. | 
 | 382 |                     skippable = InitialTriState::kAllOut == initialTriState; | 
 | 383 |                     break; | 
| Mike Reed | c1f7774 | 2016-12-09 09:00:50 -0500 | [diff] [blame] | 384 |                 case kIntersect_SkClipOp: | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 385 |                     // intersecting with the empty set yields the empty set | 
 | 386 |                     if (InitialTriState::kAllOut == initialTriState) { | 
 | 387 |                         skippable = true; | 
 | 388 |                     } else { | 
 | 389 |                         // We can clear to zero and then simply draw the clip element. | 
 | 390 |                         initialTriState = InitialTriState::kAllOut; | 
| Mike Reed | c1f7774 | 2016-12-09 09:00:50 -0500 | [diff] [blame] | 391 |                         element->setOp(kReplace_SkClipOp); | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 392 |                     } | 
 | 393 |                     break; | 
| Mike Reed | c1f7774 | 2016-12-09 09:00:50 -0500 | [diff] [blame] | 394 |                 case kUnion_SkClipOp: | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 395 |                     if (InitialTriState::kAllIn == initialTriState) { | 
 | 396 |                         // unioning the infinite plane with anything is a no-op. | 
 | 397 |                         skippable = true; | 
 | 398 |                     } else { | 
 | 399 |                         // unioning the empty set with a shape is the shape. | 
| Mike Reed | c1f7774 | 2016-12-09 09:00:50 -0500 | [diff] [blame] | 400 |                         element->setOp(kReplace_SkClipOp); | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 401 |                     } | 
 | 402 |                     break; | 
| Mike Reed | c1f7774 | 2016-12-09 09:00:50 -0500 | [diff] [blame] | 403 |                 case kXOR_SkClipOp: | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 404 |                     if (InitialTriState::kAllOut == initialTriState) { | 
 | 405 |                         // xor could be changed to diff in the kAllIn case, not sure it's a win. | 
| Mike Reed | c1f7774 | 2016-12-09 09:00:50 -0500 | [diff] [blame] | 406 |                         element->setOp(kReplace_SkClipOp); | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 407 |                     } | 
 | 408 |                     break; | 
| Mike Reed | c1f7774 | 2016-12-09 09:00:50 -0500 | [diff] [blame] | 409 |                 case kReverseDifference_SkClipOp: | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 410 |                     if (InitialTriState::kAllIn == initialTriState) { | 
 | 411 |                         // subtracting the whole plane will yield the empty set. | 
 | 412 |                         skippable = true; | 
 | 413 |                         initialTriState = InitialTriState::kAllOut; | 
 | 414 |                     } else { | 
 | 415 |                         // this picks up flips inserted in the backwards pass. | 
 | 416 |                         skippable = element->isInverseFilled() ? | 
 | 417 |                             GrClip::IsOutsideClip(element->getBounds(), queryBounds) : | 
 | 418 |                             element->contains(relaxedQueryBounds); | 
 | 419 |                         if (skippable) { | 
 | 420 |                             initialTriState = InitialTriState::kAllIn; | 
 | 421 |                         } else { | 
| Mike Reed | c1f7774 | 2016-12-09 09:00:50 -0500 | [diff] [blame] | 422 |                             element->setOp(kReplace_SkClipOp); | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 423 |                         } | 
 | 424 |                     } | 
 | 425 |                     break; | 
| Mike Reed | c1f7774 | 2016-12-09 09:00:50 -0500 | [diff] [blame] | 426 |                 case kReplace_SkClipOp: | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 427 |                     skippable = false; // we would have skipped it in the backwards walk if we | 
 | 428 |                                        // could've. | 
 | 429 |                     break; | 
 | 430 |                 default: | 
 | 431 |                     SkDEBUGFAIL("Unexpected op."); | 
 | 432 |                     break; | 
 | 433 |             } | 
 | 434 |             if (!skippable) { | 
 | 435 |                 break; | 
 | 436 |             } else { | 
 | 437 |                 if (element->isAA()) { | 
 | 438 |                     --numAAElements; | 
 | 439 |                 } | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 440 |                 fMaskElements.popHead(); | 
 | 441 |                 element = fMaskElements.headIter().get(); | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 442 |             } | 
 | 443 |         } | 
 | 444 |     } | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 445 |     fMaskRequiresAA = numAAElements > 0; | 
| csmartdalton | 5ecbbbe | 2016-08-23 13:26:40 -0700 | [diff] [blame] | 446 |  | 
 | 447 |     SkASSERT(InitialTriState::kUnknown != initialTriState); | 
 | 448 |     fInitialState = static_cast<GrReducedClip::InitialState>(initialTriState); | 
 | 449 | } | 
 | 450 |  | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 451 | GrReducedClip::ClipResult GrReducedClip::clipInsideElement(const Element* element) { | 
 | 452 |     SkIRect elementIBounds; | 
 | 453 |     if (!element->isAA()) { | 
 | 454 |         element->getBounds().round(&elementIBounds); | 
 | 455 |     } else { | 
 | 456 |         elementIBounds = GrClip::GetPixelIBounds(element->getBounds()); | 
 | 457 |     } | 
 | 458 |     SkASSERT(fHasScissor); | 
 | 459 |     if (!fScissor.intersect(elementIBounds)) { | 
 | 460 |         this->makeEmpty(); | 
 | 461 |         return ClipResult::kMadeEmpty; | 
 | 462 |     } | 
| csmartdalton | bf4a8f9 | 2016-09-06 10:01:06 -0700 | [diff] [blame] | 463 |  | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 464 |     switch (element->getDeviceSpaceType()) { | 
 | 465 |         case Element::DeviceSpaceType::kEmpty: | 
 | 466 |             return ClipResult::kMadeEmpty; | 
 | 467 |  | 
 | 468 |         case Element::DeviceSpaceType::kRect: | 
 | 469 |             SkASSERT(element->getBounds() == element->getDeviceSpaceRect()); | 
 | 470 |             if (element->isAA()) { | 
 | 471 |                 if (SK_InvalidGenID == fAAClipRectGenID) { // No AA clip rect yet? | 
 | 472 |                     fAAClipRect = element->getDeviceSpaceRect(); | 
 | 473 |                     // fAAClipRectGenID is the value we should use for fMaskGenID if we end up | 
 | 474 |                     // moving the AA clip rect into the mask. The mask GenID is simply the topmost | 
 | 475 |                     // element's GenID. And since we walk the stack backwards, this means it's just | 
 | 476 |                     // the first element we don't skip during our walk. | 
 | 477 |                     fAAClipRectGenID = fMaskElements.isEmpty() ? element->getGenID() : fMaskGenID; | 
 | 478 |                     SkASSERT(SK_InvalidGenID != fAAClipRectGenID); | 
 | 479 |                 } else if (!fAAClipRect.intersect(element->getDeviceSpaceRect())) { | 
 | 480 |                     this->makeEmpty(); | 
 | 481 |                     return ClipResult::kMadeEmpty; | 
 | 482 |                 } | 
 | 483 |             } | 
 | 484 |             return ClipResult::kClipped; | 
 | 485 |  | 
 | 486 |         case Element::DeviceSpaceType::kRRect: | 
| Chris Dalton | 584a79a | 2017-11-15 13:14:01 -0700 | [diff] [blame] | 487 |             return this->addAnalyticFP(element->getDeviceSpaceRRect(), Invert::kNo, | 
| Chris Dalton | 3b51df1 | 2017-11-27 14:33:06 -0700 | [diff] [blame^] | 488 |                                        GrAA(element->isAA())); | 
| Chris Dalton | 584a79a | 2017-11-15 13:14:01 -0700 | [diff] [blame] | 489 |  | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 490 |         case Element::DeviceSpaceType::kPath: | 
| Chris Dalton | 3b51df1 | 2017-11-27 14:33:06 -0700 | [diff] [blame^] | 491 |             return this->addAnalyticFP(element->getDeviceSpacePath(), Invert::kNo, | 
 | 492 |                                        GrAA(element->isAA())); | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 493 |     } | 
 | 494 |  | 
 | 495 |     SK_ABORT("Unexpected DeviceSpaceType"); | 
 | 496 |     return ClipResult::kNotClipped; | 
| csmartdalton | bf4a8f9 | 2016-09-06 10:01:06 -0700 | [diff] [blame] | 497 | } | 
 | 498 |  | 
| Chris Dalton | 584a79a | 2017-11-15 13:14:01 -0700 | [diff] [blame] | 499 | GrReducedClip::ClipResult GrReducedClip::clipOutsideElement(const Element* element) { | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 500 |     switch (element->getDeviceSpaceType()) { | 
 | 501 |         case Element::DeviceSpaceType::kEmpty: | 
 | 502 |             return ClipResult::kMadeEmpty; | 
| csmartdalton | bf4a8f9 | 2016-09-06 10:01:06 -0700 | [diff] [blame] | 503 |  | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 504 |         case Element::DeviceSpaceType::kRect: | 
| Chris Dalton | 584a79a | 2017-11-15 13:14:01 -0700 | [diff] [blame] | 505 |             if (fWindowRects.count() < fMaxWindowRectangles) { | 
 | 506 |                 // Clip out the inside of every rect. We won't be able to entirely skip the AA ones, | 
 | 507 |                 // but it saves processing time. | 
 | 508 |                 this->addWindowRectangle(element->getDeviceSpaceRect(), element->isAA()); | 
 | 509 |                 if (!element->isAA()) { | 
 | 510 |                     return ClipResult::kClipped; | 
 | 511 |                 } | 
 | 512 |             } | 
 | 513 |             return this->addAnalyticFP(element->getDeviceSpaceRect(), Invert::kYes, | 
| Chris Dalton | 3b51df1 | 2017-11-27 14:33:06 -0700 | [diff] [blame^] | 514 |                                        GrAA(element->isAA())); | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 515 |  | 
 | 516 |         case Element::DeviceSpaceType::kRRect: { | 
| Brian Osman | 554c1f0 | 2017-11-16 13:56:47 +0000 | [diff] [blame] | 517 |             const SkRRect& clipRRect = element->getDeviceSpaceRRect(); | 
| Chris Dalton | 3b51df1 | 2017-11-27 14:33:06 -0700 | [diff] [blame^] | 518 |             ClipResult clipResult = this->addAnalyticFP(clipRRect, Invert::kYes, | 
 | 519 |                                                         GrAA(element->isAA())); | 
| Chris Dalton | 584a79a | 2017-11-15 13:14:01 -0700 | [diff] [blame] | 520 |             if (fWindowRects.count() >= fMaxWindowRectangles) { | 
 | 521 |                 return clipResult; | 
 | 522 |             } | 
 | 523 |  | 
 | 524 |             // Clip out the interiors of round rects with two window rectangles in the shape of a | 
 | 525 |             // "plus". This doesn't let us skip the clip element, but still saves processing time. | 
| csmartdalton | bf4a8f9 | 2016-09-06 10:01:06 -0700 | [diff] [blame] | 526 |             SkVector insetTL = clipRRect.radii(SkRRect::kUpperLeft_Corner); | 
 | 527 |             SkVector insetBR = clipRRect.radii(SkRRect::kLowerRight_Corner); | 
 | 528 |             if (SkRRect::kComplex_Type == clipRRect.getType()) { | 
 | 529 |                 const SkVector& insetTR = clipRRect.radii(SkRRect::kUpperRight_Corner); | 
 | 530 |                 const SkVector& insetBL = clipRRect.radii(SkRRect::kLowerLeft_Corner); | 
 | 531 |                 insetTL.fX = SkTMax(insetTL.x(), insetBL.x()); | 
 | 532 |                 insetTL.fY = SkTMax(insetTL.y(), insetTR.y()); | 
 | 533 |                 insetBR.fX = SkTMax(insetBR.x(), insetTR.x()); | 
 | 534 |                 insetBR.fY = SkTMax(insetBR.y(), insetBL.y()); | 
 | 535 |             } | 
 | 536 |             const SkRect& bounds = clipRRect.getBounds(); | 
 | 537 |             if (insetTL.x() + insetBR.x() >= bounds.width() || | 
 | 538 |                 insetTL.y() + insetBR.y() >= bounds.height()) { | 
| Chris Dalton | 584a79a | 2017-11-15 13:14:01 -0700 | [diff] [blame] | 539 |                 return clipResult; // The interior "plus" is empty. | 
| csmartdalton | bf4a8f9 | 2016-09-06 10:01:06 -0700 | [diff] [blame] | 540 |             } | 
 | 541 |  | 
 | 542 |             SkRect horzRect = SkRect::MakeLTRB(bounds.left(), bounds.top() + insetTL.y(), | 
 | 543 |                                                bounds.right(), bounds.bottom() - insetBR.y()); | 
 | 544 |             this->addWindowRectangle(horzRect, element->isAA()); | 
| Chris Dalton | 584a79a | 2017-11-15 13:14:01 -0700 | [diff] [blame] | 545 |  | 
 | 546 |             if (fWindowRects.count() < fMaxWindowRectangles) { | 
 | 547 |                 SkRect vertRect = SkRect::MakeLTRB(bounds.left() + insetTL.x(), bounds.top(), | 
 | 548 |                                                    bounds.right() - insetBR.x(), bounds.bottom()); | 
 | 549 |                 this->addWindowRectangle(vertRect, element->isAA()); | 
| csmartdalton | bf4a8f9 | 2016-09-06 10:01:06 -0700 | [diff] [blame] | 550 |             } | 
 | 551 |  | 
| Chris Dalton | 584a79a | 2017-11-15 13:14:01 -0700 | [diff] [blame] | 552 |             return clipResult; | 
| csmartdalton | bf4a8f9 | 2016-09-06 10:01:06 -0700 | [diff] [blame] | 553 |         } | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 554 |  | 
 | 555 |         case Element::DeviceSpaceType::kPath: | 
| Chris Dalton | 584a79a | 2017-11-15 13:14:01 -0700 | [diff] [blame] | 556 |             return this->addAnalyticFP(element->getDeviceSpacePath(), Invert::kYes, | 
| Chris Dalton | 3b51df1 | 2017-11-27 14:33:06 -0700 | [diff] [blame^] | 557 |                                        GrAA(element->isAA())); | 
| csmartdalton | bf4a8f9 | 2016-09-06 10:01:06 -0700 | [diff] [blame] | 558 |     } | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 559 |  | 
 | 560 |     SK_ABORT("Unexpected DeviceSpaceType"); | 
 | 561 |     return ClipResult::kNotClipped; | 
| csmartdalton | bf4a8f9 | 2016-09-06 10:01:06 -0700 | [diff] [blame] | 562 | } | 
 | 563 |  | 
 | 564 | inline void GrReducedClip::addWindowRectangle(const SkRect& elementInteriorRect, bool elementIsAA) { | 
 | 565 |     SkIRect window; | 
 | 566 |     if (!elementIsAA) { | 
 | 567 |         elementInteriorRect.round(&window); | 
 | 568 |     } else { | 
 | 569 |         elementInteriorRect.roundIn(&window); | 
 | 570 |     } | 
 | 571 |     if (!window.isEmpty()) { // Skip very thin windows that round to zero or negative dimensions. | 
 | 572 |         fWindowRects.addWindow(window); | 
 | 573 |     } | 
 | 574 | } | 
 | 575 |  | 
| Chris Dalton | 584a79a | 2017-11-15 13:14:01 -0700 | [diff] [blame] | 576 | template<typename T> | 
 | 577 | inline GrReducedClip::ClipResult GrReducedClip::addAnalyticFP(const T& deviceSpaceShape, | 
| Chris Dalton | 3b51df1 | 2017-11-27 14:33:06 -0700 | [diff] [blame^] | 578 |                                                               Invert invert, GrAA aa) { | 
| Chris Dalton | 584a79a | 2017-11-15 13:14:01 -0700 | [diff] [blame] | 579 |     if (fAnalyticFPs.count() >= fMaxAnalyticFPs) { | 
 | 580 |         return ClipResult::kNotClipped; | 
 | 581 |     } | 
 | 582 |  | 
 | 583 |     GrClipEdgeType edgeType; | 
 | 584 |     if (Invert::kNo == invert) { | 
| Chris Dalton | 3b51df1 | 2017-11-27 14:33:06 -0700 | [diff] [blame^] | 585 |         edgeType = (GrAA::kYes == aa) ? GrClipEdgeType::kFillAA : GrClipEdgeType::kFillBW; | 
| Chris Dalton | 584a79a | 2017-11-15 13:14:01 -0700 | [diff] [blame] | 586 |     } else { | 
| Chris Dalton | 3b51df1 | 2017-11-27 14:33:06 -0700 | [diff] [blame^] | 587 |         edgeType = (GrAA::kYes == aa) ? GrClipEdgeType::kInverseFillAA | 
 | 588 |                                       : GrClipEdgeType::kInverseFillBW; | 
| Chris Dalton | 584a79a | 2017-11-15 13:14:01 -0700 | [diff] [blame] | 589 |     } | 
 | 590 |  | 
 | 591 |     if (auto fp = make_analytic_clip_fp(edgeType, deviceSpaceShape)) { | 
 | 592 |         fAnalyticFPs.push_back(std::move(fp)); | 
 | 593 |         return ClipResult::kClipped; | 
 | 594 |     } | 
 | 595 |  | 
 | 596 |     return ClipResult::kNotClipped; | 
 | 597 | } | 
 | 598 |  | 
 | 599 | std::unique_ptr<GrFragmentProcessor> make_analytic_clip_fp(GrClipEdgeType edgeType, | 
 | 600 |                                                            const SkRect& deviceSpaceRect) { | 
 | 601 |     return GrConvexPolyEffect::Make(edgeType, deviceSpaceRect); | 
 | 602 | } | 
 | 603 |  | 
 | 604 | std::unique_ptr<GrFragmentProcessor> make_analytic_clip_fp(GrClipEdgeType edgeType, | 
 | 605 |                                                            const SkRRect& deviceSpaceRRect) { | 
 | 606 |     return GrRRectEffect::Make(edgeType, deviceSpaceRRect); | 
 | 607 | } | 
 | 608 |  | 
 | 609 | std::unique_ptr<GrFragmentProcessor> make_analytic_clip_fp(GrClipEdgeType edgeType, | 
 | 610 |                                                            const SkPath& deviceSpacePath) { | 
 | 611 |     return GrConvexPolyEffect::Make(edgeType, deviceSpacePath); | 
 | 612 | } | 
 | 613 |  | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 614 | void GrReducedClip::makeEmpty() { | 
 | 615 |     fHasScissor = false; | 
 | 616 |     fAAClipRectGenID = SK_InvalidGenID; | 
 | 617 |     fWindowRects.reset(); | 
 | 618 |     fMaskElements.reset(); | 
 | 619 |     fInitialState = InitialState::kAllOut; | 
| bsalomon@google.com | 34cd70a | 2012-12-06 14:23:20 +0000 | [diff] [blame] | 620 | } | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 621 |  | 
 | 622 | //////////////////////////////////////////////////////////////////////////////// | 
 | 623 | // Create a 8-bit clip mask in alpha | 
 | 624 |  | 
| Brian Osman | 1105224 | 2016-10-27 14:47:55 -0400 | [diff] [blame] | 625 | static bool stencil_element(GrRenderTargetContext* rtc, | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 626 |                             const GrFixedClip& clip, | 
 | 627 |                             const GrUserStencilSettings* ss, | 
 | 628 |                             const SkMatrix& viewMatrix, | 
 | 629 |                             const SkClipStack::Element* element) { | 
| Chris Dalton | 3b51df1 | 2017-11-27 14:33:06 -0700 | [diff] [blame^] | 630 |     GrAA aa = GrAA(element->isAA()); | 
| Brian Salomon | f3b46e5 | 2017-08-30 11:37:57 -0400 | [diff] [blame] | 631 |     switch (element->getDeviceSpaceType()) { | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 632 |         case SkClipStack::Element::DeviceSpaceType::kEmpty: | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 633 |             SkDEBUGFAIL("Should never get here with an empty element."); | 
 | 634 |             break; | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 635 |         case SkClipStack::Element::DeviceSpaceType::kRect: | 
| Brian Salomon | f3b46e5 | 2017-08-30 11:37:57 -0400 | [diff] [blame] | 636 |             return rtc->priv().drawAndStencilRect(clip, ss, (SkRegion::Op)element->getOp(), | 
| Brian Salomon | 0e8fc8b | 2016-12-09 15:10:07 -0500 | [diff] [blame] | 637 |                                                   element->isInverseFilled(), aa, viewMatrix, | 
| Brian Salomon | f3b46e5 | 2017-08-30 11:37:57 -0400 | [diff] [blame] | 638 |                                                   element->getDeviceSpaceRect()); | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 639 |             break; | 
 | 640 |         default: { | 
 | 641 |             SkPath path; | 
| Brian Salomon | f3b46e5 | 2017-08-30 11:37:57 -0400 | [diff] [blame] | 642 |             element->asDeviceSpacePath(&path); | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 643 |             if (path.isInverseFillType()) { | 
 | 644 |                 path.toggleInverseFillType(); | 
 | 645 |             } | 
 | 646 |  | 
| Brian Salomon | 0e8fc8b | 2016-12-09 15:10:07 -0500 | [diff] [blame] | 647 |             return rtc->priv().drawAndStencilPath(clip, ss, (SkRegion::Op)element->getOp(), | 
 | 648 |                                                   element->isInverseFilled(), aa, viewMatrix, path); | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 649 |             break; | 
 | 650 |         } | 
 | 651 |     } | 
 | 652 |  | 
 | 653 |     return false; | 
 | 654 | } | 
 | 655 |  | 
| Brian Osman | 1105224 | 2016-10-27 14:47:55 -0400 | [diff] [blame] | 656 | static void draw_element(GrRenderTargetContext* rtc, | 
| Brian Salomon | 82f4431 | 2017-01-11 13:42:54 -0500 | [diff] [blame] | 657 |                          const GrClip& clip,  // TODO: can this just always be WideOpen? | 
 | 658 |                          GrPaint&& paint, | 
| Brian Salomon | 0e8fc8b | 2016-12-09 15:10:07 -0500 | [diff] [blame] | 659 |                          GrAA aa, | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 660 |                          const SkMatrix& viewMatrix, | 
 | 661 |                          const SkClipStack::Element* element) { | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 662 |     // TODO: Draw rrects directly here. | 
| Brian Salomon | f3b46e5 | 2017-08-30 11:37:57 -0400 | [diff] [blame] | 663 |     switch (element->getDeviceSpaceType()) { | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 664 |         case SkClipStack::Element::DeviceSpaceType::kEmpty: | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 665 |             SkDEBUGFAIL("Should never get here with an empty element."); | 
 | 666 |             break; | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 667 |         case SkClipStack::Element::DeviceSpaceType::kRect: | 
| Brian Salomon | f3b46e5 | 2017-08-30 11:37:57 -0400 | [diff] [blame] | 668 |             rtc->drawRect(clip, std::move(paint), aa, viewMatrix, element->getDeviceSpaceRect()); | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 669 |             break; | 
 | 670 |         default: { | 
 | 671 |             SkPath path; | 
| Brian Salomon | f3b46e5 | 2017-08-30 11:37:57 -0400 | [diff] [blame] | 672 |             element->asDeviceSpacePath(&path); | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 673 |             if (path.isInverseFillType()) { | 
 | 674 |                 path.toggleInverseFillType(); | 
 | 675 |             } | 
 | 676 |  | 
| Brian Salomon | 82f4431 | 2017-01-11 13:42:54 -0500 | [diff] [blame] | 677 |             rtc->drawPath(clip, std::move(paint), aa, viewMatrix, path, GrStyle::SimpleFill()); | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 678 |             break; | 
 | 679 |         } | 
 | 680 |     } | 
 | 681 | } | 
 | 682 |  | 
| Brian Osman | 1105224 | 2016-10-27 14:47:55 -0400 | [diff] [blame] | 683 | bool GrReducedClip::drawAlphaClipMask(GrRenderTargetContext* rtc) const { | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 684 |     // The texture may be larger than necessary, this rect represents the part of the texture | 
 | 685 |     // we populate with a rasterization of the clip. | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 686 |     GrFixedClip clip(SkIRect::MakeWH(fScissor.width(), fScissor.height())); | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 687 |  | 
| csmartdalton | bf4a8f9 | 2016-09-06 10:01:06 -0700 | [diff] [blame] | 688 |     if (!fWindowRects.empty()) { | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 689 |         clip.setWindowRectangles(fWindowRects.makeOffset(-fScissor.left(), -fScissor.top()), | 
| csmartdalton | bf4a8f9 | 2016-09-06 10:01:06 -0700 | [diff] [blame] | 690 |                                  GrWindowRectsState::Mode::kExclusive); | 
 | 691 |     } | 
 | 692 |  | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 693 |     // The scratch texture that we are drawing into can be substantially larger than the mask. Only | 
 | 694 |     // clear the part that we care about. | 
 | 695 |     GrColor initialCoverage = InitialState::kAllIn == this->initialState() ? -1 : 0; | 
| Brian Osman | 693a540 | 2016-10-27 15:13:22 -0400 | [diff] [blame] | 696 |     rtc->priv().clear(clip, initialCoverage, true); | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 697 |  | 
 | 698 |     // Set the matrix so that rendered clip elements are transformed to mask space from clip space. | 
 | 699 |     SkMatrix translate; | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 700 |     translate.setTranslate(SkIntToScalar(-fScissor.left()), SkIntToScalar(-fScissor.top())); | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 701 |  | 
 | 702 |     // walk through each clip element and perform its set op | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 703 |     for (ElementList::Iter iter(fMaskElements); iter.get(); iter.next()) { | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 704 |         const Element* element = iter.get(); | 
| reed | 73603f3 | 2016-09-20 08:42:38 -0700 | [diff] [blame] | 705 |         SkRegion::Op op = (SkRegion::Op)element->getOp(); | 
| Chris Dalton | 3b51df1 | 2017-11-27 14:33:06 -0700 | [diff] [blame^] | 706 |         GrAA aa = GrAA(element->isAA()); | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 707 |         bool invert = element->isInverseFilled(); | 
 | 708 |         if (invert || SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op == op) { | 
 | 709 |             // draw directly into the result with the stencil set to make the pixels affected | 
 | 710 |             // by the clip shape be non-zero. | 
 | 711 |             static constexpr GrUserStencilSettings kStencilInElement( | 
 | 712 |                  GrUserStencilSettings::StaticInit< | 
 | 713 |                      0xffff, | 
 | 714 |                      GrUserStencilTest::kAlways, | 
 | 715 |                      0xffff, | 
 | 716 |                      GrUserStencilOp::kReplace, | 
 | 717 |                      GrUserStencilOp::kReplace, | 
 | 718 |                      0xffff>() | 
 | 719 |             ); | 
| Brian Osman | 1105224 | 2016-10-27 14:47:55 -0400 | [diff] [blame] | 720 |             if (!stencil_element(rtc, clip, &kStencilInElement, translate, element)) { | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 721 |                 return false; | 
 | 722 |             } | 
 | 723 |  | 
 | 724 |             // Draw to the exterior pixels (those with a zero stencil value). | 
 | 725 |             static constexpr GrUserStencilSettings kDrawOutsideElement( | 
 | 726 |                  GrUserStencilSettings::StaticInit< | 
 | 727 |                      0x0000, | 
 | 728 |                      GrUserStencilTest::kEqual, | 
 | 729 |                      0xffff, | 
 | 730 |                      GrUserStencilOp::kZero, | 
 | 731 |                      GrUserStencilOp::kZero, | 
 | 732 |                      0xffff>() | 
 | 733 |             ); | 
| Brian Salomon | 0e8fc8b | 2016-12-09 15:10:07 -0500 | [diff] [blame] | 734 |             if (!rtc->priv().drawAndStencilRect(clip, &kDrawOutsideElement, op, !invert, GrAA::kNo, | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 735 |                                                 translate, SkRect::Make(fScissor))) { | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 736 |                 return false; | 
 | 737 |             } | 
 | 738 |         } else { | 
 | 739 |             // all the remaining ops can just be directly draw into the accumulation buffer | 
 | 740 |             GrPaint paint; | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 741 |             paint.setCoverageSetOpXPFactory(op, false); | 
 | 742 |  | 
| Brian Salomon | 82f4431 | 2017-01-11 13:42:54 -0500 | [diff] [blame] | 743 |             draw_element(rtc, clip, std::move(paint), aa, translate, element); | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 744 |         } | 
 | 745 |     } | 
 | 746 |  | 
 | 747 |     return true; | 
 | 748 | } | 
 | 749 |  | 
 | 750 | //////////////////////////////////////////////////////////////////////////////// | 
 | 751 | // Create a 1-bit clip mask in the stencil buffer. | 
 | 752 |  | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 753 | bool GrReducedClip::drawStencilClipMask(GrContext* context, | 
| Brian Salomon | 9a76772 | 2017-03-13 17:57:28 -0400 | [diff] [blame] | 754 |                                         GrRenderTargetContext* renderTargetContext) const { | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 755 |     // We set the current clip to the bounds so that our recursive draws are scissored to them. | 
| Chris Dalton | bbfd516 | 2017-11-07 13:35:22 -0700 | [diff] [blame] | 756 |     GrStencilClip stencilClip(fScissor, this->maskGenID()); | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 757 |  | 
| csmartdalton | bf4a8f9 | 2016-09-06 10:01:06 -0700 | [diff] [blame] | 758 |     if (!fWindowRects.empty()) { | 
| Chris Dalton | bbfd516 | 2017-11-07 13:35:22 -0700 | [diff] [blame] | 759 |         stencilClip.fixedClip().setWindowRectangles(fWindowRects, | 
 | 760 |                                                     GrWindowRectsState::Mode::kExclusive); | 
| csmartdalton | bf4a8f9 | 2016-09-06 10:01:06 -0700 | [diff] [blame] | 761 |     } | 
 | 762 |  | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 763 |     bool initialState = InitialState::kAllIn == this->initialState(); | 
| Jim Van Verth | 6a40abc | 2017-11-02 16:56:09 +0000 | [diff] [blame] | 764 |     renderTargetContext->priv().clearStencilClip(stencilClip.fixedClip(), initialState); | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 765 |  | 
| Brian Salomon | 0e8fc8b | 2016-12-09 15:10:07 -0500 | [diff] [blame] | 766 |     // walk through each clip element and perform its set op with the existing clip. | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 767 |     for (ElementList::Iter iter(fMaskElements); iter.get(); iter.next()) { | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 768 |         const Element* element = iter.get(); | 
| Brian Salomon | 0e8fc8b | 2016-12-09 15:10:07 -0500 | [diff] [blame] | 769 |         GrAAType aaType = GrAAType::kNone; | 
| Brian Salomon | 7c8460e | 2017-05-12 11:36:10 -0400 | [diff] [blame] | 770 |         if (element->isAA() && GrFSAAType::kNone != renderTargetContext->fsaaType()) { | 
| Brian Salomon | 0e8fc8b | 2016-12-09 15:10:07 -0500 | [diff] [blame] | 771 |             aaType = GrAAType::kMSAA; | 
 | 772 |         } | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 773 |  | 
 | 774 |         bool fillInverted = false; | 
 | 775 |  | 
 | 776 |         // This will be used to determine whether the clip shape can be rendered into the | 
 | 777 |         // stencil with arbitrary stencil settings. | 
 | 778 |         GrPathRenderer::StencilSupport stencilSupport; | 
 | 779 |  | 
| reed | 73603f3 | 2016-09-20 08:42:38 -0700 | [diff] [blame] | 780 |         SkRegion::Op op = (SkRegion::Op)element->getOp(); | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 781 |  | 
 | 782 |         GrPathRenderer* pr = nullptr; | 
 | 783 |         SkPath clipPath; | 
| Brian Salomon | f3b46e5 | 2017-08-30 11:37:57 -0400 | [diff] [blame] | 784 |         if (Element::DeviceSpaceType::kRect == element->getDeviceSpaceType()) { | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 785 |             stencilSupport = GrPathRenderer::kNoRestriction_StencilSupport; | 
 | 786 |             fillInverted = false; | 
 | 787 |         } else { | 
| Brian Salomon | f3b46e5 | 2017-08-30 11:37:57 -0400 | [diff] [blame] | 788 |             element->asDeviceSpacePath(&clipPath); | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 789 |             fillInverted = clipPath.isInverseFillType(); | 
 | 790 |             if (fillInverted) { | 
 | 791 |                 clipPath.toggleInverseFillType(); | 
 | 792 |             } | 
 | 793 |  | 
 | 794 |             GrShape shape(clipPath, GrStyle::SimpleFill()); | 
 | 795 |             GrPathRenderer::CanDrawPathArgs canDrawArgs; | 
| Eric Karl | 5c77975 | 2017-05-08 12:02:07 -0700 | [diff] [blame] | 796 |             canDrawArgs.fCaps = context->caps(); | 
| Chris Dalton | db91c6e | 2017-09-08 16:25:08 -0600 | [diff] [blame] | 797 |             canDrawArgs.fClipConservativeBounds = &stencilClip.fixedClip().scissorRect(); | 
| Brian Salomon | 9a76772 | 2017-03-13 17:57:28 -0400 | [diff] [blame] | 798 |             canDrawArgs.fViewMatrix = &SkMatrix::I(); | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 799 |             canDrawArgs.fShape = &shape; | 
| Brian Salomon | 0e8fc8b | 2016-12-09 15:10:07 -0500 | [diff] [blame] | 800 |             canDrawArgs.fAAType = aaType; | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 801 |             canDrawArgs.fHasUserStencilSettings = false; | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 802 |  | 
 | 803 |             GrDrawingManager* dm = context->contextPriv().drawingManager(); | 
| Brian Salomon | 82125e9 | 2016-12-10 09:35:48 -0500 | [diff] [blame] | 804 |             pr = dm->getPathRenderer(canDrawArgs, false, GrPathRendererChain::DrawType::kStencil, | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 805 |                                      &stencilSupport); | 
 | 806 |             if (!pr) { | 
 | 807 |                 return false; | 
 | 808 |             } | 
 | 809 |         } | 
 | 810 |  | 
 | 811 |         bool canRenderDirectToStencil = | 
 | 812 |             GrPathRenderer::kNoRestriction_StencilSupport == stencilSupport; | 
 | 813 |         bool drawDirectToClip; // Given the renderer, the element, | 
 | 814 |                                // fill rule, and set operation should | 
 | 815 |                                // we render the element directly to | 
 | 816 |                                // stencil bit used for clipping. | 
 | 817 |         GrUserStencilSettings const* const* stencilPasses = | 
 | 818 |             GrStencilSettings::GetClipPasses(op, canRenderDirectToStencil, fillInverted, | 
 | 819 |                                              &drawDirectToClip); | 
 | 820 |  | 
 | 821 |         // draw the element to the client stencil bits if necessary | 
 | 822 |         if (!drawDirectToClip) { | 
 | 823 |             static constexpr GrUserStencilSettings kDrawToStencil( | 
 | 824 |                  GrUserStencilSettings::StaticInit< | 
 | 825 |                      0x0000, | 
 | 826 |                      GrUserStencilTest::kAlways, | 
 | 827 |                      0xffff, | 
 | 828 |                      GrUserStencilOp::kIncMaybeClamp, | 
 | 829 |                      GrUserStencilOp::kIncMaybeClamp, | 
 | 830 |                      0xffff>() | 
 | 831 |             ); | 
| Brian Salomon | f3b46e5 | 2017-08-30 11:37:57 -0400 | [diff] [blame] | 832 |             if (Element::DeviceSpaceType::kRect == element->getDeviceSpaceType()) { | 
| Brian Osman | 693a540 | 2016-10-27 15:13:22 -0400 | [diff] [blame] | 833 |                 renderTargetContext->priv().stencilRect(stencilClip.fixedClip(), &kDrawToStencil, | 
| Brian Salomon | f3b46e5 | 2017-08-30 11:37:57 -0400 | [diff] [blame] | 834 |                                                         aaType, SkMatrix::I(), | 
 | 835 |                                                         element->getDeviceSpaceRect()); | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 836 |             } else { | 
 | 837 |                 if (!clipPath.isEmpty()) { | 
 | 838 |                     GrShape shape(clipPath, GrStyle::SimpleFill()); | 
 | 839 |                     if (canRenderDirectToStencil) { | 
 | 840 |                         GrPaint paint; | 
| Brian Salomon | a163392 | 2017-01-09 11:46:10 -0500 | [diff] [blame] | 841 |                         paint.setXPFactory(GrDisableColorXPFactory::Get()); | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 842 |  | 
| Robert Phillips | 256c37b | 2017-03-01 14:32:46 -0500 | [diff] [blame] | 843 |                         GrPathRenderer::DrawPathArgs args{context, | 
| Brian Salomon | 82f4431 | 2017-01-11 13:42:54 -0500 | [diff] [blame] | 844 |                                                           std::move(paint), | 
 | 845 |                                                           &kDrawToStencil, | 
 | 846 |                                                           renderTargetContext, | 
 | 847 |                                                           &stencilClip.fixedClip(), | 
| Chris Dalton | db91c6e | 2017-09-08 16:25:08 -0600 | [diff] [blame] | 848 |                                                           &stencilClip.fixedClip().scissorRect(), | 
| Brian Salomon | 9a76772 | 2017-03-13 17:57:28 -0400 | [diff] [blame] | 849 |                                                           &SkMatrix::I(), | 
| Brian Salomon | 82f4431 | 2017-01-11 13:42:54 -0500 | [diff] [blame] | 850 |                                                           &shape, | 
 | 851 |                                                           aaType, | 
 | 852 |                                                           false}; | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 853 |                         pr->drawPath(args); | 
 | 854 |                     } else { | 
 | 855 |                         GrPathRenderer::StencilPathArgs args; | 
| Robert Phillips | 256c37b | 2017-03-01 14:32:46 -0500 | [diff] [blame] | 856 |                         args.fContext = context; | 
| Brian Osman | 1105224 | 2016-10-27 14:47:55 -0400 | [diff] [blame] | 857 |                         args.fRenderTargetContext = renderTargetContext; | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 858 |                         args.fClip = &stencilClip.fixedClip(); | 
| Chris Dalton | db91c6e | 2017-09-08 16:25:08 -0600 | [diff] [blame] | 859 |                         args.fClipConservativeBounds = &stencilClip.fixedClip().scissorRect(); | 
| Brian Salomon | 9a76772 | 2017-03-13 17:57:28 -0400 | [diff] [blame] | 860 |                         args.fViewMatrix = &SkMatrix::I(); | 
| Brian Salomon | 0e8fc8b | 2016-12-09 15:10:07 -0500 | [diff] [blame] | 861 |                         args.fAAType = aaType; | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 862 |                         args.fShape = &shape; | 
 | 863 |                         pr->stencilPath(args); | 
 | 864 |                     } | 
 | 865 |                 } | 
 | 866 |             } | 
 | 867 |         } | 
 | 868 |  | 
 | 869 |         // now we modify the clip bit by rendering either the clip | 
 | 870 |         // element directly or a bounding rect of the entire clip. | 
 | 871 |         for (GrUserStencilSettings const* const* pass = stencilPasses; *pass; ++pass) { | 
 | 872 |             if (drawDirectToClip) { | 
| Brian Salomon | f3b46e5 | 2017-08-30 11:37:57 -0400 | [diff] [blame] | 873 |                 if (Element::DeviceSpaceType::kRect == element->getDeviceSpaceType()) { | 
| Brian Salomon | 9a76772 | 2017-03-13 17:57:28 -0400 | [diff] [blame] | 874 |                     renderTargetContext->priv().stencilRect(stencilClip, *pass, aaType, | 
| Brian Salomon | f3b46e5 | 2017-08-30 11:37:57 -0400 | [diff] [blame] | 875 |                                                             SkMatrix::I(), | 
 | 876 |                                                             element->getDeviceSpaceRect()); | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 877 |                 } else { | 
 | 878 |                     GrShape shape(clipPath, GrStyle::SimpleFill()); | 
 | 879 |                     GrPaint paint; | 
| Brian Salomon | a163392 | 2017-01-09 11:46:10 -0500 | [diff] [blame] | 880 |                     paint.setXPFactory(GrDisableColorXPFactory::Get()); | 
| Robert Phillips | 256c37b | 2017-03-01 14:32:46 -0500 | [diff] [blame] | 881 |                     GrPathRenderer::DrawPathArgs args{context, | 
| Brian Salomon | 82f4431 | 2017-01-11 13:42:54 -0500 | [diff] [blame] | 882 |                                                       std::move(paint), | 
 | 883 |                                                       *pass, | 
 | 884 |                                                       renderTargetContext, | 
 | 885 |                                                       &stencilClip, | 
| Chris Dalton | db91c6e | 2017-09-08 16:25:08 -0600 | [diff] [blame] | 886 |                                                       &stencilClip.fixedClip().scissorRect(), | 
| Brian Salomon | 9a76772 | 2017-03-13 17:57:28 -0400 | [diff] [blame] | 887 |                                                       &SkMatrix::I(), | 
| Brian Salomon | 82f4431 | 2017-01-11 13:42:54 -0500 | [diff] [blame] | 888 |                                                       &shape, | 
 | 889 |                                                       aaType, | 
 | 890 |                                                       false}; | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 891 |                     pr->drawPath(args); | 
 | 892 |                 } | 
 | 893 |             } else { | 
 | 894 |                 // The view matrix is setup to do clip space -> stencil space translation, so | 
 | 895 |                 // draw rect in clip space. | 
| Brian Salomon | 9a76772 | 2017-03-13 17:57:28 -0400 | [diff] [blame] | 896 |                 renderTargetContext->priv().stencilRect(stencilClip, *pass, aaType, SkMatrix::I(), | 
| Chris Dalton | 7947193 | 2017-10-27 01:50:57 -0600 | [diff] [blame] | 897 |                                                         SkRect::Make(fScissor)); | 
| csmartdalton | bde96c6 | 2016-08-31 12:54:46 -0700 | [diff] [blame] | 898 |             } | 
 | 899 |         } | 
 | 900 |     } | 
 | 901 |     return true; | 
 | 902 | } |