@@ -978,8 +978,8 @@ static bool CompareOps(uint8_t* ptrA,
978
978
return true ;
979
979
}
980
980
981
- void DisplayList::RenderTo (SkCanvas* canvas) const {
982
- DisplayListCanvasDispatcher dispatcher (canvas);
981
+ void DisplayList::RenderTo (SkCanvas* canvas, SkScalar opacity ) const {
982
+ DisplayListCanvasDispatcher dispatcher (canvas, opacity );
983
983
Dispatch (dispatcher);
984
984
}
985
985
@@ -995,19 +995,31 @@ bool DisplayList::Equals(const DisplayList& other) const {
995
995
return CompareOps (ptr, ptr + byte_count_, o_ptr, o_ptr + other.byte_count_ );
996
996
}
997
997
998
+ DisplayList::DisplayList ()
999
+ : byte_count_(0 ),
1000
+ op_count_(0 ),
1001
+ nested_byte_count_(0 ),
1002
+ nested_op_count_(0 ),
1003
+ unique_id_(0 ),
1004
+ bounds_({0 , 0 , 0 , 0 }),
1005
+ bounds_cull_({0 , 0 , 0 , 0 }),
1006
+ can_apply_group_opacity_(true ) {}
1007
+
998
1008
DisplayList::DisplayList (uint8_t * ptr,
999
1009
size_t byte_count,
1000
1010
int op_count,
1001
1011
size_t nested_byte_count,
1002
1012
int nested_op_count,
1003
- const SkRect& cull_rect)
1013
+ const SkRect& cull_rect,
1014
+ bool can_apply_group_opacity)
1004
1015
: storage_(ptr),
1005
1016
byte_count_(byte_count),
1006
1017
op_count_(op_count),
1007
1018
nested_byte_count_(nested_byte_count),
1008
1019
nested_op_count_(nested_op_count),
1009
1020
bounds_({0 , 0 , -1 , -1 }),
1010
- bounds_cull_(cull_rect) {
1021
+ bounds_cull_(cull_rect),
1022
+ can_apply_group_opacity_(can_apply_group_opacity) {
1011
1023
static std::atomic<uint32_t > nextID{1 };
1012
1024
do {
1013
1025
unique_id_ = nextID.fetch_add (+1 , std::memory_order_relaxed);
@@ -1057,7 +1069,7 @@ void* DisplayListBuilder::Push(size_t pod, int op_inc, Args&&... args) {
1057
1069
}
1058
1070
1059
1071
sk_sp<DisplayList> DisplayListBuilder::Build () {
1060
- while (save_level_ > 0 ) {
1072
+ while (layer_stack_. size () > 1 ) {
1061
1073
restore ();
1062
1074
}
1063
1075
size_t bytes = used_;
@@ -1067,13 +1079,17 @@ sk_sp<DisplayList> DisplayListBuilder::Build() {
1067
1079
used_ = allocated_ = op_count_ = 0 ;
1068
1080
nested_bytes_ = nested_op_count_ = 0 ;
1069
1081
storage_.realloc (bytes);
1082
+ bool compatible = layer_stack_.back ().is_group_opacity_compatible ();
1070
1083
return sk_sp<DisplayList>(new DisplayList (storage_.release (), bytes, count,
1071
1084
nested_bytes, nested_count,
1072
- cull_rect_));
1085
+ cull_rect_, compatible ));
1073
1086
}
1074
1087
1075
1088
DisplayListBuilder::DisplayListBuilder (const SkRect& cull_rect)
1076
- : cull_rect_(cull_rect) {}
1089
+ : cull_rect_(cull_rect) {
1090
+ layer_stack_.emplace_back ();
1091
+ current_layer_ = &layer_stack_.back ();
1092
+ }
1077
1093
1078
1094
DisplayListBuilder::~DisplayListBuilder () {
1079
1095
uint8_t * ptr = storage_.get ();
@@ -1090,6 +1106,7 @@ void DisplayListBuilder::onSetDither(bool dither) {
1090
1106
}
1091
1107
void DisplayListBuilder::onSetInvertColors (bool invert) {
1092
1108
Push<SetInvertColorsOp>(0 , 0 , current_invert_colors_ = invert);
1109
+ UpdateCurrentOpacityCompatibility ();
1093
1110
}
1094
1111
void DisplayListBuilder::onSetStrokeCap (SkPaint::Cap cap) {
1095
1112
Push<SetStrokeCapOp>(0 , 0 , current_stroke_cap_ = cap);
@@ -1112,6 +1129,7 @@ void DisplayListBuilder::onSetColor(SkColor color) {
1112
1129
void DisplayListBuilder::onSetBlendMode (SkBlendMode mode) {
1113
1130
current_blender_ = nullptr ;
1114
1131
Push<SetBlendModeOp>(0 , 0 , current_blend_mode_ = mode);
1132
+ UpdateCurrentOpacityCompatibility ();
1115
1133
}
1116
1134
void DisplayListBuilder::onSetBlender (sk_sp<SkBlender> blender) {
1117
1135
// setBlender(nullptr) should be redirected to setBlendMode(SrcOver)
@@ -1126,6 +1144,7 @@ void DisplayListBuilder::onSetBlender(sk_sp<SkBlender> blender) {
1126
1144
(current_blender_ = blender) //
1127
1145
? Push<SetBlenderOp>(0 , 0 , std::move (blender))
1128
1146
: Push<ClearBlenderOp>(0 , 0 );
1147
+ UpdateCurrentOpacityCompatibility ();
1129
1148
}
1130
1149
}
1131
1150
void DisplayListBuilder::onSetShader (sk_sp<SkShader> shader) {
@@ -1142,6 +1161,7 @@ void DisplayListBuilder::onSetColorFilter(sk_sp<SkColorFilter> filter) {
1142
1161
(current_color_filter_ = filter) //
1143
1162
? Push<SetColorFilterOp>(0 , 0 , std::move (filter))
1144
1163
: Push<ClearColorFilterOp>(0 , 0 );
1164
+ UpdateCurrentOpacityCompatibility ();
1145
1165
}
1146
1166
void DisplayListBuilder::onSetPathEffect (sk_sp<SkPathEffect> effect) {
1147
1167
(current_path_effect_ = effect) //
@@ -1228,21 +1248,37 @@ void DisplayListBuilder::setAttributesFromPaint(
1228
1248
}
1229
1249
1230
1250
void DisplayListBuilder::save () {
1231
- save_level_++;
1232
1251
Push<SaveOp>(0 , 1 );
1252
+ layer_stack_.emplace_back ();
1253
+ current_layer_ = &layer_stack_.back ();
1233
1254
}
1234
1255
void DisplayListBuilder::restore () {
1235
- if (save_level_ > 0 ) {
1256
+ if (layer_stack_.size () > 1 ) {
1257
+ // Grab the current layer info before we push the restore
1258
+ // on the stack.
1259
+ LayerInfo layer_info = layer_stack_.back ();
1260
+ layer_stack_.pop_back ();
1261
+ current_layer_ = &layer_stack_.back ();
1236
1262
Push<RestoreOp>(0 , 1 );
1237
- save_level_--;
1263
+ if (!layer_info.has_layer ) {
1264
+ // For regular save() ops there was no protecting layer so we have to
1265
+ // accumulate the values into the enclosing layer.
1266
+ if (layer_info.cannot_inherit_opacity ) {
1267
+ current_layer_->mark_incompatible ();
1268
+ } else if (layer_info.has_compatible_op ) {
1269
+ current_layer_->add_compatible_op ();
1270
+ }
1271
+ }
1238
1272
}
1239
1273
}
1240
1274
void DisplayListBuilder::saveLayer (const SkRect* bounds,
1241
1275
bool restore_with_paint) {
1242
- save_level_++;
1243
1276
bounds //
1244
1277
? Push<SaveLayerBoundsOp>(0 , 1 , *bounds, restore_with_paint)
1245
1278
: Push<SaveLayerOp>(0 , 1 , restore_with_paint);
1279
+ CheckLayerOpacityCompatibility (restore_with_paint);
1280
+ layer_stack_.emplace_back (true );
1281
+ current_layer_ = &layer_stack_.back ();
1246
1282
}
1247
1283
1248
1284
void DisplayListBuilder::translate (SkScalar tx, SkScalar ty) {
@@ -1356,21 +1392,27 @@ void DisplayListBuilder::clipPath(const SkPath& path,
1356
1392
1357
1393
void DisplayListBuilder::drawPaint () {
1358
1394
Push<DrawPaintOp>(0 , 1 );
1395
+ CheckLayerOpacityCompatibility ();
1359
1396
}
1360
1397
void DisplayListBuilder::drawColor (SkColor color, SkBlendMode mode) {
1361
1398
Push<DrawColorOp>(0 , 1 , color, mode);
1399
+ CheckLayerOpacityCompatibility (mode);
1362
1400
}
1363
1401
void DisplayListBuilder::drawLine (const SkPoint& p0, const SkPoint& p1) {
1364
1402
Push<DrawLineOp>(0 , 1 , p0, p1);
1403
+ CheckLayerOpacityCompatibility ();
1365
1404
}
1366
1405
void DisplayListBuilder::drawRect (const SkRect& rect) {
1367
1406
Push<DrawRectOp>(0 , 1 , rect);
1407
+ CheckLayerOpacityCompatibility ();
1368
1408
}
1369
1409
void DisplayListBuilder::drawOval (const SkRect& bounds) {
1370
1410
Push<DrawOvalOp>(0 , 1 , bounds);
1411
+ CheckLayerOpacityCompatibility ();
1371
1412
}
1372
1413
void DisplayListBuilder::drawCircle (const SkPoint& center, SkScalar radius) {
1373
1414
Push<DrawCircleOp>(0 , 1 , center, radius);
1415
+ CheckLayerOpacityCompatibility ();
1374
1416
}
1375
1417
void DisplayListBuilder::drawRRect (const SkRRect& rrect) {
1376
1418
if (rrect.isRect ()) {
@@ -1379,21 +1421,29 @@ void DisplayListBuilder::drawRRect(const SkRRect& rrect) {
1379
1421
drawOval (rrect.rect ());
1380
1422
} else {
1381
1423
Push<DrawRRectOp>(0 , 1 , rrect);
1424
+ CheckLayerOpacityCompatibility ();
1382
1425
}
1383
1426
}
1384
1427
void DisplayListBuilder::drawDRRect (const SkRRect& outer,
1385
1428
const SkRRect& inner) {
1386
1429
Push<DrawDRRectOp>(0 , 1 , outer, inner);
1430
+ CheckLayerOpacityCompatibility ();
1387
1431
}
1388
1432
void DisplayListBuilder::drawPath (const SkPath& path) {
1389
1433
Push<DrawPathOp>(0 , 1 , path);
1434
+ CheckLayerOpacityHairlineCompatibility ();
1390
1435
}
1391
1436
1392
1437
void DisplayListBuilder::drawArc (const SkRect& bounds,
1393
1438
SkScalar start,
1394
1439
SkScalar sweep,
1395
1440
bool useCenter) {
1396
1441
Push<DrawArcOp>(0 , 1 , bounds, start, sweep, useCenter);
1442
+ if (useCenter) {
1443
+ CheckLayerOpacityHairlineCompatibility ();
1444
+ } else {
1445
+ CheckLayerOpacityCompatibility ();
1446
+ }
1397
1447
}
1398
1448
void DisplayListBuilder::drawPoints (SkCanvas::PointMode mode,
1399
1449
uint32_t count,
@@ -1416,10 +1466,19 @@ void DisplayListBuilder::drawPoints(SkCanvas::PointMode mode,
1416
1466
return ;
1417
1467
}
1418
1468
CopyV (data_ptr, pts, count);
1469
+ // drawPoints treats every point or line (or segment of a polygon)
1470
+ // as a completely separate operation meaning we cannot ensure
1471
+ // distribution of group opacity without analyzing the mode and the
1472
+ // bounds of every sub-primitive.
1473
+ // See: https://fiddle.skia.org/c/228459001d2de8db117ce25ef5cedb0c
1474
+ UpdateLayerOpacityCompatibility (false );
1419
1475
}
1420
1476
void DisplayListBuilder::drawVertices (const sk_sp<SkVertices> vertices,
1421
1477
SkBlendMode mode) {
1422
1478
Push<DrawVerticesOp>(0 , 1 , std::move (vertices), mode);
1479
+ // DrawVertices applies its colors to the paint so we have no way
1480
+ // of controlling opacity using the current paint attributes.
1481
+ UpdateLayerOpacityCompatibility (false );
1423
1482
}
1424
1483
1425
1484
void DisplayListBuilder::drawImage (const sk_sp<SkImage> image,
@@ -1429,6 +1488,7 @@ void DisplayListBuilder::drawImage(const sk_sp<SkImage> image,
1429
1488
render_with_attributes
1430
1489
? Push<DrawImageWithAttrOp>(0 , 1 , std::move (image), point, sampling)
1431
1490
: Push<DrawImageOp>(0 , 1 , std::move (image), point, sampling);
1491
+ CheckLayerOpacityCompatibility (render_with_attributes);
1432
1492
}
1433
1493
void DisplayListBuilder::drawImageRect (const sk_sp<SkImage> image,
1434
1494
const SkRect& src,
@@ -1438,6 +1498,7 @@ void DisplayListBuilder::drawImageRect(const sk_sp<SkImage> image,
1438
1498
SkCanvas::SrcRectConstraint constraint) {
1439
1499
Push<DrawImageRectOp>(0 , 1 , std::move (image), src, dst, sampling,
1440
1500
render_with_attributes, constraint);
1501
+ CheckLayerOpacityCompatibility (render_with_attributes);
1441
1502
}
1442
1503
void DisplayListBuilder::drawImageNine (const sk_sp<SkImage> image,
1443
1504
const SkIRect& center,
@@ -1448,6 +1509,7 @@ void DisplayListBuilder::drawImageNine(const sk_sp<SkImage> image,
1448
1509
? Push<DrawImageNineWithAttrOp>(0 , 1 , std::move (image), center, dst,
1449
1510
filter)
1450
1511
: Push<DrawImageNineOp>(0 , 1 , std::move (image), center, dst, filter);
1512
+ CheckLayerOpacityCompatibility (render_with_attributes);
1451
1513
}
1452
1514
void DisplayListBuilder::drawImageLattice (const sk_sp<SkImage> image,
1453
1515
const SkCanvas::Lattice& lattice,
@@ -1469,6 +1531,7 @@ void DisplayListBuilder::drawImageLattice(const sk_sp<SkImage> image,
1469
1531
filter, render_with_attributes);
1470
1532
CopyV (pod, lattice.fXDivs , xDivCount, lattice.fYDivs , yDivCount,
1471
1533
lattice.fColors , cellCount, lattice.fRectTypes , cellCount);
1534
+ CheckLayerOpacityCompatibility (render_with_attributes);
1472
1535
}
1473
1536
void DisplayListBuilder::drawAtlas (const sk_sp<SkImage> atlas,
1474
1537
const SkRSXform xform[],
@@ -1503,6 +1566,10 @@ void DisplayListBuilder::drawAtlas(const sk_sp<SkImage> atlas,
1503
1566
}
1504
1567
CopyV (data_ptr, xform, count, tex, count);
1505
1568
}
1569
+ // drawAtlas treats each image as a separate operation so we cannot rely
1570
+ // on it to distribute the opacity without overlap without checking all
1571
+ // of the transforms and texture rectangles.
1572
+ UpdateLayerOpacityCompatibility (false );
1506
1573
}
1507
1574
1508
1575
void DisplayListBuilder::drawPicture (const sk_sp<SkPicture> picture,
@@ -1520,6 +1587,7 @@ void DisplayListBuilder::drawPicture(const sk_sp<SkPicture> picture,
1520
1587
// This behavior is identical to the way SkPicture computes nested op counts.
1521
1588
nested_op_count_ += picture->approximateOpCount (true ) - 1 ;
1522
1589
nested_bytes_ += picture->approximateBytesUsed ();
1590
+ CheckLayerOpacityCompatibility (render_with_attributes);
1523
1591
}
1524
1592
void DisplayListBuilder::drawDisplayList (
1525
1593
const sk_sp<DisplayList> display_list) {
@@ -1532,11 +1600,13 @@ void DisplayListBuilder::drawDisplayList(
1532
1600
// This behavior is identical to the way SkPicture computes nested op counts.
1533
1601
nested_op_count_ += display_list->op_count (true ) - 1 ;
1534
1602
nested_bytes_ += display_list->bytes (true );
1603
+ UpdateLayerOpacityCompatibility (display_list->can_apply_group_opacity ());
1535
1604
}
1536
1605
void DisplayListBuilder::drawTextBlob (const sk_sp<SkTextBlob> blob,
1537
1606
SkScalar x,
1538
1607
SkScalar y) {
1539
1608
Push<DrawTextBlobOp>(0 , 1 , std::move (blob), x, y);
1609
+ CheckLayerOpacityCompatibility ();
1540
1610
}
1541
1611
void DisplayListBuilder::drawShadow (const SkPath& path,
1542
1612
const SkColor color,
@@ -1546,6 +1616,7 @@ void DisplayListBuilder::drawShadow(const SkPath& path,
1546
1616
transparent_occluder //
1547
1617
? Push<DrawShadowTransparentOccluderOp>(0 , 1 , path, color, elevation, dpr)
1548
1618
: Push<DrawShadowOp>(0 , 1 , path, color, elevation, dpr);
1619
+ UpdateLayerOpacityCompatibility (false );
1549
1620
}
1550
1621
1551
1622
// clang-format off
0 commit comments