OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2008 The Android Open Source Project | 2 * Copyright 2008 The Android Open Source Project |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkBitmapDevice.h" | 8 #include "SkBitmapDevice.h" |
9 #include "SkCanvas.h" | 9 #include "SkCanvas.h" |
10 #include "SkCanvasPriv.h" | 10 #include "SkCanvasPriv.h" |
11 #include "SkClipStack.h" | 11 #include "SkClipStack.h" |
12 #include "SkColorFilter.h" | 12 #include "SkColorFilter.h" |
13 #include "SkDraw.h" | 13 #include "SkDraw.h" |
14 #include "SkDrawable.h" | 14 #include "SkDrawable.h" |
15 #include "SkDrawFilter.h" | 15 #include "SkDrawFilter.h" |
16 #include "SkDrawLooper.h" | 16 #include "SkDrawLooper.h" |
17 #include "SkErrorInternals.h" | 17 #include "SkErrorInternals.h" |
18 #include "SkImage.h" | 18 #include "SkImage.h" |
19 #include "SkImage_Base.h" | 19 #include "SkImage_Base.h" |
20 #include "SkImageFilter.h" | 20 #include "SkImageFilter.h" |
21 #include "SkImageFilterCache.h" | 21 #include "SkImageFilterCache.h" |
22 #include "SkLatticeIter.h" | 22 #include "SkLatticeIter.h" |
23 #include "SkMatrixUtils.h" | 23 #include "SkMatrixUtils.h" |
24 #include "SkMetaData.h" | 24 #include "SkMetaData.h" |
25 #include "SkNx.h" | |
25 #include "SkPaintPriv.h" | 26 #include "SkPaintPriv.h" |
26 #include "SkPatchUtils.h" | 27 #include "SkPatchUtils.h" |
27 #include "SkPicture.h" | 28 #include "SkPicture.h" |
28 #include "SkRasterClip.h" | 29 #include "SkRasterClip.h" |
29 #include "SkReadPixelsRec.h" | 30 #include "SkReadPixelsRec.h" |
30 #include "SkRRect.h" | 31 #include "SkRRect.h" |
31 #include "SkSmallAllocator.h" | 32 #include "SkSmallAllocator.h" |
32 #include "SkSpecialImage.h" | 33 #include "SkSpecialImage.h" |
33 #include "SkSurface_Base.h" | 34 #include "SkSurface_Base.h" |
34 #include "SkTextBlob.h" | 35 #include "SkTextBlob.h" |
(...skipping 590 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
625 AutoDrawLooper looper(this, fProps, paint, false, bounds); \ | 626 AutoDrawLooper looper(this, fProps, paint, false, bounds); \ |
626 while (looper.next(type)) { \ | 627 while (looper.next(type)) { \ |
627 SkDrawIter iter(this); | 628 SkDrawIter iter(this); |
628 | 629 |
629 #define LOOPER_END } | 630 #define LOOPER_END } |
630 | 631 |
631 //////////////////////////////////////////////////////////////////////////// | 632 //////////////////////////////////////////////////////////////////////////// |
632 | 633 |
633 void SkCanvas::resetForNextPicture(const SkIRect& bounds) { | 634 void SkCanvas::resetForNextPicture(const SkIRect& bounds) { |
634 this->restoreToCount(1); | 635 this->restoreToCount(1); |
635 fCachedLocalClipBounds.setEmpty(); | |
636 fCachedLocalClipBoundsDirty = true; | |
637 fClipStack->reset(); | 636 fClipStack->reset(); |
638 fMCRec->reset(bounds); | 637 fMCRec->reset(bounds); |
639 | 638 |
640 // We're peering through a lot of structs here. Only at this scope do we | 639 // We're peering through a lot of structs here. Only at this scope do we |
641 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevi ce). | 640 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevi ce). |
642 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.siz e()); | 641 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.siz e()); |
642 this->setCachedClipDeviceBounds(bounds); | |
643 fConservativeIsScaleTranslate = true; | |
643 } | 644 } |
644 | 645 |
645 SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) { | 646 SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) { |
646 if (device && device->forceConservativeRasterClip()) { | 647 if (device && device->forceConservativeRasterClip()) { |
647 flags = InitFlags(flags | kConservativeRasterClip_InitFlag); | 648 flags = InitFlags(flags | kConservativeRasterClip_InitFlag); |
648 } | 649 } |
649 // Since init() is only called once by our constructors, it is safe to perfo rm this | 650 // Since init() is only called once by our constructors, it is safe to perfo rm this |
650 // const-cast. | 651 // const-cast. |
651 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativ eRasterClip_InitFlag); | 652 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativ eRasterClip_InitFlag); |
652 | 653 |
653 fCachedLocalClipBounds.setEmpty(); | |
654 fCachedLocalClipBoundsDirty = true; | |
655 fAllowSoftClip = true; | 654 fAllowSoftClip = true; |
656 fAllowSimplifyClip = false; | 655 fAllowSimplifyClip = false; |
657 fDeviceCMDirty = true; | 656 fDeviceCMDirty = true; |
658 fSaveCount = 1; | 657 fSaveCount = 1; |
659 fMetaData = nullptr; | 658 fMetaData = nullptr; |
660 #ifdef SK_EXPERIMENTAL_SHADOWING | 659 #ifdef SK_EXPERIMENTAL_SHADOWING |
661 fLights = nullptr; | 660 fLights = nullptr; |
662 #endif | 661 #endif |
663 | 662 |
664 fClipStack.reset(new SkClipStack); | 663 fClipStack.reset(new SkClipStack); |
665 | 664 |
666 fMCRec = (MCRec*)fMCStack.push_back(); | 665 fMCRec = (MCRec*)fMCStack.push_back(); |
667 new (fMCRec) MCRec(fConservativeRasterClip); | 666 new (fMCRec) MCRec(fConservativeRasterClip); |
668 | 667 |
669 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage)); | 668 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage)); |
670 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage; | 669 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage; |
671 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRast erClip, | 670 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRast erClip, |
672 fMCRec->fMatrix); | 671 fMCRec->fMatrix); |
673 | 672 |
674 fMCRec->fTopLayer = fMCRec->fLayer; | 673 fMCRec->fTopLayer = fMCRec->fLayer; |
675 | 674 |
676 fSurfaceBase = nullptr; | 675 fSurfaceBase = nullptr; |
677 | 676 |
678 if (device) { | 677 if (device) { |
679 // The root device and the canvas should always have the same pixel geom etry | 678 // The root device and the canvas should always have the same pixel geom etry |
680 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry( )); | 679 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry( )); |
681 fMCRec->fLayer->fDevice = SkRef(device); | 680 fMCRec->fLayer->fDevice = SkRef(device); |
682 fMCRec->fRasterClip.setRect(device->getGlobalBounds()); | 681 fMCRec->fRasterClip.setRect(device->getGlobalBounds()); |
682 this->setCachedClipDeviceBounds(device->getGlobalBounds()); | |
683 fConservativeIsScaleTranslate = true; | |
683 } | 684 } |
685 | |
684 return device; | 686 return device; |
685 } | 687 } |
686 | 688 |
687 SkCanvas::SkCanvas() | 689 SkCanvas::SkCanvas() |
688 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) | 690 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) |
689 , fProps(SkSurfaceProps::kLegacyFontHost_InitType) | 691 , fProps(SkSurfaceProps::kLegacyFontHost_InitType) |
690 , fConservativeRasterClip(false) | 692 , fConservativeRasterClip(false) |
691 { | 693 { |
692 inc_canvas(); | 694 inc_canvas(); |
693 | 695 |
(...skipping 394 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1088 } | 1090 } |
1089 SkIRect ir; | 1091 SkIRect ir; |
1090 if (bounds) { | 1092 if (bounds) { |
1091 SkRect r; | 1093 SkRect r; |
1092 | 1094 |
1093 ctm.mapRect(&r, *bounds); | 1095 ctm.mapRect(&r, *bounds); |
1094 r.roundOut(&ir); | 1096 r.roundOut(&ir); |
1095 // early exit if the layer's bounds are clipped out | 1097 // early exit if the layer's bounds are clipped out |
1096 if (!ir.intersect(clipBounds)) { | 1098 if (!ir.intersect(clipBounds)) { |
1097 if (BoundsAffectsClip(saveLayerFlags)) { | 1099 if (BoundsAffectsClip(saveLayerFlags)) { |
1098 fCachedLocalClipBoundsDirty = true; | |
1099 fMCRec->fRasterClip.setEmpty(); | 1100 fMCRec->fRasterClip.setEmpty(); |
1101 fDeviceClipBounds.setEmpty(); | |
1100 } | 1102 } |
1101 return false; | 1103 return false; |
1102 } | 1104 } |
1103 } else { // no user bounds, so just use the clip | 1105 } else { // no user bounds, so just use the clip |
1104 ir = clipBounds; | 1106 ir = clipBounds; |
1105 } | 1107 } |
1106 SkASSERT(!ir.isEmpty()); | 1108 SkASSERT(!ir.isEmpty()); |
1107 | 1109 |
1108 if (BoundsAffectsClip(saveLayerFlags)) { | 1110 if (BoundsAffectsClip(saveLayerFlags)) { |
1109 // Simplify the current clips since they will be applied properly during restore() | 1111 // Simplify the current clips since they will be applied properly during restore() |
1110 fCachedLocalClipBoundsDirty = true; | |
1111 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op); | 1112 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op); |
1112 fMCRec->fRasterClip.setRect(ir); | 1113 fMCRec->fRasterClip.setRect(ir); |
1114 this->setCachedClipDeviceBounds(ir); | |
1113 } | 1115 } |
1114 | 1116 |
1115 if (intersection) { | 1117 if (intersection) { |
1116 *intersection = ir; | 1118 *intersection = ir; |
1117 } | 1119 } |
1118 return true; | 1120 return true; |
1119 } | 1121 } |
1120 | 1122 |
1121 | 1123 |
1122 int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) { | 1124 int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) { |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1294 SkPaint tmpPaint; | 1296 SkPaint tmpPaint; |
1295 tmpPaint.setAlpha(alpha); | 1297 tmpPaint.setAlpha(alpha); |
1296 return this->saveLayer(bounds, &tmpPaint); | 1298 return this->saveLayer(bounds, &tmpPaint); |
1297 } | 1299 } |
1298 } | 1300 } |
1299 | 1301 |
1300 void SkCanvas::internalRestore() { | 1302 void SkCanvas::internalRestore() { |
1301 SkASSERT(fMCStack.count() != 0); | 1303 SkASSERT(fMCStack.count() != 0); |
1302 | 1304 |
1303 fDeviceCMDirty = true; | 1305 fDeviceCMDirty = true; |
1304 fCachedLocalClipBoundsDirty = true; | |
1305 | 1306 |
1306 fClipStack->restore(); | 1307 fClipStack->restore(); |
1307 | 1308 |
1308 // reserve our layer (if any) | 1309 // reserve our layer (if any) |
1309 DeviceCM* layer = fMCRec->fLayer; // may be null | 1310 DeviceCM* layer = fMCRec->fLayer; // may be null |
1310 // now detach it from fMCRec so we can pop(). Gets freed after its drawn | 1311 // now detach it from fMCRec so we can pop(). Gets freed after its drawn |
1311 fMCRec->fLayer = nullptr; | 1312 fMCRec->fLayer = nullptr; |
1312 | 1313 |
1313 // now do the normal restore() | 1314 // now do the normal restore() |
1314 fMCRec->~MCRec(); // balanced in save() | 1315 fMCRec->~MCRec(); // balanced in save() |
(...skipping 13 matching lines...) Expand all Loading... | |
1328 // reset this, since internalDrawDevice will have set it to true | 1329 // reset this, since internalDrawDevice will have set it to true |
1329 fDeviceCMDirty = true; | 1330 fDeviceCMDirty = true; |
1330 delete layer; | 1331 delete layer; |
1331 } else { | 1332 } else { |
1332 // we're at the root | 1333 // we're at the root |
1333 SkASSERT(layer == (void*)fDeviceCMStorage); | 1334 SkASSERT(layer == (void*)fDeviceCMStorage); |
1334 layer->~DeviceCM(); | 1335 layer->~DeviceCM(); |
1335 // no need to update fMCRec, 'cause we're killing the canvas | 1336 // no need to update fMCRec, 'cause we're killing the canvas |
1336 } | 1337 } |
1337 } | 1338 } |
1339 | |
1340 if (fMCRec) { | |
1341 fConservativeIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate(); | |
1342 this->setCachedClipDeviceBounds(fMCRec->fRasterClip.getBounds()); | |
1343 } | |
1338 } | 1344 } |
1339 | 1345 |
1340 sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceP rops* props) { | 1346 sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceP rops* props) { |
1341 if (nullptr == props) { | 1347 if (nullptr == props) { |
1342 props = &fProps; | 1348 props = &fProps; |
1343 } | 1349 } |
1344 return this->onNewSurface(info, *props); | 1350 return this->onNewSurface(info, *props); |
1345 } | 1351 } |
1346 | 1352 |
1347 sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurface Props& props) { | 1353 sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurface Props& props) { |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1482 this->concat(m); | 1488 this->concat(m); |
1483 } | 1489 } |
1484 | 1490 |
1485 void SkCanvas::concat(const SkMatrix& matrix) { | 1491 void SkCanvas::concat(const SkMatrix& matrix) { |
1486 if (matrix.isIdentity()) { | 1492 if (matrix.isIdentity()) { |
1487 return; | 1493 return; |
1488 } | 1494 } |
1489 | 1495 |
1490 this->checkForDeferredSave(); | 1496 this->checkForDeferredSave(); |
1491 fDeviceCMDirty = true; | 1497 fDeviceCMDirty = true; |
1492 fCachedLocalClipBoundsDirty = true; | |
1493 fMCRec->fMatrix.preConcat(matrix); | 1498 fMCRec->fMatrix.preConcat(matrix); |
1494 | 1499 |
1500 // We may miss some rare cases here. Ex: rotate 45 then -45. But being dat a | |
1501 // independ of preConcat() may allow us to go faster. | |
1502 fConservativeIsScaleTranslate = fConservativeIsScaleTranslate && matrix.isSc aleTranslate(); | |
1495 this->didConcat(matrix); | 1503 this->didConcat(matrix); |
1496 } | 1504 } |
1497 | 1505 |
1498 void SkCanvas::internalSetMatrix(const SkMatrix& matrix) { | 1506 void SkCanvas::internalSetMatrix(const SkMatrix& matrix) { |
1499 fDeviceCMDirty = true; | 1507 fDeviceCMDirty = true; |
1500 fCachedLocalClipBoundsDirty = true; | |
1501 fMCRec->fMatrix = matrix; | 1508 fMCRec->fMatrix = matrix; |
1502 } | 1509 } |
1503 | 1510 |
1504 void SkCanvas::setMatrix(const SkMatrix& matrix) { | 1511 void SkCanvas::setMatrix(const SkMatrix& matrix) { |
1505 this->checkForDeferredSave(); | 1512 this->checkForDeferredSave(); |
1506 this->internalSetMatrix(matrix); | 1513 this->internalSetMatrix(matrix); |
1514 fConservativeIsScaleTranslate = matrix.isScaleTranslate(); | |
1507 this->didSetMatrix(matrix); | 1515 this->didSetMatrix(matrix); |
1508 } | 1516 } |
1509 | 1517 |
1510 void SkCanvas::resetMatrix() { | 1518 void SkCanvas::resetMatrix() { |
1511 this->setMatrix(SkMatrix::I()); | 1519 this->setMatrix(SkMatrix::I()); |
1512 } | 1520 } |
1513 | 1521 |
1514 #ifdef SK_EXPERIMENTAL_SHADOWING | 1522 #ifdef SK_EXPERIMENTAL_SHADOWING |
1515 void SkCanvas::translateZ(SkScalar z) { | 1523 void SkCanvas::translateZ(SkScalar z) { |
1516 this->checkForDeferredSave(); | 1524 this->checkForDeferredSave(); |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1597 rect.left(), rect.top(), rect.right(), rect.bottom()); | 1605 rect.left(), rect.top(), rect.right(), rect.bottom()); |
1598 #endif | 1606 #endif |
1599 return; | 1607 return; |
1600 } | 1608 } |
1601 } | 1609 } |
1602 #endif | 1610 #endif |
1603 | 1611 |
1604 AutoValidateClip avc(this); | 1612 AutoValidateClip avc(this); |
1605 | 1613 |
1606 fDeviceCMDirty = true; | 1614 fDeviceCMDirty = true; |
1607 fCachedLocalClipBoundsDirty = true; | |
1608 | 1615 |
1609 if (isScaleTrans) { | 1616 if (isScaleTrans) { |
1610 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle; | 1617 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle; |
1611 fClipStack->clipDevRect(devR, op, isAA); | 1618 fClipStack->clipDevRect(devR, op, isAA); |
1612 fMCRec->fRasterClip.op(devR, this->getTopLayerBounds(), op, isAA); | 1619 fMCRec->fRasterClip.op(devR, this->getTopLayerBounds(), op, isAA); |
1613 } else { | 1620 } else { |
1614 // since we're rotated or some such thing, we convert the rect to a path | 1621 // since we're rotated or some such thing, we convert the rect to a path |
1615 // and clip against that, since it can handle any matrix. However, to | 1622 // and clip against that, since it can handle any matrix. However, to |
1616 // avoid recursion in the case where we are subclassed (e.g. Pictures) | 1623 // avoid recursion in the case where we are subclassed (e.g. Pictures) |
1617 // we explicitly call "our" version of clipPath. | 1624 // we explicitly call "our" version of clipPath. |
1618 SkPath path; | 1625 SkPath path; |
1619 | 1626 |
1620 path.addRect(rect); | 1627 path.addRect(rect); |
1621 this->SkCanvas::onClipPath(path, op, edgeStyle); | 1628 this->SkCanvas::onClipPath(path, op, edgeStyle); |
1622 } | 1629 } |
1630 | |
1631 this->setCachedClipDeviceBounds(fMCRec->fRasterClip.getBounds()); | |
1623 } | 1632 } |
1624 | 1633 |
1625 void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { | 1634 void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { |
1626 this->checkForDeferredSave(); | 1635 this->checkForDeferredSave(); |
1627 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; | 1636 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; |
1628 if (rrect.isRect()) { | 1637 if (rrect.isRect()) { |
1629 this->onClipRect(rrect.getBounds(), op, edgeStyle); | 1638 this->onClipRect(rrect.getBounds(), op, edgeStyle); |
1630 } else { | 1639 } else { |
1631 this->onClipRRect(rrect, op, edgeStyle); | 1640 this->onClipRRect(rrect, op, edgeStyle); |
1632 } | 1641 } |
1633 } | 1642 } |
1634 | 1643 |
1635 void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { | 1644 void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { |
1636 SkRRect transformedRRect; | 1645 SkRRect transformedRRect; |
1637 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) { | 1646 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) { |
1638 AutoValidateClip avc(this); | 1647 AutoValidateClip avc(this); |
1639 | 1648 |
1640 fDeviceCMDirty = true; | 1649 fDeviceCMDirty = true; |
1641 fCachedLocalClipBoundsDirty = true; | |
1642 if (!fAllowSoftClip) { | 1650 if (!fAllowSoftClip) { |
1643 edgeStyle = kHard_ClipEdgeStyle; | 1651 edgeStyle = kHard_ClipEdgeStyle; |
1644 } | 1652 } |
1645 | 1653 |
1646 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == ed geStyle); | 1654 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == ed geStyle); |
1647 | 1655 |
1648 fMCRec->fRasterClip.op(transformedRRect, this->getTopLayerBounds(), op, | 1656 fMCRec->fRasterClip.op(transformedRRect, this->getTopLayerBounds(), op, |
1649 kSoft_ClipEdgeStyle == edgeStyle); | 1657 kSoft_ClipEdgeStyle == edgeStyle); |
1658 this->setCachedClipDeviceBounds(fMCRec->fRasterClip.getBounds()); | |
1650 return; | 1659 return; |
1651 } | 1660 } |
1652 | 1661 |
1653 SkPath path; | 1662 SkPath path; |
1654 path.addRRect(rrect); | 1663 path.addRRect(rrect); |
1655 // call the non-virtual version | 1664 // call the non-virtual version |
1656 this->SkCanvas::onClipPath(path, op, edgeStyle); | 1665 this->SkCanvas::onClipPath(path, op, edgeStyle); |
1657 } | 1666 } |
1658 | 1667 |
1659 void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { | 1668 void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1695 fClipStack->clipEmpty(); | 1704 fClipStack->clipEmpty(); |
1696 (void)fMCRec->fRasterClip.setEmpty(); | 1705 (void)fMCRec->fRasterClip.setEmpty(); |
1697 return; | 1706 return; |
1698 } | 1707 } |
1699 } | 1708 } |
1700 #endif | 1709 #endif |
1701 | 1710 |
1702 AutoValidateClip avc(this); | 1711 AutoValidateClip avc(this); |
1703 | 1712 |
1704 fDeviceCMDirty = true; | 1713 fDeviceCMDirty = true; |
1705 fCachedLocalClipBoundsDirty = true; | |
1706 if (!fAllowSoftClip) { | 1714 if (!fAllowSoftClip) { |
1707 edgeStyle = kHard_ClipEdgeStyle; | 1715 edgeStyle = kHard_ClipEdgeStyle; |
1708 } | 1716 } |
1709 | 1717 |
1710 SkPath devPath; | 1718 SkPath devPath; |
1711 path.transform(fMCRec->fMatrix, &devPath); | 1719 path.transform(fMCRec->fMatrix, &devPath); |
1712 | 1720 |
1713 // Check if the transfomation, or the original path itself | 1721 // Check if the transfomation, or the original path itself |
1714 // made us empty. Note this can also happen if we contained NaN | 1722 // made us empty. Note this can also happen if we contained NaN |
1715 // values. computing the bounds detects this, and will set our | 1723 // values. computing the bounds detects this, and will set our |
(...skipping 10 matching lines...) Expand all Loading... | |
1726 if (fAllowSimplifyClip) { | 1734 if (fAllowSimplifyClip) { |
1727 bool clipIsAA = getClipStack()->asPath(&devPath); | 1735 bool clipIsAA = getClipStack()->asPath(&devPath); |
1728 if (clipIsAA) { | 1736 if (clipIsAA) { |
1729 edgeStyle = kSoft_ClipEdgeStyle; | 1737 edgeStyle = kSoft_ClipEdgeStyle; |
1730 } | 1738 } |
1731 | 1739 |
1732 op = SkRegion::kReplace_Op; | 1740 op = SkRegion::kReplace_Op; |
1733 } | 1741 } |
1734 | 1742 |
1735 fMCRec->fRasterClip.op(devPath, this->getTopLayerBounds(), op, edgeStyle); | 1743 fMCRec->fRasterClip.op(devPath, this->getTopLayerBounds(), op, edgeStyle); |
1744 this->setCachedClipDeviceBounds(fMCRec->fRasterClip.getBounds()); | |
1736 } | 1745 } |
1737 | 1746 |
1738 void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { | 1747 void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { |
1739 this->checkForDeferredSave(); | 1748 this->checkForDeferredSave(); |
1740 this->onClipRegion(rgn, op); | 1749 this->onClipRegion(rgn, op); |
1741 } | 1750 } |
1742 | 1751 |
1743 void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) { | 1752 void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) { |
1744 AutoValidateClip avc(this); | 1753 AutoValidateClip avc(this); |
1745 | 1754 |
1746 fDeviceCMDirty = true; | 1755 fDeviceCMDirty = true; |
1747 fCachedLocalClipBoundsDirty = true; | |
1748 | 1756 |
1749 // todo: signal fClipStack that we have a region, and therefore (I guess) | 1757 // todo: signal fClipStack that we have a region, and therefore (I guess) |
1750 // we have to ignore it, and use the region directly? | 1758 // we have to ignore it, and use the region directly? |
1751 fClipStack->clipDevRect(rgn.getBounds(), op); | 1759 fClipStack->clipDevRect(rgn.getBounds(), op); |
1752 | 1760 |
1753 fMCRec->fRasterClip.op(rgn, op); | 1761 fMCRec->fRasterClip.op(rgn, op); |
1762 this->setCachedClipDeviceBounds(fMCRec->fRasterClip.getBounds()); | |
1754 } | 1763 } |
1755 | 1764 |
1756 #ifdef SK_DEBUG | 1765 #ifdef SK_DEBUG |
1757 void SkCanvas::validateClip() const { | 1766 void SkCanvas::validateClip() const { |
1758 // construct clipRgn from the clipstack | 1767 // construct clipRgn from the clipstack |
1759 const SkBaseDevice* device = this->getDevice(); | 1768 const SkBaseDevice* device = this->getDevice(); |
1760 if (!device) { | 1769 if (!device) { |
1761 SkASSERT(this->isClipEmpty()); | 1770 SkASSERT(this->isClipEmpty()); |
1762 return; | 1771 return; |
1763 } | 1772 } |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1800 /////////////////////////////////////////////////////////////////////////////// | 1809 /////////////////////////////////////////////////////////////////////////////// |
1801 | 1810 |
1802 bool SkCanvas::isClipEmpty() const { | 1811 bool SkCanvas::isClipEmpty() const { |
1803 return fMCRec->fRasterClip.isEmpty(); | 1812 return fMCRec->fRasterClip.isEmpty(); |
1804 } | 1813 } |
1805 | 1814 |
1806 bool SkCanvas::isClipRect() const { | 1815 bool SkCanvas::isClipRect() const { |
1807 return fMCRec->fRasterClip.isRect(); | 1816 return fMCRec->fRasterClip.isRect(); |
1808 } | 1817 } |
1809 | 1818 |
1810 bool SkCanvas::quickReject(const SkRect& rect) const { | 1819 static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) { |
1811 if (!rect.isFinite()) | 1820 #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 |
1812 return true; | 1821 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec); |
1822 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec); | |
1823 __m128 mask = _mm_cmplt_ps(lLtT, RrBb); | |
1824 return 0xF != _mm_movemask_ps(mask); | |
1825 #elif defined(SK_ARM_HAS_NEON) | |
1826 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0]; | |
1827 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1]; | |
1828 uint32x4_t mask = vcltq_f32(lLtT, RrBb); | |
1829 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask); | |
1830 #else | |
1831 SkRect devRectAsRect; | |
1832 SkRect devClipAsRect; | |
1833 devRect.store(&devRectAsRect.fLeft); | |
1834 devClip.store(&devClipAsRect.fLeft); | |
1835 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect); | |
1836 #endif | |
1837 } | |
1813 | 1838 |
1814 if (fMCRec->fRasterClip.isEmpty()) { | 1839 // It's important for this function to not be inlined. Otherwise the compiler w ill share code |
1815 return true; | 1840 // between the fast path and the slow path, resulting in two slow paths. |
1841 static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRe ct& deviceClip, | |
1842 const SkMatrix& matrix) { | |
1843 SkRect deviceRect; | |
1844 matrix.mapRect(&deviceRect, src); | |
1845 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip); | |
1846 } | |
1847 | |
1848 bool SkCanvas::quickReject(const SkRect& src) const { | |
reed1
2016/08/11 18:36:28
SkASSERT(compute_float_from_rasterclip_bounds == f
msarett
2016/08/11 20:15:16
Done.
| |
1849 if (!fConservativeIsScaleTranslate) { | |
1850 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix); | |
1816 } | 1851 } |
1817 | 1852 |
1818 if (fMCRec->fMatrix.hasPerspective()) { | 1853 // We inline the implementation of mapScaleTranslate() for the fast path. |
1819 SkRect dst; | 1854 float sx = fMCRec->fMatrix.getScaleX(); |
1820 fMCRec->fMatrix.mapRect(&dst, rect); | 1855 float sy = fMCRec->fMatrix.getScaleY(); |
1821 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBound s()); | 1856 float tx = fMCRec->fMatrix.getTranslateX(); |
1822 } else { | 1857 float ty = fMCRec->fMatrix.getTranslateY(); |
1823 const SkRect& clipR = this->getLocalClipBounds(); | 1858 Sk4f scale(sx, sy, sx, sy); |
1859 Sk4f trans(tx, ty, tx, ty); | |
1824 | 1860 |
1825 // for speed, do the most likely reject compares first | 1861 // Apply matrix. |
1826 // TODO: should we use | instead, or compare all 4 at once? | 1862 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans; |
1827 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) { | 1863 |
1828 return true; | 1864 // Make sure left < right, top < bottom. |
1829 } | 1865 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]); |
1830 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) { | 1866 Sk4f min = Sk4f::Min(ltrb, rblt); |
1831 return true; | 1867 Sk4f max = Sk4f::Max(ltrb, rblt); |
1832 } | 1868 // We can extract either pair [0,1] or [2,3] from min and max and be correct , but on |
1833 return false; | 1869 // ARM this sequence generates the fastest (a single instruction). |
1834 } | 1870 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]); |
1871 | |
1872 // Check if the device rect is NaN or outside the clip. | |
1873 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft)); | |
1835 } | 1874 } |
1836 | 1875 |
1837 bool SkCanvas::quickReject(const SkPath& path) const { | 1876 bool SkCanvas::quickReject(const SkPath& path) const { |
1838 return path.isEmpty() || this->quickReject(path.getBounds()); | 1877 return path.isEmpty() || this->quickReject(path.getBounds()); |
1839 } | 1878 } |
1840 | 1879 |
1841 bool SkCanvas::getClipBounds(SkRect* bounds) const { | 1880 bool SkCanvas::getClipBounds(SkRect* bounds) const { |
1842 SkIRect ibounds; | 1881 SkIRect ibounds; |
1843 if (!this->getClipDeviceBounds(&ibounds)) { | 1882 if (!this->getClipDeviceBounds(&ibounds)) { |
1844 return false; | 1883 return false; |
(...skipping 28 matching lines...) Expand all Loading... | |
1873 } | 1912 } |
1874 return false; | 1913 return false; |
1875 } | 1914 } |
1876 | 1915 |
1877 if (bounds) { | 1916 if (bounds) { |
1878 *bounds = clip.getBounds(); | 1917 *bounds = clip.getBounds(); |
1879 } | 1918 } |
1880 return true; | 1919 return true; |
1881 } | 1920 } |
1882 | 1921 |
1922 void SkCanvas::setCachedClipDeviceBounds(const SkIRect& bounds) { | |
1923 // Expand bounds out by 1 in case we are anti-aliasing. We store the | |
1924 // bounds as floats to enable a faster quick reject implementation. | |
1925 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&fDevice ClipBounds.fLeft); | |
1926 } | |
1927 | |
1883 const SkMatrix& SkCanvas::getTotalMatrix() const { | 1928 const SkMatrix& SkCanvas::getTotalMatrix() const { |
1884 return fMCRec->fMatrix; | 1929 return fMCRec->fMatrix; |
1885 } | 1930 } |
1886 | 1931 |
1887 const SkRegion& SkCanvas::internal_private_getTotalClip() const { | 1932 const SkRegion& SkCanvas::internal_private_getTotalClip() const { |
1888 return fMCRec->fRasterClip.forceGetBW(); | 1933 return fMCRec->fRasterClip.forceGetBW(); |
1889 } | 1934 } |
1890 | 1935 |
1891 GrDrawContext* SkCanvas::internal_private_accessTopLayerDrawContext() { | 1936 GrDrawContext* SkCanvas::internal_private_accessTopLayerDrawContext() { |
1892 SkBaseDevice* dev = this->getTopDevice(); | 1937 SkBaseDevice* dev = this->getTopDevice(); |
(...skipping 1275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3168 | 3213 |
3169 SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() { | 3214 SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() { |
3170 fCanvas->restoreToCount(fSaveCount); | 3215 fCanvas->restoreToCount(fSaveCount); |
3171 } | 3216 } |
3172 | 3217 |
3173 #ifdef SK_SUPPORT_LEGACY_NEW_SURFACE_API | 3218 #ifdef SK_SUPPORT_LEGACY_NEW_SURFACE_API |
3174 SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* p rops) { | 3219 SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* p rops) { |
3175 return this->makeSurface(info, props).release(); | 3220 return this->makeSurface(info, props).release(); |
3176 } | 3221 } |
3177 #endif | 3222 #endif |
OLD | NEW |