| 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 588 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 623 #define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \ | 624 #define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \ |
| 624 this->predrawNotify(bounds, &paint, auxOpaque); \ | 625 this->predrawNotify(bounds, &paint, auxOpaque); \ |
| 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 |
| 634 static inline SkRect qr_clip_bounds(const SkIRect& bounds) { |
| 635 if (bounds.isEmpty()) { |
| 636 return SkRect::MakeEmpty(); |
| 637 } |
| 638 |
| 639 // Expand bounds out by 1 in case we are anti-aliasing. We store the |
| 640 // bounds as floats to enable a faster quick reject implementation. |
| 641 SkRect dst; |
| 642 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLe
ft); |
| 643 return dst; |
| 644 } |
| 645 |
| 633 void SkCanvas::resetForNextPicture(const SkIRect& bounds) { | 646 void SkCanvas::resetForNextPicture(const SkIRect& bounds) { |
| 634 this->restoreToCount(1); | 647 this->restoreToCount(1); |
| 635 fCachedLocalClipBounds.setEmpty(); | |
| 636 fCachedLocalClipBoundsDirty = true; | |
| 637 fClipStack->reset(); | 648 fClipStack->reset(); |
| 638 fMCRec->reset(bounds); | 649 fMCRec->reset(bounds); |
| 639 | 650 |
| 640 // We're peering through a lot of structs here. Only at this scope do we | 651 // 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). | 652 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevi
ce). |
| 642 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.siz
e()); | 653 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.siz
e()); |
| 654 fDeviceClipBounds = qr_clip_bounds(bounds); |
| 655 fConservativeIsScaleTranslate = true; |
| 643 } | 656 } |
| 644 | 657 |
| 645 SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) { | 658 SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) { |
| 646 if (device && device->forceConservativeRasterClip()) { | 659 if (device && device->forceConservativeRasterClip()) { |
| 647 flags = InitFlags(flags | kConservativeRasterClip_InitFlag); | 660 flags = InitFlags(flags | kConservativeRasterClip_InitFlag); |
| 648 } | 661 } |
| 649 // Since init() is only called once by our constructors, it is safe to perfo
rm this | 662 // Since init() is only called once by our constructors, it is safe to perfo
rm this |
| 650 // const-cast. | 663 // const-cast. |
| 651 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativ
eRasterClip_InitFlag); | 664 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativ
eRasterClip_InitFlag); |
| 652 | 665 |
| 653 fCachedLocalClipBounds.setEmpty(); | |
| 654 fCachedLocalClipBoundsDirty = true; | |
| 655 fAllowSoftClip = true; | 666 fAllowSoftClip = true; |
| 656 fAllowSimplifyClip = false; | 667 fAllowSimplifyClip = false; |
| 657 fDeviceCMDirty = true; | 668 fDeviceCMDirty = true; |
| 658 fSaveCount = 1; | 669 fSaveCount = 1; |
| 659 fMetaData = nullptr; | 670 fMetaData = nullptr; |
| 660 #ifdef SK_EXPERIMENTAL_SHADOWING | 671 #ifdef SK_EXPERIMENTAL_SHADOWING |
| 661 fLights = nullptr; | 672 fLights = nullptr; |
| 662 #endif | 673 #endif |
| 663 | 674 |
| 664 fClipStack.reset(new SkClipStack); | 675 fClipStack.reset(new SkClipStack); |
| 665 | 676 |
| 666 fMCRec = (MCRec*)fMCStack.push_back(); | 677 fMCRec = (MCRec*)fMCStack.push_back(); |
| 667 new (fMCRec) MCRec(fConservativeRasterClip); | 678 new (fMCRec) MCRec(fConservativeRasterClip); |
| 668 | 679 |
| 669 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage)); | 680 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage)); |
| 670 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage; | 681 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage; |
| 671 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRast
erClip, | 682 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRast
erClip, |
| 672 fMCRec->fMatrix); | 683 fMCRec->fMatrix); |
| 673 | 684 |
| 674 fMCRec->fTopLayer = fMCRec->fLayer; | 685 fMCRec->fTopLayer = fMCRec->fLayer; |
| 675 | 686 |
| 676 fSurfaceBase = nullptr; | 687 fSurfaceBase = nullptr; |
| 677 | 688 |
| 678 if (device) { | 689 if (device) { |
| 679 // The root device and the canvas should always have the same pixel geom
etry | 690 // The root device and the canvas should always have the same pixel geom
etry |
| 680 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry(
)); | 691 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry(
)); |
| 681 fMCRec->fLayer->fDevice = SkRef(device); | 692 fMCRec->fLayer->fDevice = SkRef(device); |
| 682 fMCRec->fRasterClip.setRect(device->getGlobalBounds()); | 693 fMCRec->fRasterClip.setRect(device->getGlobalBounds()); |
| 694 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds()); |
| 695 fConservativeIsScaleTranslate = true; |
| 683 } | 696 } |
| 697 |
| 684 return device; | 698 return device; |
| 685 } | 699 } |
| 686 | 700 |
| 687 SkCanvas::SkCanvas() | 701 SkCanvas::SkCanvas() |
| 688 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) | 702 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) |
| 689 , fProps(SkSurfaceProps::kLegacyFontHost_InitType) | 703 , fProps(SkSurfaceProps::kLegacyFontHost_InitType) |
| 690 , fConservativeRasterClip(false) | 704 , fConservativeRasterClip(false) |
| 691 { | 705 { |
| 692 inc_canvas(); | 706 inc_canvas(); |
| 693 | 707 |
| (...skipping 394 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1088 } | 1102 } |
| 1089 SkIRect ir; | 1103 SkIRect ir; |
| 1090 if (bounds) { | 1104 if (bounds) { |
| 1091 SkRect r; | 1105 SkRect r; |
| 1092 | 1106 |
| 1093 ctm.mapRect(&r, *bounds); | 1107 ctm.mapRect(&r, *bounds); |
| 1094 r.roundOut(&ir); | 1108 r.roundOut(&ir); |
| 1095 // early exit if the layer's bounds are clipped out | 1109 // early exit if the layer's bounds are clipped out |
| 1096 if (!ir.intersect(clipBounds)) { | 1110 if (!ir.intersect(clipBounds)) { |
| 1097 if (BoundsAffectsClip(saveLayerFlags)) { | 1111 if (BoundsAffectsClip(saveLayerFlags)) { |
| 1098 fCachedLocalClipBoundsDirty = true; | |
| 1099 fMCRec->fRasterClip.setEmpty(); | 1112 fMCRec->fRasterClip.setEmpty(); |
| 1113 fDeviceClipBounds.setEmpty(); |
| 1100 } | 1114 } |
| 1101 return false; | 1115 return false; |
| 1102 } | 1116 } |
| 1103 } else { // no user bounds, so just use the clip | 1117 } else { // no user bounds, so just use the clip |
| 1104 ir = clipBounds; | 1118 ir = clipBounds; |
| 1105 } | 1119 } |
| 1106 SkASSERT(!ir.isEmpty()); | 1120 SkASSERT(!ir.isEmpty()); |
| 1107 | 1121 |
| 1108 if (BoundsAffectsClip(saveLayerFlags)) { | 1122 if (BoundsAffectsClip(saveLayerFlags)) { |
| 1109 // Simplify the current clips since they will be applied properly during
restore() | 1123 // Simplify the current clips since they will be applied properly during
restore() |
| 1110 fCachedLocalClipBoundsDirty = true; | |
| 1111 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op); | 1124 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op); |
| 1112 fMCRec->fRasterClip.setRect(ir); | 1125 fMCRec->fRasterClip.setRect(ir); |
| 1126 fDeviceClipBounds = qr_clip_bounds(ir); |
| 1113 } | 1127 } |
| 1114 | 1128 |
| 1115 if (intersection) { | 1129 if (intersection) { |
| 1116 *intersection = ir; | 1130 *intersection = ir; |
| 1117 } | 1131 } |
| 1118 return true; | 1132 return true; |
| 1119 } | 1133 } |
| 1120 | 1134 |
| 1121 | 1135 |
| 1122 int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) { | 1136 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; | 1308 SkPaint tmpPaint; |
| 1295 tmpPaint.setAlpha(alpha); | 1309 tmpPaint.setAlpha(alpha); |
| 1296 return this->saveLayer(bounds, &tmpPaint); | 1310 return this->saveLayer(bounds, &tmpPaint); |
| 1297 } | 1311 } |
| 1298 } | 1312 } |
| 1299 | 1313 |
| 1300 void SkCanvas::internalRestore() { | 1314 void SkCanvas::internalRestore() { |
| 1301 SkASSERT(fMCStack.count() != 0); | 1315 SkASSERT(fMCStack.count() != 0); |
| 1302 | 1316 |
| 1303 fDeviceCMDirty = true; | 1317 fDeviceCMDirty = true; |
| 1304 fCachedLocalClipBoundsDirty = true; | |
| 1305 | 1318 |
| 1306 fClipStack->restore(); | 1319 fClipStack->restore(); |
| 1307 | 1320 |
| 1308 // reserve our layer (if any) | 1321 // reserve our layer (if any) |
| 1309 DeviceCM* layer = fMCRec->fLayer; // may be null | 1322 DeviceCM* layer = fMCRec->fLayer; // may be null |
| 1310 // now detach it from fMCRec so we can pop(). Gets freed after its drawn | 1323 // now detach it from fMCRec so we can pop(). Gets freed after its drawn |
| 1311 fMCRec->fLayer = nullptr; | 1324 fMCRec->fLayer = nullptr; |
| 1312 | 1325 |
| 1313 // now do the normal restore() | 1326 // now do the normal restore() |
| 1314 fMCRec->~MCRec(); // balanced in save() | 1327 fMCRec->~MCRec(); // balanced in save() |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1328 // reset this, since internalDrawDevice will have set it to true | 1341 // reset this, since internalDrawDevice will have set it to true |
| 1329 fDeviceCMDirty = true; | 1342 fDeviceCMDirty = true; |
| 1330 delete layer; | 1343 delete layer; |
| 1331 } else { | 1344 } else { |
| 1332 // we're at the root | 1345 // we're at the root |
| 1333 SkASSERT(layer == (void*)fDeviceCMStorage); | 1346 SkASSERT(layer == (void*)fDeviceCMStorage); |
| 1334 layer->~DeviceCM(); | 1347 layer->~DeviceCM(); |
| 1335 // no need to update fMCRec, 'cause we're killing the canvas | 1348 // no need to update fMCRec, 'cause we're killing the canvas |
| 1336 } | 1349 } |
| 1337 } | 1350 } |
| 1351 |
| 1352 if (fMCRec) { |
| 1353 fConservativeIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate(); |
| 1354 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds()); |
| 1355 } |
| 1338 } | 1356 } |
| 1339 | 1357 |
| 1340 sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceP
rops* props) { | 1358 sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceP
rops* props) { |
| 1341 if (nullptr == props) { | 1359 if (nullptr == props) { |
| 1342 props = &fProps; | 1360 props = &fProps; |
| 1343 } | 1361 } |
| 1344 return this->onNewSurface(info, *props); | 1362 return this->onNewSurface(info, *props); |
| 1345 } | 1363 } |
| 1346 | 1364 |
| 1347 sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurface
Props& props) { | 1365 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); | 1500 this->concat(m); |
| 1483 } | 1501 } |
| 1484 | 1502 |
| 1485 void SkCanvas::concat(const SkMatrix& matrix) { | 1503 void SkCanvas::concat(const SkMatrix& matrix) { |
| 1486 if (matrix.isIdentity()) { | 1504 if (matrix.isIdentity()) { |
| 1487 return; | 1505 return; |
| 1488 } | 1506 } |
| 1489 | 1507 |
| 1490 this->checkForDeferredSave(); | 1508 this->checkForDeferredSave(); |
| 1491 fDeviceCMDirty = true; | 1509 fDeviceCMDirty = true; |
| 1492 fCachedLocalClipBoundsDirty = true; | |
| 1493 fMCRec->fMatrix.preConcat(matrix); | 1510 fMCRec->fMatrix.preConcat(matrix); |
| 1494 | 1511 fConservativeIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate(); |
| 1495 this->didConcat(matrix); | 1512 this->didConcat(matrix); |
| 1496 } | 1513 } |
| 1497 | 1514 |
| 1498 void SkCanvas::internalSetMatrix(const SkMatrix& matrix) { | 1515 void SkCanvas::internalSetMatrix(const SkMatrix& matrix) { |
| 1499 fDeviceCMDirty = true; | 1516 fDeviceCMDirty = true; |
| 1500 fCachedLocalClipBoundsDirty = true; | |
| 1501 fMCRec->fMatrix = matrix; | 1517 fMCRec->fMatrix = matrix; |
| 1502 } | 1518 } |
| 1503 | 1519 |
| 1504 void SkCanvas::setMatrix(const SkMatrix& matrix) { | 1520 void SkCanvas::setMatrix(const SkMatrix& matrix) { |
| 1505 this->checkForDeferredSave(); | 1521 this->checkForDeferredSave(); |
| 1506 this->internalSetMatrix(matrix); | 1522 this->internalSetMatrix(matrix); |
| 1523 fConservativeIsScaleTranslate = matrix.isScaleTranslate(); |
| 1507 this->didSetMatrix(matrix); | 1524 this->didSetMatrix(matrix); |
| 1508 } | 1525 } |
| 1509 | 1526 |
| 1510 void SkCanvas::resetMatrix() { | 1527 void SkCanvas::resetMatrix() { |
| 1511 this->setMatrix(SkMatrix::I()); | 1528 this->setMatrix(SkMatrix::I()); |
| 1512 } | 1529 } |
| 1513 | 1530 |
| 1514 #ifdef SK_EXPERIMENTAL_SHADOWING | 1531 #ifdef SK_EXPERIMENTAL_SHADOWING |
| 1515 void SkCanvas::translateZ(SkScalar z) { | 1532 void SkCanvas::translateZ(SkScalar z) { |
| 1516 this->checkForDeferredSave(); | 1533 this->checkForDeferredSave(); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1568 if (fMCRec->fRasterClip.isEmpty()) { | 1585 if (fMCRec->fRasterClip.isEmpty()) { |
| 1569 return; | 1586 return; |
| 1570 } | 1587 } |
| 1571 | 1588 |
| 1572 if (this->quickReject(rect)) { | 1589 if (this->quickReject(rect)) { |
| 1573 fDeviceCMDirty = true; | 1590 fDeviceCMDirty = true; |
| 1574 fCachedLocalClipBoundsDirty = true; | 1591 fCachedLocalClipBoundsDirty = true; |
| 1575 | 1592 |
| 1576 fClipStack->clipEmpty(); | 1593 fClipStack->clipEmpty(); |
| 1577 (void)fMCRec->fRasterClip.setEmpty(); | 1594 (void)fMCRec->fRasterClip.setEmpty(); |
| 1595 fDeviceClipBounds.setEmpty(); |
| 1578 return; | 1596 return; |
| 1579 } | 1597 } |
| 1580 } | 1598 } |
| 1581 #endif | 1599 #endif |
| 1582 | 1600 |
| 1583 const bool isScaleTrans = fMCRec->fMatrix.isScaleTranslate(); | 1601 const bool isScaleTrans = fMCRec->fMatrix.isScaleTranslate(); |
| 1584 SkRect devR; | 1602 SkRect devR; |
| 1585 if (isScaleTrans) { | 1603 if (isScaleTrans) { |
| 1586 fMCRec->fMatrix.mapRectScaleTranslate(&devR, rect); | 1604 fMCRec->fMatrix.mapRectScaleTranslate(&devR, rect); |
| 1587 } | 1605 } |
| 1588 | 1606 |
| 1589 #ifndef SK_SUPPORT_PRECHECK_CLIPRECT | 1607 #ifndef SK_SUPPORT_PRECHECK_CLIPRECT |
| 1590 if (SkRegion::kIntersect_Op == op && | 1608 if (SkRegion::kIntersect_Op == op && |
| 1591 kHard_ClipEdgeStyle == edgeStyle | 1609 kHard_ClipEdgeStyle == edgeStyle |
| 1592 && isScaleTrans) | 1610 && isScaleTrans) |
| 1593 { | 1611 { |
| 1594 if (devR.round().contains(fMCRec->fRasterClip.getBounds())) { | 1612 if (devR.round().contains(fMCRec->fRasterClip.getBounds())) { |
| 1595 #if 0 | 1613 #if 0 |
| 1596 SkDebugf("------- ignored clipRect [%g %g %g %g]\n", | 1614 SkDebugf("------- ignored clipRect [%g %g %g %g]\n", |
| 1597 rect.left(), rect.top(), rect.right(), rect.bottom()); | 1615 rect.left(), rect.top(), rect.right(), rect.bottom()); |
| 1598 #endif | 1616 #endif |
| 1599 return; | 1617 return; |
| 1600 } | 1618 } |
| 1601 } | 1619 } |
| 1602 #endif | 1620 #endif |
| 1603 | 1621 |
| 1604 AutoValidateClip avc(this); | 1622 AutoValidateClip avc(this); |
| 1605 | 1623 |
| 1606 fDeviceCMDirty = true; | 1624 fDeviceCMDirty = true; |
| 1607 fCachedLocalClipBoundsDirty = true; | |
| 1608 | 1625 |
| 1609 if (isScaleTrans) { | 1626 if (isScaleTrans) { |
| 1610 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle; | 1627 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle; |
| 1611 fClipStack->clipDevRect(devR, op, isAA); | 1628 fClipStack->clipDevRect(devR, op, isAA); |
| 1612 fMCRec->fRasterClip.op(devR, this->getTopLayerBounds(), op, isAA); | 1629 fMCRec->fRasterClip.op(devR, this->getTopLayerBounds(), op, isAA); |
| 1613 } else { | 1630 } else { |
| 1614 // since we're rotated or some such thing, we convert the rect to a path | 1631 // 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 | 1632 // 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) | 1633 // avoid recursion in the case where we are subclassed (e.g. Pictures) |
| 1617 // we explicitly call "our" version of clipPath. | 1634 // we explicitly call "our" version of clipPath. |
| 1618 SkPath path; | 1635 SkPath path; |
| 1619 | 1636 |
| 1620 path.addRect(rect); | 1637 path.addRect(rect); |
| 1621 this->SkCanvas::onClipPath(path, op, edgeStyle); | 1638 this->SkCanvas::onClipPath(path, op, edgeStyle); |
| 1622 } | 1639 } |
| 1640 |
| 1641 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds()); |
| 1623 } | 1642 } |
| 1624 | 1643 |
| 1625 void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { | 1644 void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { |
| 1626 this->checkForDeferredSave(); | 1645 this->checkForDeferredSave(); |
| 1627 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; | 1646 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; |
| 1628 if (rrect.isRect()) { | 1647 if (rrect.isRect()) { |
| 1629 this->onClipRect(rrect.getBounds(), op, edgeStyle); | 1648 this->onClipRect(rrect.getBounds(), op, edgeStyle); |
| 1630 } else { | 1649 } else { |
| 1631 this->onClipRRect(rrect, op, edgeStyle); | 1650 this->onClipRRect(rrect, op, edgeStyle); |
| 1632 } | 1651 } |
| 1633 } | 1652 } |
| 1634 | 1653 |
| 1635 void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle
edgeStyle) { | 1654 void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle
edgeStyle) { |
| 1636 SkRRect transformedRRect; | 1655 SkRRect transformedRRect; |
| 1637 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) { | 1656 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) { |
| 1638 AutoValidateClip avc(this); | 1657 AutoValidateClip avc(this); |
| 1639 | 1658 |
| 1640 fDeviceCMDirty = true; | 1659 fDeviceCMDirty = true; |
| 1641 fCachedLocalClipBoundsDirty = true; | |
| 1642 if (!fAllowSoftClip) { | 1660 if (!fAllowSoftClip) { |
| 1643 edgeStyle = kHard_ClipEdgeStyle; | 1661 edgeStyle = kHard_ClipEdgeStyle; |
| 1644 } | 1662 } |
| 1645 | 1663 |
| 1646 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == ed
geStyle); | 1664 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == ed
geStyle); |
| 1647 | 1665 |
| 1648 fMCRec->fRasterClip.op(transformedRRect, this->getTopLayerBounds(), op, | 1666 fMCRec->fRasterClip.op(transformedRRect, this->getTopLayerBounds(), op, |
| 1649 kSoft_ClipEdgeStyle == edgeStyle); | 1667 kSoft_ClipEdgeStyle == edgeStyle); |
| 1668 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds()); |
| 1650 return; | 1669 return; |
| 1651 } | 1670 } |
| 1652 | 1671 |
| 1653 SkPath path; | 1672 SkPath path; |
| 1654 path.addRRect(rrect); | 1673 path.addRRect(rrect); |
| 1655 // call the non-virtual version | 1674 // call the non-virtual version |
| 1656 this->SkCanvas::onClipPath(path, op, edgeStyle); | 1675 this->SkCanvas::onClipPath(path, op, edgeStyle); |
| 1657 } | 1676 } |
| 1658 | 1677 |
| 1659 void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { | 1678 void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1687 if (fMCRec->fRasterClip.isEmpty()) { | 1706 if (fMCRec->fRasterClip.isEmpty()) { |
| 1688 return; | 1707 return; |
| 1689 } | 1708 } |
| 1690 | 1709 |
| 1691 if (this->quickReject(path.getBounds())) { | 1710 if (this->quickReject(path.getBounds())) { |
| 1692 fDeviceCMDirty = true; | 1711 fDeviceCMDirty = true; |
| 1693 fCachedLocalClipBoundsDirty = true; | 1712 fCachedLocalClipBoundsDirty = true; |
| 1694 | 1713 |
| 1695 fClipStack->clipEmpty(); | 1714 fClipStack->clipEmpty(); |
| 1696 (void)fMCRec->fRasterClip.setEmpty(); | 1715 (void)fMCRec->fRasterClip.setEmpty(); |
| 1716 fDeviceClipBounds.setEmpty(); |
| 1697 return; | 1717 return; |
| 1698 } | 1718 } |
| 1699 } | 1719 } |
| 1700 #endif | 1720 #endif |
| 1701 | 1721 |
| 1702 AutoValidateClip avc(this); | 1722 AutoValidateClip avc(this); |
| 1703 | 1723 |
| 1704 fDeviceCMDirty = true; | 1724 fDeviceCMDirty = true; |
| 1705 fCachedLocalClipBoundsDirty = true; | |
| 1706 if (!fAllowSoftClip) { | 1725 if (!fAllowSoftClip) { |
| 1707 edgeStyle = kHard_ClipEdgeStyle; | 1726 edgeStyle = kHard_ClipEdgeStyle; |
| 1708 } | 1727 } |
| 1709 | 1728 |
| 1710 SkPath devPath; | 1729 SkPath devPath; |
| 1711 path.transform(fMCRec->fMatrix, &devPath); | 1730 path.transform(fMCRec->fMatrix, &devPath); |
| 1712 | 1731 |
| 1713 // Check if the transfomation, or the original path itself | 1732 // Check if the transfomation, or the original path itself |
| 1714 // made us empty. Note this can also happen if we contained NaN | 1733 // made us empty. Note this can also happen if we contained NaN |
| 1715 // values. computing the bounds detects this, and will set our | 1734 // values. computing the bounds detects this, and will set our |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1726 if (fAllowSimplifyClip) { | 1745 if (fAllowSimplifyClip) { |
| 1727 bool clipIsAA = getClipStack()->asPath(&devPath); | 1746 bool clipIsAA = getClipStack()->asPath(&devPath); |
| 1728 if (clipIsAA) { | 1747 if (clipIsAA) { |
| 1729 edgeStyle = kSoft_ClipEdgeStyle; | 1748 edgeStyle = kSoft_ClipEdgeStyle; |
| 1730 } | 1749 } |
| 1731 | 1750 |
| 1732 op = SkRegion::kReplace_Op; | 1751 op = SkRegion::kReplace_Op; |
| 1733 } | 1752 } |
| 1734 | 1753 |
| 1735 fMCRec->fRasterClip.op(devPath, this->getTopLayerBounds(), op, edgeStyle); | 1754 fMCRec->fRasterClip.op(devPath, this->getTopLayerBounds(), op, edgeStyle); |
| 1755 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds()); |
| 1736 } | 1756 } |
| 1737 | 1757 |
| 1738 void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { | 1758 void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { |
| 1739 this->checkForDeferredSave(); | 1759 this->checkForDeferredSave(); |
| 1740 this->onClipRegion(rgn, op); | 1760 this->onClipRegion(rgn, op); |
| 1741 } | 1761 } |
| 1742 | 1762 |
| 1743 void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) { | 1763 void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) { |
| 1744 AutoValidateClip avc(this); | 1764 AutoValidateClip avc(this); |
| 1745 | 1765 |
| 1746 fDeviceCMDirty = true; | 1766 fDeviceCMDirty = true; |
| 1747 fCachedLocalClipBoundsDirty = true; | |
| 1748 | 1767 |
| 1749 // todo: signal fClipStack that we have a region, and therefore (I guess) | 1768 // todo: signal fClipStack that we have a region, and therefore (I guess) |
| 1750 // we have to ignore it, and use the region directly? | 1769 // we have to ignore it, and use the region directly? |
| 1751 fClipStack->clipDevRect(rgn.getBounds(), op); | 1770 fClipStack->clipDevRect(rgn.getBounds(), op); |
| 1752 | 1771 |
| 1753 fMCRec->fRasterClip.op(rgn, op); | 1772 fMCRec->fRasterClip.op(rgn, op); |
| 1773 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds()); |
| 1754 } | 1774 } |
| 1755 | 1775 |
| 1756 #ifdef SK_DEBUG | 1776 #ifdef SK_DEBUG |
| 1757 void SkCanvas::validateClip() const { | 1777 void SkCanvas::validateClip() const { |
| 1758 // construct clipRgn from the clipstack | 1778 // construct clipRgn from the clipstack |
| 1759 const SkBaseDevice* device = this->getDevice(); | 1779 const SkBaseDevice* device = this->getDevice(); |
| 1760 if (!device) { | 1780 if (!device) { |
| 1761 SkASSERT(this->isClipEmpty()); | 1781 SkASSERT(this->isClipEmpty()); |
| 1762 return; | 1782 return; |
| 1763 } | 1783 } |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1800 /////////////////////////////////////////////////////////////////////////////// | 1820 /////////////////////////////////////////////////////////////////////////////// |
| 1801 | 1821 |
| 1802 bool SkCanvas::isClipEmpty() const { | 1822 bool SkCanvas::isClipEmpty() const { |
| 1803 return fMCRec->fRasterClip.isEmpty(); | 1823 return fMCRec->fRasterClip.isEmpty(); |
| 1804 } | 1824 } |
| 1805 | 1825 |
| 1806 bool SkCanvas::isClipRect() const { | 1826 bool SkCanvas::isClipRect() const { |
| 1807 return fMCRec->fRasterClip.isRect(); | 1827 return fMCRec->fRasterClip.isRect(); |
| 1808 } | 1828 } |
| 1809 | 1829 |
| 1810 bool SkCanvas::quickReject(const SkRect& rect) const { | 1830 static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) { |
| 1811 if (!rect.isFinite()) | 1831 #if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 |
| 1812 return true; | 1832 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec); |
| 1833 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec); |
| 1834 __m128 mask = _mm_cmplt_ps(lLtT, RrBb); |
| 1835 return 0xF != _mm_movemask_ps(mask); |
| 1836 #elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON) |
| 1837 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0]; |
| 1838 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1]; |
| 1839 uint32x4_t mask = vcltq_f32(lLtT, RrBb); |
| 1840 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask); |
| 1841 #else |
| 1842 SkRect devRectAsRect; |
| 1843 SkRect devClipAsRect; |
| 1844 devRect.store(&devRectAsRect.fLeft); |
| 1845 devClip.store(&devClipAsRect.fLeft); |
| 1846 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect); |
| 1847 #endif |
| 1848 } |
| 1813 | 1849 |
| 1850 // It's important for this function to not be inlined. Otherwise the compiler w
ill share code |
| 1851 // between the fast path and the slow path, resulting in two slow paths. |
| 1852 static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRe
ct& deviceClip, |
| 1853 const SkMatrix& matrix) { |
| 1854 SkRect deviceRect; |
| 1855 matrix.mapRect(&deviceRect, src); |
| 1856 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip); |
| 1857 } |
| 1858 |
| 1859 bool SkCanvas::quickReject(const SkRect& src) const { |
| 1860 #ifdef SK_DEBUG |
| 1861 // Verify that fDeviceClipBounds are set properly. |
| 1862 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds()); |
| 1814 if (fMCRec->fRasterClip.isEmpty()) { | 1863 if (fMCRec->fRasterClip.isEmpty()) { |
| 1815 return true; | 1864 SkASSERT(fDeviceClipBounds.isEmpty() || tmp == fDeviceClipBounds); |
| 1865 } else { |
| 1866 SkASSERT(tmp == fDeviceClipBounds); |
| 1816 } | 1867 } |
| 1817 | 1868 |
| 1818 if (fMCRec->fMatrix.hasPerspective()) { | 1869 // Verify that fConservativeIsScaleTranslate is set properly. |
| 1819 SkRect dst; | 1870 SkASSERT(!fConservativeIsScaleTranslate || fMCRec->fMatrix.isScaleTranslate(
)); |
| 1820 fMCRec->fMatrix.mapRect(&dst, rect); | 1871 #endif |
| 1821 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBound
s()); | |
| 1822 } else { | |
| 1823 const SkRect& clipR = this->getLocalClipBounds(); | |
| 1824 | 1872 |
| 1825 // for speed, do the most likely reject compares first | 1873 if (!fConservativeIsScaleTranslate) { |
| 1826 // TODO: should we use | instead, or compare all 4 at once? | 1874 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix); |
| 1827 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) { | |
| 1828 return true; | |
| 1829 } | |
| 1830 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) { | |
| 1831 return true; | |
| 1832 } | |
| 1833 return false; | |
| 1834 } | 1875 } |
| 1876 |
| 1877 // We inline the implementation of mapScaleTranslate() for the fast path. |
| 1878 float sx = fMCRec->fMatrix.getScaleX(); |
| 1879 float sy = fMCRec->fMatrix.getScaleY(); |
| 1880 float tx = fMCRec->fMatrix.getTranslateX(); |
| 1881 float ty = fMCRec->fMatrix.getTranslateY(); |
| 1882 Sk4f scale(sx, sy, sx, sy); |
| 1883 Sk4f trans(tx, ty, tx, ty); |
| 1884 |
| 1885 // Apply matrix. |
| 1886 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans; |
| 1887 |
| 1888 // Make sure left < right, top < bottom. |
| 1889 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]); |
| 1890 Sk4f min = Sk4f::Min(ltrb, rblt); |
| 1891 Sk4f max = Sk4f::Max(ltrb, rblt); |
| 1892 // We can extract either pair [0,1] or [2,3] from min and max and be correct
, but on |
| 1893 // ARM this sequence generates the fastest (a single instruction). |
| 1894 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]); |
| 1895 |
| 1896 // Check if the device rect is NaN or outside the clip. |
| 1897 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft)); |
| 1835 } | 1898 } |
| 1836 | 1899 |
| 1837 bool SkCanvas::quickReject(const SkPath& path) const { | 1900 bool SkCanvas::quickReject(const SkPath& path) const { |
| 1838 return path.isEmpty() || this->quickReject(path.getBounds()); | 1901 return path.isEmpty() || this->quickReject(path.getBounds()); |
| 1839 } | 1902 } |
| 1840 | 1903 |
| 1841 bool SkCanvas::getClipBounds(SkRect* bounds) const { | 1904 bool SkCanvas::getClipBounds(SkRect* bounds) const { |
| 1842 SkIRect ibounds; | 1905 SkIRect ibounds; |
| 1843 if (!this->getClipDeviceBounds(&ibounds)) { | 1906 if (!this->getClipDeviceBounds(&ibounds)) { |
| 1844 return false; | 1907 return false; |
| (...skipping 603 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2448 if (special) { | 2511 if (special) { |
| 2449 SkPoint pt; | 2512 SkPoint pt; |
| 2450 iter.fMatrix->mapXY(x, y, &pt); | 2513 iter.fMatrix->mapXY(x, y, &pt); |
| 2451 iter.fDevice->drawSpecial(iter, special.get(), | 2514 iter.fDevice->drawSpecial(iter, special.get(), |
| 2452 SkScalarRoundToInt(pt.fX), | 2515 SkScalarRoundToInt(pt.fX), |
| 2453 SkScalarRoundToInt(pt.fY), pnt); | 2516 SkScalarRoundToInt(pt.fY), pnt); |
| 2454 } else { | 2517 } else { |
| 2455 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint()); | 2518 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint()); |
| 2456 } | 2519 } |
| 2457 } | 2520 } |
| 2458 | 2521 |
| 2459 LOOPER_END | 2522 LOOPER_END |
| 2460 } | 2523 } |
| 2461 | 2524 |
| 2462 // this one is non-virtual, so it can be called safely by other canvas apis | 2525 // this one is non-virtual, so it can be called safely by other canvas apis |
| 2463 void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, | 2526 void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, |
| 2464 const SkRect& dst, const SkPaint* paint, | 2527 const SkRect& dst, const SkPaint* paint, |
| 2465 SrcRectConstraint constraint) { | 2528 SrcRectConstraint constraint) { |
| 2466 if (bitmap.drawsNothing() || dst.isEmpty()) { | 2529 if (bitmap.drawsNothing() || dst.isEmpty()) { |
| 2467 return; | 2530 return; |
| 2468 } | 2531 } |
| (...skipping 699 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3168 | 3231 |
| 3169 SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() { | 3232 SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() { |
| 3170 fCanvas->restoreToCount(fSaveCount); | 3233 fCanvas->restoreToCount(fSaveCount); |
| 3171 } | 3234 } |
| 3172 | 3235 |
| 3173 #ifdef SK_SUPPORT_LEGACY_NEW_SURFACE_API | 3236 #ifdef SK_SUPPORT_LEGACY_NEW_SURFACE_API |
| 3174 SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* p
rops) { | 3237 SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* p
rops) { |
| 3175 return this->makeSurface(info, props).release(); | 3238 return this->makeSurface(info, props).release(); |
| 3176 } | 3239 } |
| 3177 #endif | 3240 #endif |
| OLD | NEW |