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 |