| 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" |
| 11 #include "SkBitmapDevice.h" | 11 #include "SkBitmapDevice.h" |
| 12 #include "SkBounder.h" | 12 #include "SkBounder.h" |
| 13 #include "SkDeviceImageFilterProxy.h" | 13 #include "SkDeviceImageFilterProxy.h" |
| 14 #include "SkDraw.h" | 14 #include "SkDraw.h" |
| 15 #include "SkDrawFilter.h" | 15 #include "SkDrawFilter.h" |
| 16 #include "SkDrawLooper.h" | 16 #include "SkDrawLooper.h" |
| 17 #include "SkMetaData.h" | 17 #include "SkMetaData.h" |
| 18 #include "SkPathOps.h" | 18 #include "SkPathOps.h" |
| 19 #include "SkPicture.h" | 19 #include "SkPicture.h" |
| 20 #include "SkRasterClip.h" | 20 #include "SkRasterClip.h" |
| 21 #include "SkRRect.h" | 21 #include "SkRRect.h" |
| 22 #include "SkScalarCompare.h" | |
| 23 #include "SkSurface_Base.h" | 22 #include "SkSurface_Base.h" |
| 24 #include "SkTemplates.h" | 23 #include "SkTemplates.h" |
| 25 #include "SkTextFormatParams.h" | 24 #include "SkTextFormatParams.h" |
| 26 #include "SkTLazy.h" | 25 #include "SkTLazy.h" |
| 27 #include "SkUtils.h" | 26 #include "SkUtils.h" |
| 28 | 27 |
| 29 #if SK_SUPPORT_GPU | 28 #if SK_SUPPORT_GPU |
| 30 #include "GrRenderTarget.h" | 29 #include "GrRenderTarget.h" |
| 31 #endif | 30 #endif |
| 32 | 31 |
| (...skipping 445 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 478 while (looper.next(type)) { \ | 477 while (looper.next(type)) { \ |
| 479 SkAutoBounderCommit ac(fBounder); \ | 478 SkAutoBounderCommit ac(fBounder); \ |
| 480 SkDrawIter iter(this); | 479 SkDrawIter iter(this); |
| 481 | 480 |
| 482 #define LOOPER_END } | 481 #define LOOPER_END } |
| 483 | 482 |
| 484 //////////////////////////////////////////////////////////////////////////// | 483 //////////////////////////////////////////////////////////////////////////// |
| 485 | 484 |
| 486 SkBaseDevice* SkCanvas::init(SkBaseDevice* device) { | 485 SkBaseDevice* SkCanvas::init(SkBaseDevice* device) { |
| 487 fBounder = NULL; | 486 fBounder = NULL; |
| 488 fLocalBoundsCompareType.setEmpty(); | 487 fCachedLocalClipBounds.setEmpty(); |
| 489 fLocalBoundsCompareTypeDirty = true; | 488 fCachedLocalClipBoundsDirty = true; |
| 490 fAllowSoftClip = true; | 489 fAllowSoftClip = true; |
| 491 fAllowSimplifyClip = false; | 490 fAllowSimplifyClip = false; |
| 492 fDeviceCMDirty = false; | 491 fDeviceCMDirty = false; |
| 493 fSaveLayerCount = 0; | 492 fSaveLayerCount = 0; |
| 494 fMetaData = NULL; | 493 fMetaData = NULL; |
| 495 | 494 |
| 496 fMCRec = (MCRec*)fMCStack.push_back(); | 495 fMCRec = (MCRec*)fMCStack.push_back(); |
| 497 new (fMCRec) MCRec(NULL, 0); | 496 new (fMCRec) MCRec(NULL, 0); |
| 498 | 497 |
| 499 fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL, NULL)); | 498 fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL, NULL)); |
| (...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 890 // check for underflow | 889 // check for underflow |
| 891 if (fMCStack.count() > 1) { | 890 if (fMCStack.count() > 1) { |
| 892 this->internalRestore(); | 891 this->internalRestore(); |
| 893 } | 892 } |
| 894 } | 893 } |
| 895 | 894 |
| 896 void SkCanvas::internalRestore() { | 895 void SkCanvas::internalRestore() { |
| 897 SkASSERT(fMCStack.count() != 0); | 896 SkASSERT(fMCStack.count() != 0); |
| 898 | 897 |
| 899 fDeviceCMDirty = true; | 898 fDeviceCMDirty = true; |
| 900 fLocalBoundsCompareTypeDirty = true; | 899 fCachedLocalClipBoundsDirty = true; |
| 901 | 900 |
| 902 if (SkCanvas::kClip_SaveFlag & fMCRec->fFlags) { | 901 if (SkCanvas::kClip_SaveFlag & fMCRec->fFlags) { |
| 903 fClipStack.restore(); | 902 fClipStack.restore(); |
| 904 } | 903 } |
| 905 | 904 |
| 906 // reserve our layer (if any) | 905 // reserve our layer (if any) |
| 907 DeviceCM* layer = fMCRec->fLayer; // may be null | 906 DeviceCM* layer = fMCRec->fLayer; // may be null |
| 908 // now detach it from fMCRec so we can pop(). Gets freed after its drawn | 907 // now detach it from fMCRec so we can pop(). Gets freed after its drawn |
| 909 fMCRec->fLayer = NULL; | 908 fMCRec->fLayer = NULL; |
| 910 | 909 |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1049 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint); | 1048 iter.fDevice->drawSprite(iter, bitmap, pos.x(), pos.y(), *paint); |
| 1050 } | 1049 } |
| 1051 } | 1050 } |
| 1052 LOOPER_END | 1051 LOOPER_END |
| 1053 } | 1052 } |
| 1054 | 1053 |
| 1055 ///////////////////////////////////////////////////////////////////////////// | 1054 ///////////////////////////////////////////////////////////////////////////// |
| 1056 | 1055 |
| 1057 bool SkCanvas::translate(SkScalar dx, SkScalar dy) { | 1056 bool SkCanvas::translate(SkScalar dx, SkScalar dy) { |
| 1058 fDeviceCMDirty = true; | 1057 fDeviceCMDirty = true; |
| 1059 fLocalBoundsCompareTypeDirty = true; | 1058 fCachedLocalClipBoundsDirty = true; |
| 1060 return fMCRec->fMatrix->preTranslate(dx, dy); | 1059 return fMCRec->fMatrix->preTranslate(dx, dy); |
| 1061 } | 1060 } |
| 1062 | 1061 |
| 1063 bool SkCanvas::scale(SkScalar sx, SkScalar sy) { | 1062 bool SkCanvas::scale(SkScalar sx, SkScalar sy) { |
| 1064 fDeviceCMDirty = true; | 1063 fDeviceCMDirty = true; |
| 1065 fLocalBoundsCompareTypeDirty = true; | 1064 fCachedLocalClipBoundsDirty = true; |
| 1066 return fMCRec->fMatrix->preScale(sx, sy); | 1065 return fMCRec->fMatrix->preScale(sx, sy); |
| 1067 } | 1066 } |
| 1068 | 1067 |
| 1069 bool SkCanvas::rotate(SkScalar degrees) { | 1068 bool SkCanvas::rotate(SkScalar degrees) { |
| 1070 fDeviceCMDirty = true; | 1069 fDeviceCMDirty = true; |
| 1071 fLocalBoundsCompareTypeDirty = true; | 1070 fCachedLocalClipBoundsDirty = true; |
| 1072 return fMCRec->fMatrix->preRotate(degrees); | 1071 return fMCRec->fMatrix->preRotate(degrees); |
| 1073 } | 1072 } |
| 1074 | 1073 |
| 1075 bool SkCanvas::skew(SkScalar sx, SkScalar sy) { | 1074 bool SkCanvas::skew(SkScalar sx, SkScalar sy) { |
| 1076 fDeviceCMDirty = true; | 1075 fDeviceCMDirty = true; |
| 1077 fLocalBoundsCompareTypeDirty = true; | 1076 fCachedLocalClipBoundsDirty = true; |
| 1078 return fMCRec->fMatrix->preSkew(sx, sy); | 1077 return fMCRec->fMatrix->preSkew(sx, sy); |
| 1079 } | 1078 } |
| 1080 | 1079 |
| 1081 bool SkCanvas::concat(const SkMatrix& matrix) { | 1080 bool SkCanvas::concat(const SkMatrix& matrix) { |
| 1082 fDeviceCMDirty = true; | 1081 fDeviceCMDirty = true; |
| 1083 fLocalBoundsCompareTypeDirty = true; | 1082 fCachedLocalClipBoundsDirty = true; |
| 1084 return fMCRec->fMatrix->preConcat(matrix); | 1083 return fMCRec->fMatrix->preConcat(matrix); |
| 1085 } | 1084 } |
| 1086 | 1085 |
| 1087 void SkCanvas::setMatrix(const SkMatrix& matrix) { | 1086 void SkCanvas::setMatrix(const SkMatrix& matrix) { |
| 1088 fDeviceCMDirty = true; | 1087 fDeviceCMDirty = true; |
| 1089 fLocalBoundsCompareTypeDirty = true; | 1088 fCachedLocalClipBoundsDirty = true; |
| 1090 *fMCRec->fMatrix = matrix; | 1089 *fMCRec->fMatrix = matrix; |
| 1091 } | 1090 } |
| 1092 | 1091 |
| 1093 // this is not virtual, so it must call a virtual method so that subclasses | 1092 // this is not virtual, so it must call a virtual method so that subclasses |
| 1094 // will see its action | 1093 // will see its action |
| 1095 void SkCanvas::resetMatrix() { | 1094 void SkCanvas::resetMatrix() { |
| 1096 SkMatrix matrix; | 1095 SkMatrix matrix; |
| 1097 | 1096 |
| 1098 matrix.reset(); | 1097 matrix.reset(); |
| 1099 this->setMatrix(matrix); | 1098 this->setMatrix(matrix); |
| 1100 } | 1099 } |
| 1101 | 1100 |
| 1102 ////////////////////////////////////////////////////////////////////////////// | 1101 ////////////////////////////////////////////////////////////////////////////// |
| 1103 | 1102 |
| 1104 bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { | 1103 bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { |
| 1105 #ifdef SK_ENABLE_CLIP_QUICKREJECT | 1104 #ifdef SK_ENABLE_CLIP_QUICKREJECT |
| 1106 if (SkRegion::kIntersect_Op == op) { | 1105 if (SkRegion::kIntersect_Op == op) { |
| 1107 if (fMCRec->fRasterClip->isEmpty()) { | 1106 if (fMCRec->fRasterClip->isEmpty()) { |
| 1108 return false; | 1107 return false; |
| 1109 } | 1108 } |
| 1110 | 1109 |
| 1111 if (this->quickReject(rect)) { | 1110 if (this->quickReject(rect)) { |
| 1112 fDeviceCMDirty = true; | 1111 fDeviceCMDirty = true; |
| 1113 fLocalBoundsCompareTypeDirty = true; | 1112 fCachedLocalClipBoundsDirty = true; |
| 1114 | 1113 |
| 1115 fClipStack.clipEmpty(); | 1114 fClipStack.clipEmpty(); |
| 1116 return fMCRec->fRasterClip->setEmpty(); | 1115 return fMCRec->fRasterClip->setEmpty(); |
| 1117 } | 1116 } |
| 1118 } | 1117 } |
| 1119 #endif | 1118 #endif |
| 1120 | 1119 |
| 1121 AutoValidateClip avc(this); | 1120 AutoValidateClip avc(this); |
| 1122 | 1121 |
| 1123 fDeviceCMDirty = true; | 1122 fDeviceCMDirty = true; |
| 1124 fLocalBoundsCompareTypeDirty = true; | 1123 fCachedLocalClipBoundsDirty = true; |
| 1125 doAA &= fAllowSoftClip; | 1124 doAA &= fAllowSoftClip; |
| 1126 | 1125 |
| 1127 if (fMCRec->fMatrix->rectStaysRect()) { | 1126 if (fMCRec->fMatrix->rectStaysRect()) { |
| 1128 // for these simpler matrices, we can stay a rect even after applying | 1127 // for these simpler matrices, we can stay a rect even after applying |
| 1129 // the matrix. This means we don't have to a) make a path, and b) tell | 1128 // the matrix. This means we don't have to a) make a path, and b) tell |
| 1130 // the region code to scan-convert the path, only to discover that it | 1129 // the region code to scan-convert the path, only to discover that it |
| 1131 // is really just a rect. | 1130 // is really just a rect. |
| 1132 SkRect r; | 1131 SkRect r; |
| 1133 | 1132 |
| 1134 fMCRec->fMatrix->mapRect(&r, rect); | 1133 fMCRec->fMatrix->mapRect(&r, rect); |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1199 | 1198 |
| 1200 bool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { | 1199 bool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { |
| 1201 #ifdef SK_ENABLE_CLIP_QUICKREJECT | 1200 #ifdef SK_ENABLE_CLIP_QUICKREJECT |
| 1202 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) { | 1201 if (SkRegion::kIntersect_Op == op && !path.isInverseFillType()) { |
| 1203 if (fMCRec->fRasterClip->isEmpty()) { | 1202 if (fMCRec->fRasterClip->isEmpty()) { |
| 1204 return false; | 1203 return false; |
| 1205 } | 1204 } |
| 1206 | 1205 |
| 1207 if (this->quickReject(path.getBounds())) { | 1206 if (this->quickReject(path.getBounds())) { |
| 1208 fDeviceCMDirty = true; | 1207 fDeviceCMDirty = true; |
| 1209 fLocalBoundsCompareTypeDirty = true; | 1208 fCachedLocalClipBoundsDirty = true; |
| 1210 | 1209 |
| 1211 fClipStack.clipEmpty(); | 1210 fClipStack.clipEmpty(); |
| 1212 return fMCRec->fRasterClip->setEmpty(); | 1211 return fMCRec->fRasterClip->setEmpty(); |
| 1213 } | 1212 } |
| 1214 } | 1213 } |
| 1215 #endif | 1214 #endif |
| 1216 | 1215 |
| 1217 AutoValidateClip avc(this); | 1216 AutoValidateClip avc(this); |
| 1218 | 1217 |
| 1219 fDeviceCMDirty = true; | 1218 fDeviceCMDirty = true; |
| 1220 fLocalBoundsCompareTypeDirty = true; | 1219 fCachedLocalClipBoundsDirty = true; |
| 1221 doAA &= fAllowSoftClip; | 1220 doAA &= fAllowSoftClip; |
| 1222 | 1221 |
| 1223 SkPath devPath; | 1222 SkPath devPath; |
| 1224 path.transform(*fMCRec->fMatrix, &devPath); | 1223 path.transform(*fMCRec->fMatrix, &devPath); |
| 1225 | 1224 |
| 1226 // Check if the transfomation, or the original path itself | 1225 // Check if the transfomation, or the original path itself |
| 1227 // made us empty. Note this can also happen if we contained NaN | 1226 // made us empty. Note this can also happen if we contained NaN |
| 1228 // values. computing the bounds detects this, and will set our | 1227 // values. computing the bounds detects this, and will set our |
| 1229 // bounds to empty if that is the case. (see SkRect::set(pts, count)) | 1228 // bounds to empty if that is the case. (see SkRect::set(pts, count)) |
| 1230 if (devPath.getBounds().isEmpty()) { | 1229 if (devPath.getBounds().isEmpty()) { |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1343 SkASSERT(0); // unhandled op? | 1342 SkASSERT(0); // unhandled op? |
| 1344 } | 1343 } |
| 1345 } | 1344 } |
| 1346 return true; | 1345 return true; |
| 1347 } | 1346 } |
| 1348 | 1347 |
| 1349 bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { | 1348 bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { |
| 1350 AutoValidateClip avc(this); | 1349 AutoValidateClip avc(this); |
| 1351 | 1350 |
| 1352 fDeviceCMDirty = true; | 1351 fDeviceCMDirty = true; |
| 1353 fLocalBoundsCompareTypeDirty = true; | 1352 fCachedLocalClipBoundsDirty = true; |
| 1354 | 1353 |
| 1355 // todo: signal fClipStack that we have a region, and therefore (I guess) | 1354 // todo: signal fClipStack that we have a region, and therefore (I guess) |
| 1356 // we have to ignore it, and use the region directly? | 1355 // we have to ignore it, and use the region directly? |
| 1357 fClipStack.clipDevRect(rgn.getBounds(), op); | 1356 fClipStack.clipDevRect(rgn.getBounds(), op); |
| 1358 | 1357 |
| 1359 return fMCRec->fRasterClip->op(rgn, op); | 1358 return fMCRec->fRasterClip->op(rgn, op); |
| 1360 } | 1359 } |
| 1361 | 1360 |
| 1362 #ifdef SK_DEBUG | 1361 #ifdef SK_DEBUG |
| 1363 void SkCanvas::validateClip() const { | 1362 void SkCanvas::validateClip() const { |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1416 break; | 1415 break; |
| 1417 case SkClipStack::Element::kEmpty_Type: | 1416 case SkClipStack::Element::kEmpty_Type: |
| 1418 visitor->clipRect(kEmpty, SkRegion::kIntersect_Op, false); | 1417 visitor->clipRect(kEmpty, SkRegion::kIntersect_Op, false); |
| 1419 break; | 1418 break; |
| 1420 } | 1419 } |
| 1421 } | 1420 } |
| 1422 } | 1421 } |
| 1423 | 1422 |
| 1424 /////////////////////////////////////////////////////////////////////////////// | 1423 /////////////////////////////////////////////////////////////////////////////// |
| 1425 | 1424 |
| 1426 void SkCanvas::computeLocalClipBoundsCompareType() const { | |
| 1427 SkRect r; | |
| 1428 | |
| 1429 if (!this->getClipBounds(&r)) { | |
| 1430 fLocalBoundsCompareType.setEmpty(); | |
| 1431 } else { | |
| 1432 fLocalBoundsCompareType.set(SkScalarToCompareType(r.fLeft), | |
| 1433 SkScalarToCompareType(r.fTop), | |
| 1434 SkScalarToCompareType(r.fRight), | |
| 1435 SkScalarToCompareType(r.fBottom)); | |
| 1436 } | |
| 1437 } | |
| 1438 | |
| 1439 bool SkCanvas::quickReject(const SkRect& rect) const { | 1425 bool SkCanvas::quickReject(const SkRect& rect) const { |
| 1440 | 1426 |
| 1441 if (!rect.isFinite()) | 1427 if (!rect.isFinite()) |
| 1442 return true; | 1428 return true; |
| 1443 | 1429 |
| 1444 if (fMCRec->fRasterClip->isEmpty()) { | 1430 if (fMCRec->fRasterClip->isEmpty()) { |
| 1445 return true; | 1431 return true; |
| 1446 } | 1432 } |
| 1447 | 1433 |
| 1448 if (fMCRec->fMatrix->hasPerspective()) { | 1434 if (fMCRec->fMatrix->hasPerspective()) { |
| 1449 SkRect dst; | 1435 SkRect dst; |
| 1450 fMCRec->fMatrix->mapRect(&dst, rect); | 1436 fMCRec->fMatrix->mapRect(&dst, rect); |
| 1451 SkIRect idst; | 1437 SkIRect idst; |
| 1452 dst.roundOut(&idst); | 1438 dst.roundOut(&idst); |
| 1453 return !SkIRect::Intersects(idst, fMCRec->fRasterClip->getBounds()); | 1439 return !SkIRect::Intersects(idst, fMCRec->fRasterClip->getBounds()); |
| 1454 } else { | 1440 } else { |
| 1455 const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType(); | 1441 const SkRect& clipR = this->getLocalClipBounds(); |
| 1456 | 1442 |
| 1457 // for speed, do the most likely reject compares first | 1443 // for speed, do the most likely reject compares first |
| 1458 SkScalarCompareType userT = SkScalarToCompareType(rect.fTop); | 1444 // TODO: should we use | instead, or compare all 4 at once? |
| 1459 SkScalarCompareType userB = SkScalarToCompareType(rect.fBottom); | 1445 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) { |
| 1460 if (userT >= clipR.fBottom || userB <= clipR.fTop) { | |
| 1461 return true; | 1446 return true; |
| 1462 } | 1447 } |
| 1463 SkScalarCompareType userL = SkScalarToCompareType(rect.fLeft); | 1448 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) { |
| 1464 SkScalarCompareType userR = SkScalarToCompareType(rect.fRight); | |
| 1465 if (userL >= clipR.fRight || userR <= clipR.fLeft) { | |
| 1466 return true; | 1449 return true; |
| 1467 } | 1450 } |
| 1468 return false; | 1451 return false; |
| 1469 } | 1452 } |
| 1470 } | 1453 } |
| 1471 | 1454 |
| 1472 bool SkCanvas::quickReject(const SkPath& path) const { | 1455 bool SkCanvas::quickReject(const SkPath& path) const { |
| 1473 return path.isEmpty() || this->quickReject(path.getBounds()); | 1456 return path.isEmpty() || this->quickReject(path.getBounds()); |
| 1474 } | 1457 } |
| 1475 | 1458 |
| (...skipping 744 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2220 return *paint; | 2203 return *paint; |
| 2221 } | 2204 } |
| 2222 | 2205 |
| 2223 const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); } | 2206 const SkRegion& SkCanvas::LayerIter::clip() const { return fImpl->getClip(); } |
| 2224 int SkCanvas::LayerIter::x() const { return fImpl->getX(); } | 2207 int SkCanvas::LayerIter::x() const { return fImpl->getX(); } |
| 2225 int SkCanvas::LayerIter::y() const { return fImpl->getY(); } | 2208 int SkCanvas::LayerIter::y() const { return fImpl->getY(); } |
| 2226 | 2209 |
| 2227 /////////////////////////////////////////////////////////////////////////////// | 2210 /////////////////////////////////////////////////////////////////////////////// |
| 2228 | 2211 |
| 2229 SkCanvas::ClipVisitor::~ClipVisitor() { } | 2212 SkCanvas::ClipVisitor::~ClipVisitor() { } |
| OLD | NEW |