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 1148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1159 void SkCanvas::resetMatrix() { | 1159 void SkCanvas::resetMatrix() { |
1160 SkMatrix matrix; | 1160 SkMatrix matrix; |
1161 | 1161 |
1162 matrix.reset(); | 1162 matrix.reset(); |
1163 this->setMatrix(matrix); | 1163 this->setMatrix(matrix); |
1164 } | 1164 } |
1165 | 1165 |
1166 ////////////////////////////////////////////////////////////////////////////// | 1166 ////////////////////////////////////////////////////////////////////////////// |
1167 | 1167 |
1168 bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { | 1168 bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { |
| 1169 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; |
| 1170 this->onClipRect(rect, op, edgeStyle); |
| 1171 return !this->isClipEmpty(); |
| 1172 } |
| 1173 |
| 1174 void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edg
eStyle) { |
1169 #ifdef SK_ENABLE_CLIP_QUICKREJECT | 1175 #ifdef SK_ENABLE_CLIP_QUICKREJECT |
1170 if (SkRegion::kIntersect_Op == op) { | 1176 if (SkRegion::kIntersect_Op == op) { |
1171 if (fMCRec->fRasterClip->isEmpty()) { | 1177 if (fMCRec->fRasterClip->isEmpty()) { |
1172 return false; | 1178 return false; |
1173 } | 1179 } |
1174 | 1180 |
1175 if (this->quickReject(rect)) { | 1181 if (this->quickReject(rect)) { |
1176 fDeviceCMDirty = true; | 1182 fDeviceCMDirty = true; |
1177 fCachedLocalClipBoundsDirty = true; | 1183 fCachedLocalClipBoundsDirty = true; |
1178 | 1184 |
1179 fClipStack.clipEmpty(); | 1185 fClipStack.clipEmpty(); |
1180 return fMCRec->fRasterClip->setEmpty(); | 1186 return fMCRec->fRasterClip->setEmpty(); |
1181 } | 1187 } |
1182 } | 1188 } |
1183 #endif | 1189 #endif |
1184 | 1190 |
1185 AutoValidateClip avc(this); | 1191 AutoValidateClip avc(this); |
1186 | 1192 |
1187 fDeviceCMDirty = true; | 1193 fDeviceCMDirty = true; |
1188 fCachedLocalClipBoundsDirty = true; | 1194 fCachedLocalClipBoundsDirty = true; |
1189 doAA &= fAllowSoftClip; | 1195 if (!fAllowSoftClip) { |
| 1196 edgeStyle = kHard_ClipEdgeStyle; |
| 1197 } |
1190 | 1198 |
1191 if (fMCRec->fMatrix->rectStaysRect()) { | 1199 if (fMCRec->fMatrix->rectStaysRect()) { |
1192 // for these simpler matrices, we can stay a rect even after applying | 1200 // for these simpler matrices, we can stay a rect even after applying |
1193 // the matrix. This means we don't have to a) make a path, and b) tell | 1201 // the matrix. This means we don't have to a) make a path, and b) tell |
1194 // the region code to scan-convert the path, only to discover that it | 1202 // the region code to scan-convert the path, only to discover that it |
1195 // is really just a rect. | 1203 // is really just a rect. |
1196 SkRect r; | 1204 SkRect r; |
1197 | 1205 |
1198 fMCRec->fMatrix->mapRect(&r, rect); | 1206 fMCRec->fMatrix->mapRect(&r, rect); |
1199 fClipStack.clipDevRect(r, op, doAA); | 1207 fClipStack.clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle); |
1200 return fMCRec->fRasterClip->op(r, op, doAA); | 1208 fMCRec->fRasterClip->op(r, op, kSoft_ClipEdgeStyle == edgeStyle); |
1201 } else { | 1209 } else { |
1202 // since we're rotated or some such thing, we convert the rect to a path | 1210 // since we're rotated or some such thing, we convert the rect to a path |
1203 // and clip against that, since it can handle any matrix. However, to | 1211 // and clip against that, since it can handle any matrix. However, to |
1204 // avoid recursion in the case where we are subclassed (e.g. Pictures) | 1212 // avoid recursion in the case where we are subclassed (e.g. Pictures) |
1205 // we explicitly call "our" version of clipPath. | 1213 // we explicitly call "our" version of clipPath. |
1206 SkPath path; | 1214 SkPath path; |
1207 | 1215 |
1208 path.addRect(rect); | 1216 path.addRect(rect); |
1209 return this->SkCanvas::clipPath(path, op, doAA); | 1217 this->SkCanvas::onClipPath(path, op, edgeStyle); |
1210 } | 1218 } |
1211 } | 1219 } |
1212 | 1220 |
1213 static bool clipPathHelper(const SkCanvas* canvas, SkRasterClip* currClip, | 1221 static void clip_path_helper(const SkCanvas* canvas, SkRasterClip* currClip, |
1214 const SkPath& devPath, SkRegion::Op op, bool doAA) { | 1222 const SkPath& devPath, SkRegion::Op op, bool doAA)
{ |
1215 // base is used to limit the size (and therefore memory allocation) of the | 1223 // base is used to limit the size (and therefore memory allocation) of the |
1216 // region that results from scan converting devPath. | 1224 // region that results from scan converting devPath. |
1217 SkRegion base; | 1225 SkRegion base; |
1218 | 1226 |
1219 if (SkRegion::kIntersect_Op == op) { | 1227 if (SkRegion::kIntersect_Op == op) { |
1220 // since we are intersect, we can do better (tighter) with currRgn's | 1228 // since we are intersect, we can do better (tighter) with currRgn's |
1221 // bounds, than just using the device. However, if currRgn is complex, | 1229 // bounds, than just using the device. However, if currRgn is complex, |
1222 // our region blitter may hork, so we do that case in two steps. | 1230 // our region blitter may hork, so we do that case in two steps. |
1223 if (currClip->isRect()) { | 1231 if (currClip->isRect()) { |
1224 // FIXME: we should also be able to do this when currClip->isBW(), | 1232 // FIXME: we should also be able to do this when currClip->isBW(), |
1225 // but relaxing the test above triggers GM asserts in | 1233 // but relaxing the test above triggers GM asserts in |
1226 // SkRgnBuilder::blitH(). We need to investigate what's going on. | 1234 // SkRgnBuilder::blitH(). We need to investigate what's going on. |
1227 return currClip->setPath(devPath, currClip->bwRgn(), doAA); | 1235 currClip->setPath(devPath, currClip->bwRgn(), doAA); |
1228 } else { | 1236 } else { |
1229 base.setRect(currClip->getBounds()); | 1237 base.setRect(currClip->getBounds()); |
1230 SkRasterClip clip; | 1238 SkRasterClip clip; |
1231 clip.setPath(devPath, base, doAA); | 1239 clip.setPath(devPath, base, doAA); |
1232 return currClip->op(clip, op); | 1240 currClip->op(clip, op); |
1233 } | 1241 } |
1234 } else { | 1242 } else { |
1235 const SkBaseDevice* device = canvas->getDevice(); | 1243 const SkBaseDevice* device = canvas->getDevice(); |
1236 if (!device) { | 1244 if (!device) { |
1237 return currClip->setEmpty(); | 1245 currClip->setEmpty(); |
| 1246 return; |
1238 } | 1247 } |
1239 | 1248 |
1240 base.setRect(0, 0, device->width(), device->height()); | 1249 base.setRect(0, 0, device->width(), device->height()); |
1241 | 1250 |
1242 if (SkRegion::kReplace_Op == op) { | 1251 if (SkRegion::kReplace_Op == op) { |
1243 return currClip->setPath(devPath, base, doAA); | 1252 currClip->setPath(devPath, base, doAA); |
1244 } else { | 1253 } else { |
1245 SkRasterClip clip; | 1254 SkRasterClip clip; |
1246 clip.setPath(devPath, base, doAA); | 1255 clip.setPath(devPath, base, doAA); |
1247 return currClip->op(clip, op); | 1256 currClip->op(clip, op); |
1248 } | 1257 } |
1249 } | 1258 } |
1250 } | 1259 } |
1251 | 1260 |
1252 bool SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { | 1261 bool SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { |
| 1262 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; |
1253 if (rrect.isRect()) { | 1263 if (rrect.isRect()) { |
1254 // call the non-virtual version | 1264 this->onClipRect(rrect.getBounds(), op, edgeStyle); |
1255 return this->SkCanvas::clipRect(rrect.getBounds(), op, doAA); | 1265 } else { |
| 1266 this->onClipRRect(rrect, op, edgeStyle); |
1256 } | 1267 } |
| 1268 return !this->isClipEmpty(); |
| 1269 } |
1257 | 1270 |
| 1271 void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle
edgeStyle) { |
1258 SkRRect transformedRRect; | 1272 SkRRect transformedRRect; |
1259 if (rrect.transform(*fMCRec->fMatrix, &transformedRRect)) { | 1273 if (rrect.transform(*fMCRec->fMatrix, &transformedRRect)) { |
1260 AutoValidateClip avc(this); | 1274 AutoValidateClip avc(this); |
1261 | 1275 |
1262 fDeviceCMDirty = true; | 1276 fDeviceCMDirty = true; |
1263 fCachedLocalClipBoundsDirty = true; | 1277 fCachedLocalClipBoundsDirty = true; |
1264 doAA &= fAllowSoftClip; | 1278 if (!fAllowSoftClip) { |
| 1279 edgeStyle = kHard_ClipEdgeStyle; |
| 1280 } |
1265 | 1281 |
1266 fClipStack.clipDevRRect(transformedRRect, op, doAA); | 1282 fClipStack.clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == edg
eStyle); |
1267 | 1283 |
1268 SkPath devPath; | 1284 SkPath devPath; |
1269 devPath.addRRect(transformedRRect); | 1285 devPath.addRRect(transformedRRect); |
1270 | 1286 |
1271 return clipPathHelper(this, fMCRec->fRasterClip, devPath, op, doAA); | 1287 clip_path_helper(this, fMCRec->fRasterClip, devPath, op, kSoft_ClipEdgeS
tyle == edgeStyle); |
| 1288 return; |
1272 } | 1289 } |
1273 | 1290 |
1274 SkPath path; | 1291 SkPath path; |
1275 path.addRRect(rrect); | 1292 path.addRRect(rrect); |
1276 // call the non-virtual version | 1293 // call the non-virtual version |
1277 return this->SkCanvas::clipPath(path, op, doAA); | 1294 this->SkCanvas::onClipPath(path, op, edgeStyle); |
1278 } | 1295 } |
1279 | 1296 |
1280 bool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { | 1297 bool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { |
| 1298 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; |
| 1299 SkRect r; |
| 1300 if (!path.isInverseFillType() && path.isRect(&r)) { |
| 1301 this->onClipRect(r, op, edgeStyle); |
| 1302 } else { |
| 1303 this->onClipPath(path, op, edgeStyle); |
| 1304 } |
| 1305 |
| 1306 return !this->isClipEmpty(); |
| 1307 } |
| 1308 |
| 1309 void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edg
eStyle) { |
1281 #ifdef SK_ENABLE_CLIP_QUICKREJECT | 1310 #ifdef SK_ENABLE_CLIP_QUICKREJECT |
1282 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) { | 1311 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) { |
1283 if (fMCRec->fRasterClip->isEmpty()) { | 1312 if (fMCRec->fRasterClip->isEmpty()) { |
1284 return false; | 1313 return false; |
1285 } | 1314 } |
1286 | 1315 |
1287 if (this->quickReject(path.getBounds())) { | 1316 if (this->quickReject(path.getBounds())) { |
1288 fDeviceCMDirty = true; | 1317 fDeviceCMDirty = true; |
1289 fCachedLocalClipBoundsDirty = true; | 1318 fCachedLocalClipBoundsDirty = true; |
1290 | 1319 |
1291 fClipStack.clipEmpty(); | 1320 fClipStack.clipEmpty(); |
1292 return fMCRec->fRasterClip->setEmpty(); | 1321 return fMCRec->fRasterClip->setEmpty(); |
1293 } | 1322 } |
1294 } | 1323 } |
1295 #endif | 1324 #endif |
1296 | 1325 |
1297 AutoValidateClip avc(this); | 1326 AutoValidateClip avc(this); |
1298 | 1327 |
1299 fDeviceCMDirty = true; | 1328 fDeviceCMDirty = true; |
1300 fCachedLocalClipBoundsDirty = true; | 1329 fCachedLocalClipBoundsDirty = true; |
1301 doAA &= fAllowSoftClip; | 1330 if (!fAllowSoftClip) { |
| 1331 edgeStyle = kHard_ClipEdgeStyle; |
| 1332 } |
1302 | 1333 |
1303 SkPath devPath; | 1334 SkPath devPath; |
1304 path.transform(*fMCRec->fMatrix, &devPath); | 1335 path.transform(*fMCRec->fMatrix, &devPath); |
1305 | 1336 |
1306 // Check if the transfomation, or the original path itself | 1337 // Check if the transfomation, or the original path itself |
1307 // made us empty. Note this can also happen if we contained NaN | 1338 // made us empty. Note this can also happen if we contained NaN |
1308 // values. computing the bounds detects this, and will set our | 1339 // values. computing the bounds detects this, and will set our |
1309 // bounds to empty if that is the case. (see SkRect::set(pts, count)) | 1340 // bounds to empty if that is the case. (see SkRect::set(pts, count)) |
1310 if (devPath.getBounds().isEmpty()) { | 1341 if (devPath.getBounds().isEmpty()) { |
1311 // resetting the path will remove any NaN or other wanky values | 1342 // resetting the path will remove any NaN or other wanky values |
1312 // that might upset our scan converter. | 1343 // that might upset our scan converter. |
1313 devPath.reset(); | 1344 devPath.reset(); |
1314 } | 1345 } |
1315 | 1346 |
1316 // if we called path.swap() we could avoid a deep copy of this path | 1347 // if we called path.swap() we could avoid a deep copy of this path |
1317 fClipStack.clipDevPath(devPath, op, doAA); | 1348 fClipStack.clipDevPath(devPath, op, kSoft_ClipEdgeStyle == edgeStyle); |
1318 | 1349 |
1319 if (fAllowSimplifyClip) { | 1350 if (fAllowSimplifyClip) { |
1320 devPath.reset(); | 1351 devPath.reset(); |
1321 devPath.setFillType(SkPath::kInverseEvenOdd_FillType); | 1352 devPath.setFillType(SkPath::kInverseEvenOdd_FillType); |
1322 const SkClipStack* clipStack = getClipStack(); | 1353 const SkClipStack* clipStack = getClipStack(); |
1323 SkClipStack::Iter iter(*clipStack, SkClipStack::Iter::kBottom_IterStart)
; | 1354 SkClipStack::Iter iter(*clipStack, SkClipStack::Iter::kBottom_IterStart)
; |
1324 const SkClipStack::Element* element; | 1355 const SkClipStack::Element* element; |
1325 while ((element = iter.next())) { | 1356 while ((element = iter.next())) { |
1326 SkClipStack::Element::Type type = element->getType(); | 1357 SkClipStack::Element::Type type = element->getType(); |
1327 if (type == SkClipStack::Element::kEmpty_Type) { | 1358 if (type == SkClipStack::Element::kEmpty_Type) { |
1328 continue; | 1359 continue; |
1329 } | 1360 } |
1330 SkPath operand; | 1361 SkPath operand; |
1331 element->asPath(&operand); | 1362 element->asPath(&operand); |
1332 SkRegion::Op elementOp = element->getOp(); | 1363 SkRegion::Op elementOp = element->getOp(); |
1333 if (elementOp == SkRegion::kReplace_Op) { | 1364 if (elementOp == SkRegion::kReplace_Op) { |
1334 devPath = operand; | 1365 devPath = operand; |
1335 } else { | 1366 } else { |
1336 Op(devPath, operand, (SkPathOp) elementOp, &devPath); | 1367 Op(devPath, operand, (SkPathOp) elementOp, &devPath); |
1337 } | 1368 } |
1338 // if the prev and curr clips disagree about aa -vs- not, favor the
aa request. | 1369 // if the prev and curr clips disagree about aa -vs- not, favor the
aa request. |
1339 // perhaps we need an API change to avoid this sort of mixed-signals
about | 1370 // perhaps we need an API change to avoid this sort of mixed-signals
about |
1340 // clipping. | 1371 // clipping. |
1341 doAA |= element->isAA(); | 1372 if (element->isAA()) { |
| 1373 edgeStyle = kSoft_ClipEdgeStyle; |
| 1374 } |
1342 } | 1375 } |
1343 op = SkRegion::kReplace_Op; | 1376 op = SkRegion::kReplace_Op; |
1344 } | 1377 } |
1345 | 1378 |
1346 return clipPathHelper(this, fMCRec->fRasterClip, devPath, op, doAA); | 1379 clip_path_helper(this, fMCRec->fRasterClip, devPath, op, edgeStyle); |
1347 } | 1380 } |
1348 | 1381 |
1349 bool SkCanvas::updateClipConservativelyUsingBounds(const SkRect& bounds, SkRegio
n::Op op, | 1382 bool SkCanvas::updateClipConservativelyUsingBounds(const SkRect& bounds, SkRegio
n::Op op, |
1350 bool inverseFilled) { | 1383 bool inverseFilled) { |
1351 // This is for updating the clip conservatively using only bounds | 1384 // This is for updating the clip conservatively using only bounds |
1352 // information. | 1385 // information. |
1353 // Contract: | 1386 // Contract: |
1354 // The current clip must contain the true clip. The true | 1387 // The current clip must contain the true clip. The true |
1355 // clip is the clip that would have normally been computed | 1388 // clip is the clip that would have normally been computed |
1356 // by calls to clipPath and clipRRect | 1389 // by calls to clipPath and clipRRect |
1357 // Objective: | 1390 // Objective: |
1358 // Keep the current clip as small as possible without | 1391 // Keep the current clip as small as possible without |
1359 // breaking the contract, using only clip bounding rectangles | 1392 // breaking the contract, using only clip bounding rectangles |
1360 // (for performance). | 1393 // (for performance). |
1361 | 1394 |
1362 // N.B.: This *never* calls back through a virtual on canvas, so subclasses | 1395 // N.B.: This *never* calls back through a virtual on canvas, so subclasses |
1363 // don't have to worry about getting caught in a loop. Thus anywhere | 1396 // don't have to worry about getting caught in a loop. Thus anywhere |
1364 // we call a virtual method, we explicitly prefix it with | 1397 // we call a virtual method, we explicitly prefix it with |
1365 // SkCanvas:: to be sure to call the base-class. | 1398 // SkCanvas:: to be sure to call the base-class. |
1366 | 1399 |
1367 if (inverseFilled) { | 1400 if (inverseFilled) { |
1368 switch (op) { | 1401 switch (op) { |
1369 case SkRegion::kIntersect_Op: | 1402 case SkRegion::kIntersect_Op: |
1370 case SkRegion::kDifference_Op: | 1403 case SkRegion::kDifference_Op: |
1371 // These ops can only shrink the current clip. So leaving | 1404 // These ops can only shrink the current clip. So leaving |
1372 // the clip unchanges conservatively respects the contract. | 1405 // the clip unchanged conservatively respects the contract. |
1373 return this->getClipDeviceBounds(NULL); | 1406 break; |
1374 case SkRegion::kUnion_Op: | 1407 case SkRegion::kUnion_Op: |
1375 case SkRegion::kReplace_Op: | 1408 case SkRegion::kReplace_Op: |
1376 case SkRegion::kReverseDifference_Op: | 1409 case SkRegion::kReverseDifference_Op: |
1377 case SkRegion::kXOR_Op: | 1410 case SkRegion::kXOR_Op: { |
1378 { | |
1379 // These ops can grow the current clip up to the extents of | 1411 // These ops can grow the current clip up to the extents of |
1380 // the input clip, which is inverse filled, so we just set | 1412 // the input clip, which is inverse filled, so we just set |
1381 // the current clip to the device bounds. | 1413 // the current clip to the device bounds. |
1382 SkRect deviceBounds; | 1414 SkRect deviceBounds; |
1383 SkIRect deviceIBounds; | 1415 SkIRect deviceIBounds; |
1384 this->getDevice()->getGlobalBounds(&deviceIBounds); | 1416 this->getDevice()->getGlobalBounds(&deviceIBounds); |
1385 deviceBounds = SkRect::Make(deviceIBounds); | 1417 deviceBounds = SkRect::Make(deviceIBounds); |
1386 this->SkCanvas::save(SkCanvas::kMatrix_SaveFlag); | 1418 this->SkCanvas::save(SkCanvas::kMatrix_SaveFlag); |
1387 // set the clip in device space | 1419 // set the clip in device space |
1388 this->SkCanvas::setMatrix(SkMatrix::I()); | 1420 this->SkCanvas::setMatrix(SkMatrix::I()); |
1389 bool result = this->SkCanvas::clipRect(deviceBounds, | 1421 this->SkCanvas::onClipRect(deviceBounds, SkRegion::kReplace_
Op, |
1390 SkRegion::kReplace_Op, false); | 1422 kHard_ClipEdgeStyle); |
1391 this->SkCanvas::restore(); //pop the matrix, but keep the cl
ip | 1423 this->SkCanvas::restore(); //pop the matrix, but keep the cl
ip |
1392 return result; | 1424 break; |
1393 } | 1425 } |
1394 default: | 1426 default: |
1395 SkASSERT(0); // unhandled op? | 1427 SkASSERT(0); // unhandled op? |
1396 } | 1428 } |
1397 } else { | 1429 } else { |
1398 // Not inverse filled | 1430 // Not inverse filled |
1399 switch (op) { | 1431 switch (op) { |
1400 case SkRegion::kIntersect_Op: | 1432 case SkRegion::kIntersect_Op: |
1401 case SkRegion::kUnion_Op: | 1433 case SkRegion::kUnion_Op: |
1402 case SkRegion::kReplace_Op: | 1434 case SkRegion::kReplace_Op: |
1403 return this->SkCanvas::clipRect(bounds, op, false); | 1435 this->SkCanvas::onClipRect(bounds, op, kHard_ClipEdgeStyle); |
| 1436 break; |
1404 case SkRegion::kDifference_Op: | 1437 case SkRegion::kDifference_Op: |
1405 // Difference can only shrink the current clip. | 1438 // Difference can only shrink the current clip. |
1406 // Leaving clip unchanged conservatively fullfills the contract. | 1439 // Leaving clip unchanged conservatively fullfills the contract. |
1407 return this->getClipDeviceBounds(NULL); | 1440 break; |
1408 case SkRegion::kReverseDifference_Op: | 1441 case SkRegion::kReverseDifference_Op: |
1409 // To reverse, we swap in the bounds with a replace op. | 1442 // To reverse, we swap in the bounds with a replace op. |
1410 // As with difference, leave it unchanged. | 1443 // As with difference, leave it unchanged. |
1411 return this->SkCanvas::clipRect(bounds, SkRegion::kReplace_Op, f
alse); | 1444 this->SkCanvas::onClipRect(bounds, SkRegion::kReplace_Op, kHard_
ClipEdgeStyle); |
| 1445 break; |
1412 case SkRegion::kXOR_Op: | 1446 case SkRegion::kXOR_Op: |
1413 // Be conservative, based on (A XOR B) always included in (A uni
on B), | 1447 // Be conservative, based on (A XOR B) always included in (A uni
on B), |
1414 // which is always included in (bounds(A) union bounds(B)) | 1448 // which is always included in (bounds(A) union bounds(B)) |
1415 return this->SkCanvas::clipRect(bounds, SkRegion::kUnion_Op, fal
se); | 1449 this->SkCanvas::onClipRect(bounds, SkRegion::kUnion_Op, kHard_Cl
ipEdgeStyle); |
| 1450 break; |
1416 default: | 1451 default: |
1417 SkASSERT(0); // unhandled op? | 1452 SkASSERT(0); // unhandled op? |
1418 } | 1453 } |
1419 } | 1454 } |
1420 return true; | 1455 |
| 1456 return !this->isClipEmpty(); |
1421 } | 1457 } |
1422 | 1458 |
1423 bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { | 1459 bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { |
| 1460 this->onClipRegion(rgn, op); |
| 1461 return !this->isClipEmpty(); |
| 1462 } |
| 1463 |
| 1464 void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) { |
1424 AutoValidateClip avc(this); | 1465 AutoValidateClip avc(this); |
1425 | 1466 |
1426 fDeviceCMDirty = true; | 1467 fDeviceCMDirty = true; |
1427 fCachedLocalClipBoundsDirty = true; | 1468 fCachedLocalClipBoundsDirty = true; |
1428 | 1469 |
1429 // todo: signal fClipStack that we have a region, and therefore (I guess) | 1470 // todo: signal fClipStack that we have a region, and therefore (I guess) |
1430 // we have to ignore it, and use the region directly? | 1471 // we have to ignore it, and use the region directly? |
1431 fClipStack.clipDevRect(rgn.getBounds(), op); | 1472 fClipStack.clipDevRect(rgn.getBounds(), op); |
1432 | 1473 |
1433 return fMCRec->fRasterClip->op(rgn, op); | 1474 fMCRec->fRasterClip->op(rgn, op); |
1434 } | 1475 } |
1435 | 1476 |
1436 #ifdef SK_DEBUG | 1477 #ifdef SK_DEBUG |
1437 void SkCanvas::validateClip() const { | 1478 void SkCanvas::validateClip() const { |
1438 // construct clipRgn from the clipstack | 1479 // construct clipRgn from the clipstack |
1439 const SkBaseDevice* device = this->getDevice(); | 1480 const SkBaseDevice* device = this->getDevice(); |
1440 if (!device) { | 1481 if (!device) { |
1441 SkASSERT(this->getTotalClip().isEmpty()); | 1482 SkASSERT(this->getTotalClip().isEmpty()); |
1442 return; | 1483 return; |
1443 } | 1484 } |
1444 | 1485 |
1445 SkIRect ir; | 1486 SkIRect ir; |
1446 ir.set(0, 0, device->width(), device->height()); | 1487 ir.set(0, 0, device->width(), device->height()); |
1447 SkRasterClip tmpClip(ir); | 1488 SkRasterClip tmpClip(ir); |
1448 | 1489 |
1449 SkClipStack::B2TIter iter(fClipStack); | 1490 SkClipStack::B2TIter iter(fClipStack); |
1450 const SkClipStack::Element* element; | 1491 const SkClipStack::Element* element; |
1451 while ((element = iter.next()) != NULL) { | 1492 while ((element = iter.next()) != NULL) { |
1452 switch (element->getType()) { | 1493 switch (element->getType()) { |
1453 case SkClipStack::Element::kRect_Type: | 1494 case SkClipStack::Element::kRect_Type: |
1454 element->getRect().round(&ir); | 1495 element->getRect().round(&ir); |
1455 tmpClip.op(ir, element->getOp()); | 1496 tmpClip.op(ir, element->getOp()); |
1456 break; | 1497 break; |
1457 case SkClipStack::Element::kEmpty_Type: | 1498 case SkClipStack::Element::kEmpty_Type: |
1458 tmpClip.setEmpty(); | 1499 tmpClip.setEmpty(); |
1459 break; | 1500 break; |
1460 default: { | 1501 default: { |
1461 SkPath path; | 1502 SkPath path; |
1462 element->asPath(&path); | 1503 element->asPath(&path); |
1463 clipPathHelper(this, | 1504 clip_path_helper(this, &tmpClip, path, element->getOp(), element
->isAA()); |
1464 &tmpClip, | |
1465 path, | |
1466 element->getOp(), | |
1467 element->isAA()); | |
1468 break; | 1505 break; |
1469 } | 1506 } |
1470 } | 1507 } |
1471 } | 1508 } |
1472 | 1509 |
1473 #if 0 // enable this locally for testing | 1510 #if 0 // enable this locally for testing |
1474 // now compare against the current rgn | 1511 // now compare against the current rgn |
1475 const SkRegion& rgn = this->getTotalClip(); | 1512 const SkRegion& rgn = this->getTotalClip(); |
1476 SkASSERT(rgn == tmpClip); | 1513 SkASSERT(rgn == tmpClip); |
1477 #endif | 1514 #endif |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1536 return false; | 1573 return false; |
1537 } | 1574 } |
1538 } | 1575 } |
1539 | 1576 |
1540 bool SkCanvas::quickReject(const SkPath& path) const { | 1577 bool SkCanvas::quickReject(const SkPath& path) const { |
1541 return path.isEmpty() || this->quickReject(path.getBounds()); | 1578 return path.isEmpty() || this->quickReject(path.getBounds()); |
1542 } | 1579 } |
1543 | 1580 |
1544 bool SkCanvas::getClipBounds(SkRect* bounds) const { | 1581 bool SkCanvas::getClipBounds(SkRect* bounds) const { |
1545 SkIRect ibounds; | 1582 SkIRect ibounds; |
1546 if (!getClipDeviceBounds(&ibounds)) { | 1583 if (!this->getClipDeviceBounds(&ibounds)) { |
1547 return false; | 1584 return false; |
1548 } | 1585 } |
1549 | 1586 |
1550 SkMatrix inverse; | 1587 SkMatrix inverse; |
1551 // if we can't invert the CTM, we can't return local clip bounds | 1588 // if we can't invert the CTM, we can't return local clip bounds |
1552 if (!fMCRec->fMatrix->invert(&inverse)) { | 1589 if (!fMCRec->fMatrix->invert(&inverse)) { |
1553 if (bounds) { | 1590 if (bounds) { |
1554 bounds->setEmpty(); | 1591 bounds->setEmpty(); |
1555 } | 1592 } |
1556 return false; | 1593 return false; |
(...skipping 24 matching lines...) Expand all Loading... |
1581 *bounds = clip.getBounds(); | 1618 *bounds = clip.getBounds(); |
1582 } | 1619 } |
1583 return true; | 1620 return true; |
1584 } | 1621 } |
1585 | 1622 |
1586 const SkMatrix& SkCanvas::getTotalMatrix() const { | 1623 const SkMatrix& SkCanvas::getTotalMatrix() const { |
1587 return *fMCRec->fMatrix; | 1624 return *fMCRec->fMatrix; |
1588 } | 1625 } |
1589 | 1626 |
1590 SkCanvas::ClipType SkCanvas::getClipType() const { | 1627 SkCanvas::ClipType SkCanvas::getClipType() const { |
1591 if (fMCRec->fRasterClip->isEmpty()) return kEmpty_ClipType; | 1628 if (fMCRec->fRasterClip->isEmpty()) { |
1592 if (fMCRec->fRasterClip->isRect()) return kRect_ClipType; | 1629 return kEmpty_ClipType; |
| 1630 } |
| 1631 if (fMCRec->fRasterClip->isRect()) { |
| 1632 return kRect_ClipType; |
| 1633 } |
1593 return kComplex_ClipType; | 1634 return kComplex_ClipType; |
1594 } | 1635 } |
1595 | 1636 |
1596 const SkRegion& SkCanvas::getTotalClip() const { | 1637 const SkRegion& SkCanvas::getTotalClip() const { |
1597 return fMCRec->fRasterClip->forceGetBW(); | 1638 return fMCRec->fRasterClip->forceGetBW(); |
1598 } | 1639 } |
1599 | 1640 |
1600 SkBaseDevice* SkCanvas::createLayerDevice(const SkImageInfo& info) { | 1641 SkBaseDevice* SkCanvas::createLayerDevice(const SkImageInfo& info) { |
1601 SkBaseDevice* device = this->getTopDevice(); | 1642 SkBaseDevice* device = this->getTopDevice(); |
1602 return device ? device->createCompatibleDeviceForSaveLayer(info) : NULL; | 1643 return device ? device->createCompatibleDeviceForSaveLayer(info) : NULL; |
(...skipping 744 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2347 if (!bitmap.allocPixels(info)) { | 2388 if (!bitmap.allocPixels(info)) { |
2348 return NULL; | 2389 return NULL; |
2349 } | 2390 } |
2350 | 2391 |
2351 // should this functionality be moved into allocPixels()? | 2392 // should this functionality be moved into allocPixels()? |
2352 if (!bitmap.info().isOpaque()) { | 2393 if (!bitmap.info().isOpaque()) { |
2353 bitmap.eraseColor(0); | 2394 bitmap.eraseColor(0); |
2354 } | 2395 } |
2355 return SkNEW_ARGS(SkCanvas, (bitmap)); | 2396 return SkNEW_ARGS(SkCanvas, (bitmap)); |
2356 } | 2397 } |
OLD | NEW |