@@ -230,7 +230,6 @@ class SkCanvas::MCRec {
230
230
*/
231
231
DeviceCM* fTopLayer ;
232
232
std::unique_ptr<BackImage> fBackImage ;
233
- SkConservativeClip fRasterClip ;
234
233
SkM44 fMatrix ;
235
234
int fDeferredSaveCount ;
236
235
@@ -243,7 +242,7 @@ class SkCanvas::MCRec {
243
242
// don't bother initializing fNext
244
243
inc_rec ();
245
244
}
246
- MCRec (const MCRec& prev) : fRasterClip (prev. fRasterClip ), fMatrix (prev.fMatrix ) {
245
+ MCRec (const MCRec& prev) : fMatrix (prev.fMatrix ) {
247
246
fLayer = nullptr ;
248
247
fTopLayer = prev.fTopLayer ;
249
248
fDeferredSaveCount = 0 ;
@@ -256,13 +255,12 @@ class SkCanvas::MCRec {
256
255
dec_rec ();
257
256
}
258
257
259
- void reset (const SkIRect& bounds ) {
258
+ void reset () {
260
259
SkASSERT (fLayer );
261
260
SkASSERT (fDeferredSaveCount == 0 );
262
261
fLayer ->validate ();
263
262
264
263
fMatrix .setIdentity ();
265
- fRasterClip .setRect (bounds);
266
264
}
267
265
};
268
266
@@ -471,37 +469,35 @@ class AutoLayerForImageFilter {
471
469
472
470
#define DRAW_END }
473
471
474
- // TODO: conservativeUpdate is temporary to stage moving bounds tracking into SkNoPixelsDevice
475
- #define UPDATE_DEVICE_CLIP (code, conservativeUpdate ) \
472
+ #define UPDATE_DEVICE_CLIP (code ) \
476
473
do { \
477
474
AutoValidateClip avc (this ); \
478
475
FOR_EACH_TOP_DEVICE (code); \
479
- fMCRec ->fRasterClip .conservativeUpdate ; \
480
- fQuickRejectBounds = qr_clip_bounds (fMCRec ->fRasterClip .getBounds ()); \
476
+ fQuickRejectBounds = qr_clip_bounds (this ->computeDeviceClipBounds ()); \
481
477
} while (0 )
482
478
483
479
// //////////////////////////////////////////////////////////////////////////
484
480
485
- static inline SkRect qr_clip_bounds (const SkIRect & bounds) {
481
+ static inline SkRect qr_clip_bounds (const SkRect & bounds) {
486
482
if (bounds.isEmpty ()) {
487
483
return SkRect::MakeEmpty ();
488
484
}
489
485
490
486
// Expand bounds out by 1 in case we are anti-aliasing. We store the
491
487
// bounds as floats to enable a faster quick reject implementation.
492
488
SkRect dst;
493
- SkNx_cast< float >( Sk4i ::Load (&bounds.fLeft ) + Sk4i (-1 ,- 1 , 1 , 1 )).store (&dst.fLeft );
489
+ ( Sk4f ::Load (&bounds.fLeft ) + Sk4f (-1 . f , - 1 . f , 1 . f , 1 . f )).store (&dst.fLeft );
494
490
return dst;
495
491
}
496
492
497
493
void SkCanvas::resetForNextPicture (const SkIRect& bounds) {
498
494
this ->restoreToCount (1 );
499
- fMCRec ->reset (bounds );
495
+ fMCRec ->reset ();
500
496
501
497
// We're peering through a lot of structs here. Only at this scope do we
502
498
// know that the device is a SkNoPixelsDevice.
503
499
static_cast <SkNoPixelsDevice*>(fMCRec ->fLayer ->fDevice .get ())->resetForNextPicture (bounds);
504
- fQuickRejectBounds = qr_clip_bounds (bounds );
500
+ fQuickRejectBounds = qr_clip_bounds (this -> computeDeviceClipBounds () );
505
501
fIsScaleTranslate = true ;
506
502
}
507
503
@@ -519,7 +515,6 @@ void SkCanvas::init(sk_sp<SkBaseDevice> device) {
519
515
520
516
fMCRec = (MCRec*)fMCStack .push_back ();
521
517
new (fMCRec ) MCRec;
522
- fMCRec ->fRasterClip .setDeviceClipRestriction (&fClipRestrictionRect );
523
518
fIsScaleTranslate = true ;
524
519
525
520
fMCRec ->fLayer = (DeviceCM*)fDeviceCMStorage ;
@@ -528,19 +523,15 @@ void SkCanvas::init(sk_sp<SkBaseDevice> device) {
528
523
fMCRec ->fTopLayer = fMCRec ->fLayer ;
529
524
530
525
fSurfaceBase = nullptr ;
531
- fQuickRejectBounds = {0 , 0 , 0 , 0 };
532
526
533
527
if (device) {
534
528
// The root device and the canvas should always have the same pixel geometry
535
529
SkASSERT (fProps .pixelGeometry () == device->surfaceProps ().pixelGeometry ());
536
- fMCRec ->fRasterClip .setRect (device->getGlobalBounds ());
537
- fQuickRejectBounds = qr_clip_bounds (device->getGlobalBounds ());
538
-
539
530
device->androidFramework_setDeviceClipRestriction (&fClipRestrictionRect );
540
-
541
531
device->setMarkerStack (fMarkerStack .get ());
542
532
}
543
533
534
+ fQuickRejectBounds = qr_clip_bounds (this ->computeDeviceClipBounds ());
544
535
fScratchGlyphRunBuilder = std::make_unique<SkGlyphRunBuilder>();
545
536
}
546
537
@@ -1167,15 +1158,13 @@ void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy stra
1167
1158
// replaceClip() simulates what a new top-level device's canvas would be in
1168
1159
// the non-recording scenario. This allows the canvas to report the expanding
1169
1160
// effects of image filters on the temporary clip bounds.
1170
- UPDATE_DEVICE_CLIP (device->replaceClip (ir),
1171
- setRect (ir));
1161
+ UPDATE_DEVICE_CLIP (device->replaceClip (ir));
1172
1162
} else {
1173
1163
// else the layer device failed to be created, so the saveLayer() effectively
1174
1164
// becomes just a save(). The clipRegion() explicitly applies the bounds of the
1175
1165
// failed layer, without resetting the clip of the prior device that all subsequent
1176
1166
// nested draw calls need to respect.
1177
- UPDATE_DEVICE_CLIP (device->clipRegion (SkRegion (ir), SkClipOp::kIntersect ),
1178
- opRegion (SkRegion (ir), SkRegion::kIntersect_Op ));
1167
+ UPDATE_DEVICE_CLIP (device->clipRegion (SkRegion (ir), SkClipOp::kIntersect ));
1179
1168
}
1180
1169
}
1181
1170
return ;
@@ -1196,10 +1185,6 @@ void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy stra
1196
1185
1197
1186
newDevice->setOrigin (fMCRec ->fMatrix , ir.fLeft , ir.fTop );
1198
1187
newDevice->androidFramework_setDeviceClipRestriction (&fClipRestrictionRect );
1199
- if (boundsAffectsClip) {
1200
- fMCRec ->fRasterClip .setRect (ir);
1201
- fQuickRejectBounds = qr_clip_bounds (ir);
1202
- }
1203
1188
1204
1189
if (layer->fNext ) {
1205
1190
// need to punch a hole in the previous device, so we don't draw there, given that
@@ -1210,6 +1195,8 @@ void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy stra
1210
1195
layer->fDevice ->clipRegion (hole, SkClipOp::kDifference );
1211
1196
} while (layer->fNext );
1212
1197
}
1198
+
1199
+ fQuickRejectBounds = qr_clip_bounds (this ->computeDeviceClipBounds ());
1213
1200
}
1214
1201
1215
1202
int SkCanvas::saveLayerAlpha (const SkRect* bounds, U8CPU alpha) {
@@ -1317,7 +1304,10 @@ void SkCanvas::internalRestore() {
1317
1304
1318
1305
if (fMCRec ) {
1319
1306
fIsScaleTranslate = SkMatrixPriv::IsScaleTranslateAsM33 (fMCRec ->fMatrix );
1320
- fQuickRejectBounds = qr_clip_bounds (fMCRec ->fRasterClip .getBounds ());
1307
+ // Update the quick-reject bounds in case the restore changed the top device or the
1308
+ // removed save record had included modifications to the clip stack.
1309
+ fQuickRejectBounds = qr_clip_bounds (this ->computeDeviceClipBounds ());
1310
+ this ->validateClip ();
1321
1311
}
1322
1312
}
1323
1313
@@ -1586,8 +1576,7 @@ void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
1586
1576
void SkCanvas::onClipRect (const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
1587
1577
SkASSERT (rect.isSorted ());
1588
1578
const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1589
- UPDATE_DEVICE_CLIP (device->clipRect (rect, op, isAA), \
1590
- opRect (rect, fMCRec ->fMatrix .asM33 (), this ->getTopLayerBounds (), (SkRegion::Op) op, isAA));
1579
+ UPDATE_DEVICE_CLIP (device->clipRect (rect, op, isAA));
1591
1580
}
1592
1581
1593
1582
void SkCanvas::androidFramework_setDeviceClipRestriction (const SkIRect& rect) {
@@ -1597,14 +1586,12 @@ void SkCanvas::androidFramework_setDeviceClipRestriction(const SkIRect& rect) {
1597
1586
// removing it (i.e. rect is empty).
1598
1587
this ->checkForDeferredSave ();
1599
1588
}
1600
- UPDATE_DEVICE_CLIP (device->androidFramework_setDeviceClipRestriction (&fClipRestrictionRect ),\
1601
- opIRect (fClipRestrictionRect , SkRegion::kIntersect_Op ));
1589
+ UPDATE_DEVICE_CLIP (device->androidFramework_setDeviceClipRestriction (&fClipRestrictionRect ));
1602
1590
}
1603
1591
1604
1592
void SkCanvas::androidFramework_replaceClip (const SkIRect& rect) {
1605
1593
this ->checkForDeferredSave ();
1606
- UPDATE_DEVICE_CLIP (device->replaceClip (rect), \
1607
- setRect (rect));
1594
+ UPDATE_DEVICE_CLIP (device->replaceClip (rect));
1608
1595
}
1609
1596
1610
1597
void SkCanvas::clipRRect (const SkRRect& rrect, SkClipOp op, bool doAA) {
@@ -1619,8 +1606,7 @@ void SkCanvas::clipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
1619
1606
1620
1607
void SkCanvas::onClipRRect (const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
1621
1608
bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1622
- UPDATE_DEVICE_CLIP (device->clipRRect (rrect, op, isAA), \
1623
- opRRect (rrect, fMCRec ->fMatrix .asM33 (), this ->getTopLayerBounds (), (SkRegion::Op)op, isAA));
1609
+ UPDATE_DEVICE_CLIP (device->clipRRect (rrect, op, isAA));
1624
1610
}
1625
1611
1626
1612
void SkCanvas::clipPath (const SkPath& path, SkClipOp op, bool doAA) {
@@ -1650,8 +1636,7 @@ void SkCanvas::clipPath(const SkPath& path, SkClipOp op, bool doAA) {
1650
1636
1651
1637
void SkCanvas::onClipPath (const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
1652
1638
bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1653
- UPDATE_DEVICE_CLIP (device->clipPath (path, op, isAA), \
1654
- opPath (path, fMCRec ->fMatrix .asM33 (), this ->getTopLayerBounds (), (SkRegion::Op)op, isAA));
1639
+ UPDATE_DEVICE_CLIP (device->clipPath (path, op, isAA));
1655
1640
}
1656
1641
1657
1642
void SkCanvas::clipShader (sk_sp<SkShader> sh, SkClipOp op) {
@@ -1672,8 +1657,7 @@ void SkCanvas::clipShader(sk_sp<SkShader> sh, SkClipOp op) {
1672
1657
}
1673
1658
1674
1659
void SkCanvas::onClipShader (sk_sp<SkShader> sh, SkClipOp op) {
1675
- UPDATE_DEVICE_CLIP (device->clipShader (sh, op),
1676
- opShader (sh));
1660
+ UPDATE_DEVICE_CLIP (device->clipShader (sh, op));
1677
1661
}
1678
1662
1679
1663
void SkCanvas::clipRegion (const SkRegion& rgn, SkClipOp op) {
@@ -1682,13 +1666,12 @@ void SkCanvas::clipRegion(const SkRegion& rgn, SkClipOp op) {
1682
1666
}
1683
1667
1684
1668
void SkCanvas::onClipRegion (const SkRegion& rgn, SkClipOp op) {
1685
- UPDATE_DEVICE_CLIP (device->clipRegion (rgn, op),
1686
- opRegion (rgn, (SkRegion::Op) op));
1669
+ UPDATE_DEVICE_CLIP (device->clipRegion (rgn, op));
1687
1670
}
1688
1671
1689
1672
void SkCanvas::validateClip () const {
1690
1673
#ifdef SK_DEBUG
1691
- SkRect tmp = qr_clip_bounds (this ->fMCRec -> fRasterClip . getBounds ());
1674
+ SkRect tmp = qr_clip_bounds (this ->computeDeviceClipBounds ());
1692
1675
if (this ->isClipEmpty ()) {
1693
1676
SkASSERT (fQuickRejectBounds .isEmpty ());
1694
1677
} else {
@@ -1735,14 +1718,9 @@ void SkCanvas::temporary_internal_getRgnClip(SkRegion* rgn) {
1735
1718
// /////////////////////////////////////////////////////////////////////////////
1736
1719
1737
1720
bool SkCanvas::isClipEmpty () const {
1738
- return fMCRec ->fRasterClip .isEmpty ();
1739
-
1740
- // TODO: should we only use the conservative answer in a recording canvas?
1741
- #if 0
1742
1721
SkBaseDevice* dev = this ->getTopDevice ();
1743
1722
// if no device we return true
1744
- return !dev || dev->onGetClipType() == SkBaseDevice::kEmpty_ClipType;
1745
- #endif
1723
+ return !dev || dev->onGetClipType () == SkBaseDevice::ClipType::kEmpty ;
1746
1724
}
1747
1725
1748
1726
bool SkCanvas::isClipRect () const {
@@ -1841,7 +1819,28 @@ SkRect SkCanvas::getLocalClipBounds() const {
1841
1819
}
1842
1820
1843
1821
SkIRect SkCanvas::getDeviceClipBounds () const {
1844
- return fMCRec ->fRasterClip .getBounds ();
1822
+ return this ->computeDeviceClipBounds ().roundOut ();
1823
+ }
1824
+
1825
+ SkRect SkCanvas::computeDeviceClipBounds () const {
1826
+ if (this ->isClipEmpty ()) {
1827
+ return SkRect::MakeEmpty ();
1828
+ }
1829
+
1830
+ // Compute the union of all top devices' device bounds, mapped into the global coordinate system
1831
+ DeviceCM* layer = fMCRec ->fTopLayer ;
1832
+ SkRect totalBounds = SkRect::MakeEmpty ();
1833
+ while (layer) {
1834
+ if (layer->fDevice ) {
1835
+ SkIRect devClipBounds = layer->fDevice ->devClipBounds ();
1836
+ SkRect layerBounds =
1837
+ layer->fDevice ->deviceToGlobal ().mapRect (SkRect::Make (devClipBounds));
1838
+ totalBounds.join (layerBounds);
1839
+ }
1840
+ layer = layer->fNext ;
1841
+ }
1842
+
1843
+ return totalBounds;
1845
1844
}
1846
1845
1847
1846
// /////////////////////////////////////////////////////////////////////
@@ -2453,7 +2452,10 @@ bool SkCanvas::canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const
2453
2452
SkPoint pt;
2454
2453
ctm.mapXY (x, y, &pt);
2455
2454
SkIRect ir = SkIRect::MakeXYWH (SkScalarRoundToInt (pt.x ()), SkScalarRoundToInt (pt.y ()), w, h);
2456
- return ir.contains (fMCRec ->fRasterClip .getBounds ());
2455
+ // quick bounds have been outset by 1px compared to overall device bounds, so this makes the
2456
+ // contains check equivalent to between ir and device bounds
2457
+ ir.outset (1 , 1 );
2458
+ return ir.contains (fQuickRejectBounds );
2457
2459
}
2458
2460
2459
2461
// Given storage for a real paint, and an optional paint parameter, clean-up the param (if non-null)
0 commit comments