| OLD | NEW |
| 1 | 1 |
| 2 /* | 2 /* |
| 3 * Copyright 2008 The Android Open Source Project | 3 * Copyright 2008 The Android Open Source Project |
| 4 * | 4 * |
| 5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
| 6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
| 7 */ | 7 */ |
| 8 | 8 |
| 9 | 9 |
| 10 #include "SkCanvas.h" | 10 #include "SkCanvas.h" |
| (...skipping 1129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1140 void SkCanvas::resetMatrix() { | 1140 void SkCanvas::resetMatrix() { |
| 1141 SkMatrix matrix; | 1141 SkMatrix matrix; |
| 1142 | 1142 |
| 1143 matrix.reset(); | 1143 matrix.reset(); |
| 1144 this->setMatrix(matrix); | 1144 this->setMatrix(matrix); |
| 1145 } | 1145 } |
| 1146 | 1146 |
| 1147 ////////////////////////////////////////////////////////////////////////////// | 1147 ////////////////////////////////////////////////////////////////////////////// |
| 1148 | 1148 |
| 1149 bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { | 1149 bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { |
| 1150 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; |
| 1151 this->onClipRect(rect, op, edgeStyle); |
| 1152 return !this->isClipEmpty(); |
| 1153 } |
| 1154 |
| 1155 void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edg
eStyle) { |
| 1150 #ifdef SK_ENABLE_CLIP_QUICKREJECT | 1156 #ifdef SK_ENABLE_CLIP_QUICKREJECT |
| 1151 if (SkRegion::kIntersect_Op == op) { | 1157 if (SkRegion::kIntersect_Op == op) { |
| 1152 if (fMCRec->fRasterClip->isEmpty()) { | 1158 if (fMCRec->fRasterClip->isEmpty()) { |
| 1153 return false; | 1159 return false; |
| 1154 } | 1160 } |
| 1155 | 1161 |
| 1156 if (this->quickReject(rect)) { | 1162 if (this->quickReject(rect)) { |
| 1157 fDeviceCMDirty = true; | 1163 fDeviceCMDirty = true; |
| 1158 fCachedLocalClipBoundsDirty = true; | 1164 fCachedLocalClipBoundsDirty = true; |
| 1159 | 1165 |
| 1160 fClipStack.clipEmpty(); | 1166 fClipStack.clipEmpty(); |
| 1161 return fMCRec->fRasterClip->setEmpty(); | 1167 return fMCRec->fRasterClip->setEmpty(); |
| 1162 } | 1168 } |
| 1163 } | 1169 } |
| 1164 #endif | 1170 #endif |
| 1165 | 1171 |
| 1166 AutoValidateClip avc(this); | 1172 AutoValidateClip avc(this); |
| 1167 | 1173 |
| 1168 fDeviceCMDirty = true; | 1174 fDeviceCMDirty = true; |
| 1169 fCachedLocalClipBoundsDirty = true; | 1175 fCachedLocalClipBoundsDirty = true; |
| 1170 doAA &= fAllowSoftClip; | 1176 if (!fAllowSoftClip) { |
| 1177 edgeStyle = kHard_ClipEdgeStyle; |
| 1178 } |
| 1171 | 1179 |
| 1172 if (fMCRec->fMatrix->rectStaysRect()) { | 1180 if (fMCRec->fMatrix->rectStaysRect()) { |
| 1173 // for these simpler matrices, we can stay a rect even after applying | 1181 // for these simpler matrices, we can stay a rect even after applying |
| 1174 // the matrix. This means we don't have to a) make a path, and b) tell | 1182 // the matrix. This means we don't have to a) make a path, and b) tell |
| 1175 // the region code to scan-convert the path, only to discover that it | 1183 // the region code to scan-convert the path, only to discover that it |
| 1176 // is really just a rect. | 1184 // is really just a rect. |
| 1177 SkRect r; | 1185 SkRect r; |
| 1178 | 1186 |
| 1179 fMCRec->fMatrix->mapRect(&r, rect); | 1187 fMCRec->fMatrix->mapRect(&r, rect); |
| 1180 fClipStack.clipDevRect(r, op, doAA); | 1188 fClipStack.clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle); |
| 1181 return fMCRec->fRasterClip->op(r, op, doAA); | 1189 fMCRec->fRasterClip->op(r, op, kSoft_ClipEdgeStyle == edgeStyle); |
| 1182 } else { | 1190 } else { |
| 1183 // since we're rotated or some such thing, we convert the rect to a path | 1191 // since we're rotated or some such thing, we convert the rect to a path |
| 1184 // and clip against that, since it can handle any matrix. However, to | 1192 // and clip against that, since it can handle any matrix. However, to |
| 1185 // avoid recursion in the case where we are subclassed (e.g. Pictures) | 1193 // avoid recursion in the case where we are subclassed (e.g. Pictures) |
| 1186 // we explicitly call "our" version of clipPath. | 1194 // we explicitly call "our" version of clipPath. |
| 1187 SkPath path; | 1195 SkPath path; |
| 1188 | 1196 |
| 1189 path.addRect(rect); | 1197 path.addRect(rect); |
| 1190 return this->SkCanvas::clipPath(path, op, doAA); | 1198 this->SkCanvas::onClipPath(path, op, edgeStyle); |
| 1191 } | 1199 } |
| 1192 } | 1200 } |
| 1193 | 1201 |
| 1194 static bool clipPathHelper(const SkCanvas* canvas, SkRasterClip* currClip, | 1202 static void clip_path_helper(const SkCanvas* canvas, SkRasterClip* currClip, |
| 1195 const SkPath& devPath, SkRegion::Op op, bool doAA) { | 1203 const SkPath& devPath, SkRegion::Op op, bool doAA)
{ |
| 1196 // base is used to limit the size (and therefore memory allocation) of the | 1204 // base is used to limit the size (and therefore memory allocation) of the |
| 1197 // region that results from scan converting devPath. | 1205 // region that results from scan converting devPath. |
| 1198 SkRegion base; | 1206 SkRegion base; |
| 1199 | 1207 |
| 1200 if (SkRegion::kIntersect_Op == op) { | 1208 if (SkRegion::kIntersect_Op == op) { |
| 1201 // since we are intersect, we can do better (tighter) with currRgn's | 1209 // since we are intersect, we can do better (tighter) with currRgn's |
| 1202 // bounds, than just using the device. However, if currRgn is complex, | 1210 // bounds, than just using the device. However, if currRgn is complex, |
| 1203 // our region blitter may hork, so we do that case in two steps. | 1211 // our region blitter may hork, so we do that case in two steps. |
| 1204 if (currClip->isRect()) { | 1212 if (currClip->isRect()) { |
| 1205 // FIXME: we should also be able to do this when currClip->isBW(), | 1213 // FIXME: we should also be able to do this when currClip->isBW(), |
| 1206 // but relaxing the test above triggers GM asserts in | 1214 // but relaxing the test above triggers GM asserts in |
| 1207 // SkRgnBuilder::blitH(). We need to investigate what's going on. | 1215 // SkRgnBuilder::blitH(). We need to investigate what's going on. |
| 1208 return currClip->setPath(devPath, currClip->bwRgn(), doAA); | 1216 currClip->setPath(devPath, currClip->bwRgn(), doAA); |
| 1209 } else { | 1217 } else { |
| 1210 base.setRect(currClip->getBounds()); | 1218 base.setRect(currClip->getBounds()); |
| 1211 SkRasterClip clip; | 1219 SkRasterClip clip; |
| 1212 clip.setPath(devPath, base, doAA); | 1220 clip.setPath(devPath, base, doAA); |
| 1213 return currClip->op(clip, op); | 1221 currClip->op(clip, op); |
| 1214 } | 1222 } |
| 1215 } else { | 1223 } else { |
| 1216 const SkBaseDevice* device = canvas->getDevice(); | 1224 const SkBaseDevice* device = canvas->getDevice(); |
| 1217 if (!device) { | 1225 if (!device) { |
| 1218 return currClip->setEmpty(); | 1226 currClip->setEmpty(); |
| 1227 return; |
| 1219 } | 1228 } |
| 1220 | 1229 |
| 1221 base.setRect(0, 0, device->width(), device->height()); | 1230 base.setRect(0, 0, device->width(), device->height()); |
| 1222 | 1231 |
| 1223 if (SkRegion::kReplace_Op == op) { | 1232 if (SkRegion::kReplace_Op == op) { |
| 1224 return currClip->setPath(devPath, base, doAA); | 1233 currClip->setPath(devPath, base, doAA); |
| 1225 } else { | 1234 } else { |
| 1226 SkRasterClip clip; | 1235 SkRasterClip clip; |
| 1227 clip.setPath(devPath, base, doAA); | 1236 clip.setPath(devPath, base, doAA); |
| 1228 return currClip->op(clip, op); | 1237 currClip->op(clip, op); |
| 1229 } | 1238 } |
| 1230 } | 1239 } |
| 1231 } | 1240 } |
| 1232 | 1241 |
| 1233 bool SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { | 1242 bool SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { |
| 1243 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; |
| 1234 if (rrect.isRect()) { | 1244 if (rrect.isRect()) { |
| 1235 // call the non-virtual version | 1245 this->onClipRect(rrect.getBounds(), op, edgeStyle); |
| 1236 return this->SkCanvas::clipRect(rrect.getBounds(), op, doAA); | 1246 } else { |
| 1247 this->onClipRRect(rrect, op, edgeStyle); |
| 1237 } | 1248 } |
| 1249 return !this->isClipEmpty(); |
| 1250 } |
| 1238 | 1251 |
| 1252 void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle
edgeStyle) { |
| 1239 SkRRect transformedRRect; | 1253 SkRRect transformedRRect; |
| 1240 if (rrect.transform(*fMCRec->fMatrix, &transformedRRect)) { | 1254 if (rrect.transform(*fMCRec->fMatrix, &transformedRRect)) { |
| 1241 AutoValidateClip avc(this); | 1255 AutoValidateClip avc(this); |
| 1242 | 1256 |
| 1243 fDeviceCMDirty = true; | 1257 fDeviceCMDirty = true; |
| 1244 fCachedLocalClipBoundsDirty = true; | 1258 fCachedLocalClipBoundsDirty = true; |
| 1245 doAA &= fAllowSoftClip; | 1259 if (!fAllowSoftClip) { |
| 1260 edgeStyle = kHard_ClipEdgeStyle; |
| 1261 } |
| 1246 | 1262 |
| 1247 fClipStack.clipDevRRect(transformedRRect, op, doAA); | 1263 fClipStack.clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edg
eStyle); |
| 1248 | 1264 |
| 1249 SkPath devPath; | 1265 SkPath devPath; |
| 1250 devPath.addRRect(transformedRRect); | 1266 devPath.addRRect(transformedRRect); |
| 1251 | 1267 |
| 1252 return clipPathHelper(this, fMCRec->fRasterClip, devPath, op, doAA); | 1268 clip_path_helper(this, fMCRec->fRasterClip, devPath, op, kSoft_ClipEdgeS
tyle == edgeStyle); |
| 1269 return; |
| 1253 } | 1270 } |
| 1254 | 1271 |
| 1255 SkPath path; | 1272 SkPath path; |
| 1256 path.addRRect(rrect); | 1273 path.addRRect(rrect); |
| 1257 // call the non-virtual version | 1274 // call the non-virtual version |
| 1258 return this->SkCanvas::clipPath(path, op, doAA); | 1275 this->SkCanvas::onClipPath(path, op, edgeStyle); |
| 1259 } | 1276 } |
| 1260 | 1277 |
| 1261 bool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { | 1278 bool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { |
| 1279 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; |
| 1280 SkRect r; |
| 1281 if (!path.isInverseFillType() && path.isRect(&r)) { |
| 1282 this->onClipRect(r, op, edgeStyle); |
| 1283 } else { |
| 1284 this->onClipPath(path, op, edgeStyle); |
| 1285 } |
| 1286 |
| 1287 return !this->isClipEmpty(); |
| 1288 } |
| 1289 |
| 1290 void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edg
eStyle) { |
| 1262 #ifdef SK_ENABLE_CLIP_QUICKREJECT | 1291 #ifdef SK_ENABLE_CLIP_QUICKREJECT |
| 1263 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) { | 1292 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) { |
| 1264 if (fMCRec->fRasterClip->isEmpty()) { | 1293 if (fMCRec->fRasterClip->isEmpty()) { |
| 1265 return false; | 1294 return false; |
| 1266 } | 1295 } |
| 1267 | 1296 |
| 1268 if (this->quickReject(path.getBounds())) { | 1297 if (this->quickReject(path.getBounds())) { |
| 1269 fDeviceCMDirty = true; | 1298 fDeviceCMDirty = true; |
| 1270 fCachedLocalClipBoundsDirty = true; | 1299 fCachedLocalClipBoundsDirty = true; |
| 1271 | 1300 |
| 1272 fClipStack.clipEmpty(); | 1301 fClipStack.clipEmpty(); |
| 1273 return fMCRec->fRasterClip->setEmpty(); | 1302 return fMCRec->fRasterClip->setEmpty(); |
| 1274 } | 1303 } |
| 1275 } | 1304 } |
| 1276 #endif | 1305 #endif |
| 1277 | 1306 |
| 1278 AutoValidateClip avc(this); | 1307 AutoValidateClip avc(this); |
| 1279 | 1308 |
| 1280 fDeviceCMDirty = true; | 1309 fDeviceCMDirty = true; |
| 1281 fCachedLocalClipBoundsDirty = true; | 1310 fCachedLocalClipBoundsDirty = true; |
| 1282 doAA &= fAllowSoftClip; | 1311 if (!fAllowSoftClip) { |
| 1312 edgeStyle = kHard_ClipEdgeStyle; |
| 1313 } |
| 1283 | 1314 |
| 1284 SkPath devPath; | 1315 SkPath devPath; |
| 1285 path.transform(*fMCRec->fMatrix, &devPath); | 1316 path.transform(*fMCRec->fMatrix, &devPath); |
| 1286 | 1317 |
| 1287 // Check if the transfomation, or the original path itself | 1318 // Check if the transfomation, or the original path itself |
| 1288 // made us empty. Note this can also happen if we contained NaN | 1319 // made us empty. Note this can also happen if we contained NaN |
| 1289 // values. computing the bounds detects this, and will set our | 1320 // values. computing the bounds detects this, and will set our |
| 1290 // bounds to empty if that is the case. (see SkRect::set(pts, count)) | 1321 // bounds to empty if that is the case. (see SkRect::set(pts, count)) |
| 1291 if (devPath.getBounds().isEmpty()) { | 1322 if (devPath.getBounds().isEmpty()) { |
| 1292 // resetting the path will remove any NaN or other wanky values | 1323 // resetting the path will remove any NaN or other wanky values |
| 1293 // that might upset our scan converter. | 1324 // that might upset our scan converter. |
| 1294 devPath.reset(); | 1325 devPath.reset(); |
| 1295 } | 1326 } |
| 1296 | 1327 |
| 1297 // if we called path.swap() we could avoid a deep copy of this path | 1328 // if we called path.swap() we could avoid a deep copy of this path |
| 1298 fClipStack.clipDevPath(devPath, op, doAA); | 1329 fClipStack.clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle); |
| 1299 | 1330 |
| 1300 if (fAllowSimplifyClip) { | 1331 if (fAllowSimplifyClip) { |
| 1301 devPath.reset(); | 1332 devPath.reset(); |
| 1302 devPath.setFillType(SkPath::kInverseEvenOdd_FillType); | 1333 devPath.setFillType(SkPath::kInverseEvenOdd_FillType); |
| 1303 const SkClipStack* clipStack = getClipStack(); | 1334 const SkClipStack* clipStack = getClipStack(); |
| 1304 SkClipStack::Iter iter(*clipStack, SkClipStack::Iter::kBottom_IterStart)
; | 1335 SkClipStack::Iter iter(*clipStack, SkClipStack::Iter::kBottom_IterStart)
; |
| 1305 const SkClipStack::Element* element; | 1336 const SkClipStack::Element* element; |
| 1306 while ((element = iter.next())) { | 1337 while ((element = iter.next())) { |
| 1307 SkClipStack::Element::Type type = element->getType(); | 1338 SkClipStack::Element::Type type = element->getType(); |
| 1308 if (type == SkClipStack::Element::kEmpty_Type) { | 1339 if (type == SkClipStack::Element::kEmpty_Type) { |
| 1309 continue; | 1340 continue; |
| 1310 } | 1341 } |
| 1311 SkPath operand; | 1342 SkPath operand; |
| 1312 element->asPath(&operand); | 1343 element->asPath(&operand); |
| 1313 SkRegion::Op elementOp = element->getOp(); | 1344 SkRegion::Op elementOp = element->getOp(); |
| 1314 if (elementOp == SkRegion::kReplace_Op) { | 1345 if (elementOp == SkRegion::kReplace_Op) { |
| 1315 devPath = operand; | 1346 devPath = operand; |
| 1316 } else { | 1347 } else { |
| 1317 Op(devPath, operand, (SkPathOp) elementOp, &devPath); | 1348 Op(devPath, operand, (SkPathOp) elementOp, &devPath); |
| 1318 } | 1349 } |
| 1319 // if the prev and curr clips disagree about aa -vs- not, favor the
aa request. | 1350 // if the prev and curr clips disagree about aa -vs- not, favor the
aa request. |
| 1320 // perhaps we need an API change to avoid this sort of mixed-signals
about | 1351 // perhaps we need an API change to avoid this sort of mixed-signals
about |
| 1321 // clipping. | 1352 // clipping. |
| 1322 doAA |= element->isAA(); | 1353 if (element->isAA()) { |
| 1354 edgeStyle = kSoft_ClipEdgeStyle; |
| 1355 } |
| 1323 } | 1356 } |
| 1324 op = SkRegion::kReplace_Op; | 1357 op = SkRegion::kReplace_Op; |
| 1325 } | 1358 } |
| 1326 | 1359 |
| 1327 return clipPathHelper(this, fMCRec->fRasterClip, devPath, op, doAA); | 1360 clip_path_helper(this, fMCRec->fRasterClip, devPath, op, edgeStyle); |
| 1328 } | 1361 } |
| 1329 | 1362 |
| 1330 bool SkCanvas::updateClipConservativelyUsingBounds(const SkRect& bounds, SkRegio
n::Op op, | 1363 void SkCanvas::updateClipConservativelyUsingBounds(const SkRect& bounds, SkRegio
n::Op op, |
| 1331 bool inverseFilled) { | 1364 bool inverseFilled) { |
| 1332 // This is for updating the clip conservatively using only bounds | 1365 // This is for updating the clip conservatively using only bounds |
| 1333 // information. | 1366 // information. |
| 1334 // Contract: | 1367 // Contract: |
| 1335 // The current clip must contain the true clip. The true | 1368 // The current clip must contain the true clip. The true |
| 1336 // clip is the clip that would have normally been computed | 1369 // clip is the clip that would have normally been computed |
| 1337 // by calls to clipPath and clipRRect | 1370 // by calls to clipPath and clipRRect |
| 1338 // Objective: | 1371 // Objective: |
| 1339 // Keep the current clip as small as possible without | 1372 // Keep the current clip as small as possible without |
| 1340 // breaking the contract, using only clip bounding rectangles | 1373 // breaking the contract, using only clip bounding rectangles |
| 1341 // (for performance). | 1374 // (for performance). |
| 1342 | 1375 |
| 1343 // N.B.: This *never* calls back through a virtual on canvas, so subclasses | 1376 // N.B.: This *never* calls back through a virtual on canvas, so subclasses |
| 1344 // don't have to worry about getting caught in a loop. Thus anywhere | 1377 // don't have to worry about getting caught in a loop. Thus anywhere |
| 1345 // we call a virtual method, we explicitly prefix it with | 1378 // we call a virtual method, we explicitly prefix it with |
| 1346 // SkCanvas:: to be sure to call the base-class. | 1379 // SkCanvas:: to be sure to call the base-class. |
| 1347 | 1380 |
| 1348 if (inverseFilled) { | 1381 if (inverseFilled) { |
| 1349 switch (op) { | 1382 switch (op) { |
| 1350 case SkRegion::kIntersect_Op: | 1383 case SkRegion::kIntersect_Op: |
| 1351 case SkRegion::kDifference_Op: | 1384 case SkRegion::kDifference_Op: |
| 1352 // These ops can only shrink the current clip. So leaving | 1385 // These ops can only shrink the current clip. So leaving |
| 1353 // the clip unchanges conservatively respects the contract. | 1386 // the clip unchanges conservatively respects the contract. |
| 1354 return this->getClipDeviceBounds(NULL); | 1387 return; |
| 1355 case SkRegion::kUnion_Op: | 1388 case SkRegion::kUnion_Op: |
| 1356 case SkRegion::kReplace_Op: | 1389 case SkRegion::kReplace_Op: |
| 1357 case SkRegion::kReverseDifference_Op: | 1390 case SkRegion::kReverseDifference_Op: |
| 1358 case SkRegion::kXOR_Op: | 1391 case SkRegion::kXOR_Op: |
| 1359 { | 1392 { |
| 1360 // These ops can grow the current clip up to the extents of | 1393 // These ops can grow the current clip up to the extents of |
| 1361 // the input clip, which is inverse filled, so we just set | 1394 // the input clip, which is inverse filled, so we just set |
| 1362 // the current clip to the device bounds. | 1395 // the current clip to the device bounds. |
| 1363 SkRect deviceBounds; | 1396 SkRect deviceBounds; |
| 1364 SkIRect deviceIBounds; | 1397 SkIRect deviceIBounds; |
| 1365 this->getDevice()->getGlobalBounds(&deviceIBounds); | 1398 this->getDevice()->getGlobalBounds(&deviceIBounds); |
| 1366 deviceBounds = SkRect::Make(deviceIBounds); | 1399 deviceBounds = SkRect::Make(deviceIBounds); |
| 1367 this->SkCanvas::save(SkCanvas::kMatrix_SaveFlag); | 1400 this->SkCanvas::save(SkCanvas::kMatrix_SaveFlag); |
| 1368 // set the clip in device space | 1401 // set the clip in device space |
| 1369 this->SkCanvas::setMatrix(SkMatrix::I()); | 1402 this->SkCanvas::setMatrix(SkMatrix::I()); |
| 1370 bool result = this->SkCanvas::clipRect(deviceBounds, | 1403 this->SkCanvas::clipRect(deviceBounds, SkRegion::kReplace_Op
, false); |
| 1371 SkRegion::kReplace_Op, false); | |
| 1372 this->SkCanvas::restore(); //pop the matrix, but keep the cl
ip | 1404 this->SkCanvas::restore(); //pop the matrix, but keep the cl
ip |
| 1373 return result; | 1405 return; |
| 1374 } | 1406 } |
| 1375 default: | 1407 default: |
| 1376 SkASSERT(0); // unhandled op? | 1408 SkASSERT(0); // unhandled op? |
| 1377 } | 1409 } |
| 1378 } else { | 1410 } else { |
| 1379 // Not inverse filled | 1411 // Not inverse filled |
| 1380 switch (op) { | 1412 switch (op) { |
| 1381 case SkRegion::kIntersect_Op: | 1413 case SkRegion::kIntersect_Op: |
| 1382 case SkRegion::kUnion_Op: | 1414 case SkRegion::kUnion_Op: |
| 1383 case SkRegion::kReplace_Op: | 1415 case SkRegion::kReplace_Op: |
| 1384 return this->SkCanvas::clipRect(bounds, op, false); | 1416 this->SkCanvas::clipRect(bounds, op, false); |
| 1417 return; |
| 1385 case SkRegion::kDifference_Op: | 1418 case SkRegion::kDifference_Op: |
| 1386 // Difference can only shrink the current clip. | 1419 // Difference can only shrink the current clip. |
| 1387 // Leaving clip unchanged conservatively fullfills the contract. | 1420 // Leaving clip unchanged conservatively fullfills the contract. |
| 1388 return this->getClipDeviceBounds(NULL); | 1421 return; |
| 1389 case SkRegion::kReverseDifference_Op: | 1422 case SkRegion::kReverseDifference_Op: |
| 1390 // To reverse, we swap in the bounds with a replace op. | 1423 // To reverse, we swap in the bounds with a replace op. |
| 1391 // As with difference, leave it unchanged. | 1424 // As with difference, leave it unchanged. |
| 1392 return this->SkCanvas::clipRect(bounds, SkRegion::kReplace_Op, f
alse); | 1425 this->SkCanvas::clipRect(bounds, SkRegion::kReplace_Op, false); |
| 1426 return; |
| 1393 case SkRegion::kXOR_Op: | 1427 case SkRegion::kXOR_Op: |
| 1394 // Be conservative, based on (A XOR B) always included in (A uni
on B), | 1428 // Be conservative, based on (A XOR B) always included in (A uni
on B), |
| 1395 // which is always included in (bounds(A) union bounds(B)) | 1429 // which is always included in (bounds(A) union bounds(B)) |
| 1396 return this->SkCanvas::clipRect(bounds, SkRegion::kUnion_Op, fal
se); | 1430 this->SkCanvas::clipRect(bounds, SkRegion::kUnion_Op, false); |
| 1431 return; |
| 1397 default: | 1432 default: |
| 1398 SkASSERT(0); // unhandled op? | 1433 SkASSERT(0); // unhandled op? |
| 1399 } | 1434 } |
| 1400 } | 1435 } |
| 1401 return true; | |
| 1402 } | 1436 } |
| 1403 | 1437 |
| 1404 bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { | 1438 bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { |
| 1439 this->onClipRegion(rgn, op); |
| 1440 return !this->isClipEmpty(); |
| 1441 } |
| 1442 |
| 1443 void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) { |
| 1405 AutoValidateClip avc(this); | 1444 AutoValidateClip avc(this); |
| 1406 | 1445 |
| 1407 fDeviceCMDirty = true; | 1446 fDeviceCMDirty = true; |
| 1408 fCachedLocalClipBoundsDirty = true; | 1447 fCachedLocalClipBoundsDirty = true; |
| 1409 | 1448 |
| 1410 // todo: signal fClipStack that we have a region, and therefore (I guess) | 1449 // todo: signal fClipStack that we have a region, and therefore (I guess) |
| 1411 // we have to ignore it, and use the region directly? | 1450 // we have to ignore it, and use the region directly? |
| 1412 fClipStack.clipDevRect(rgn.getBounds(), op); | 1451 fClipStack.clipDevRect(rgn.getBounds(), op); |
| 1413 | 1452 |
| 1414 return fMCRec->fRasterClip->op(rgn, op); | 1453 fMCRec->fRasterClip->op(rgn, op); |
| 1415 } | 1454 } |
| 1416 | 1455 |
| 1417 #ifdef SK_DEBUG | 1456 #ifdef SK_DEBUG |
| 1418 void SkCanvas::validateClip() const { | 1457 void SkCanvas::validateClip() const { |
| 1419 // construct clipRgn from the clipstack | 1458 // construct clipRgn from the clipstack |
| 1420 const SkBaseDevice* device = this->getDevice(); | 1459 const SkBaseDevice* device = this->getDevice(); |
| 1421 if (!device) { | 1460 if (!device) { |
| 1422 SkASSERT(this->getTotalClip().isEmpty()); | 1461 SkASSERT(this->getTotalClip().isEmpty()); |
| 1423 return; | 1462 return; |
| 1424 } | 1463 } |
| 1425 | 1464 |
| 1426 SkIRect ir; | 1465 SkIRect ir; |
| 1427 ir.set(0, 0, device->width(), device->height()); | 1466 ir.set(0, 0, device->width(), device->height()); |
| 1428 SkRasterClip tmpClip(ir); | 1467 SkRasterClip tmpClip(ir); |
| 1429 | 1468 |
| 1430 SkClipStack::B2TIter iter(fClipStack); | 1469 SkClipStack::B2TIter iter(fClipStack); |
| 1431 const SkClipStack::Element* element; | 1470 const SkClipStack::Element* element; |
| 1432 while ((element = iter.next()) != NULL) { | 1471 while ((element = iter.next()) != NULL) { |
| 1433 switch (element->getType()) { | 1472 switch (element->getType()) { |
| 1434 case SkClipStack::Element::kRect_Type: | 1473 case SkClipStack::Element::kRect_Type: |
| 1435 element->getRect().round(&ir); | 1474 element->getRect().round(&ir); |
| 1436 tmpClip.op(ir, element->getOp()); | 1475 tmpClip.op(ir, element->getOp()); |
| 1437 break; | 1476 break; |
| 1438 case SkClipStack::Element::kEmpty_Type: | 1477 case SkClipStack::Element::kEmpty_Type: |
| 1439 tmpClip.setEmpty(); | 1478 tmpClip.setEmpty(); |
| 1440 break; | 1479 break; |
| 1441 default: { | 1480 default: { |
| 1442 SkPath path; | 1481 SkPath path; |
| 1443 element->asPath(&path); | 1482 element->asPath(&path); |
| 1444 clipPathHelper(this, | 1483 clip_path_helper(this, &tmpClip, path, element->getOp(), element
->isAA()); |
| 1445 &tmpClip, | |
| 1446 path, | |
| 1447 element->getOp(), | |
| 1448 element->isAA()); | |
| 1449 break; | 1484 break; |
| 1450 } | 1485 } |
| 1451 } | 1486 } |
| 1452 } | 1487 } |
| 1453 | 1488 |
| 1454 #if 0 // enable this locally for testing | 1489 #if 0 // enable this locally for testing |
| 1455 // now compare against the current rgn | 1490 // now compare against the current rgn |
| 1456 const SkRegion& rgn = this->getTotalClip(); | 1491 const SkRegion& rgn = this->getTotalClip(); |
| 1457 SkASSERT(rgn == tmpClip); | 1492 SkASSERT(rgn == tmpClip); |
| 1458 #endif | 1493 #endif |
| (...skipping 829 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2288 return *paint; | 2323 return *paint; |
| 2289 } | 2324 } |
| 2290 | 2325 |
| 2291 const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); } | 2326 const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); } |
| 2292 int SkCanvas::LayerIter::x() const { return fImpl->getX(); } | 2327 int SkCanvas::LayerIter::x() const { return fImpl->getX(); } |
| 2293 int SkCanvas::LayerIter::y() const { return fImpl->getY(); } | 2328 int SkCanvas::LayerIter::y() const { return fImpl->getY(); } |
| 2294 | 2329 |
| 2295 /////////////////////////////////////////////////////////////////////////////// | 2330 /////////////////////////////////////////////////////////////////////////////// |
| 2296 | 2331 |
| 2297 SkCanvas::ClipVisitor::~ClipVisitor() { } | 2332 SkCanvas::ClipVisitor::~ClipVisitor() { } |
| OLD | NEW |