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 |