@@ -978,8 +978,8 @@ static bool CompareOps(uint8_t* ptrA,
978978 return true ;
979979}
980980
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 );
983983 Dispatch (dispatcher);
984984}
985985
@@ -995,19 +995,31 @@ bool DisplayList::Equals(const DisplayList& other) const {
995995 return CompareOps (ptr, ptr + byte_count_, o_ptr, o_ptr + other.byte_count_ );
996996}
997997
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+
9981008DisplayList::DisplayList (uint8_t * ptr,
9991009 size_t byte_count,
10001010 int op_count,
10011011 size_t nested_byte_count,
10021012 int nested_op_count,
1003- const SkRect& cull_rect)
1013+ const SkRect& cull_rect,
1014+ bool can_apply_group_opacity)
10041015 : storage_(ptr),
10051016 byte_count_(byte_count),
10061017 op_count_(op_count),
10071018 nested_byte_count_(nested_byte_count),
10081019 nested_op_count_(nested_op_count),
10091020 bounds_({0 , 0 , -1 , -1 }),
1010- bounds_cull_(cull_rect) {
1021+ bounds_cull_(cull_rect),
1022+ can_apply_group_opacity_(can_apply_group_opacity) {
10111023 static std::atomic<uint32_t > nextID{1 };
10121024 do {
10131025 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) {
10571069}
10581070
10591071sk_sp<DisplayList> DisplayListBuilder::Build () {
1060- while (save_level_ > 0 ) {
1072+ while (layer_stack_. size () > 1 ) {
10611073 restore ();
10621074 }
10631075 size_t bytes = used_;
@@ -1067,13 +1079,17 @@ sk_sp<DisplayList> DisplayListBuilder::Build() {
10671079 used_ = allocated_ = op_count_ = 0 ;
10681080 nested_bytes_ = nested_op_count_ = 0 ;
10691081 storage_.realloc (bytes);
1082+ bool compatible = layer_stack_.back ().is_group_opacity_compatible ();
10701083 return sk_sp<DisplayList>(new DisplayList (storage_.release (), bytes, count,
10711084 nested_bytes, nested_count,
1072- cull_rect_));
1085+ cull_rect_, compatible ));
10731086}
10741087
10751088DisplayListBuilder::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+ }
10771093
10781094DisplayListBuilder::~DisplayListBuilder () {
10791095 uint8_t * ptr = storage_.get ();
@@ -1090,6 +1106,7 @@ void DisplayListBuilder::onSetDither(bool dither) {
10901106}
10911107void DisplayListBuilder::onSetInvertColors (bool invert) {
10921108 Push<SetInvertColorsOp>(0 , 0 , current_invert_colors_ = invert);
1109+ UpdateCurrentOpacityCompatibility ();
10931110}
10941111void DisplayListBuilder::onSetStrokeCap (SkPaint::Cap cap) {
10951112 Push<SetStrokeCapOp>(0 , 0 , current_stroke_cap_ = cap);
@@ -1112,6 +1129,7 @@ void DisplayListBuilder::onSetColor(SkColor color) {
11121129void DisplayListBuilder::onSetBlendMode (SkBlendMode mode) {
11131130 current_blender_ = nullptr ;
11141131 Push<SetBlendModeOp>(0 , 0 , current_blend_mode_ = mode);
1132+ UpdateCurrentOpacityCompatibility ();
11151133}
11161134void DisplayListBuilder::onSetBlender (sk_sp<SkBlender> blender) {
11171135 // setBlender(nullptr) should be redirected to setBlendMode(SrcOver)
@@ -1126,6 +1144,7 @@ void DisplayListBuilder::onSetBlender(sk_sp<SkBlender> blender) {
11261144 (current_blender_ = blender) //
11271145 ? Push<SetBlenderOp>(0 , 0 , std::move (blender))
11281146 : Push<ClearBlenderOp>(0 , 0 );
1147+ UpdateCurrentOpacityCompatibility ();
11291148 }
11301149}
11311150void DisplayListBuilder::onSetShader (sk_sp<SkShader> shader) {
@@ -1142,6 +1161,7 @@ void DisplayListBuilder::onSetColorFilter(sk_sp<SkColorFilter> filter) {
11421161 (current_color_filter_ = filter) //
11431162 ? Push<SetColorFilterOp>(0 , 0 , std::move (filter))
11441163 : Push<ClearColorFilterOp>(0 , 0 );
1164+ UpdateCurrentOpacityCompatibility ();
11451165}
11461166void DisplayListBuilder::onSetPathEffect (sk_sp<SkPathEffect> effect) {
11471167 (current_path_effect_ = effect) //
@@ -1228,21 +1248,37 @@ void DisplayListBuilder::setAttributesFromPaint(
12281248}
12291249
12301250void DisplayListBuilder::save () {
1231- save_level_++;
12321251 Push<SaveOp>(0 , 1 );
1252+ layer_stack_.emplace_back ();
1253+ current_layer_ = &layer_stack_.back ();
12331254}
12341255void 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 ();
12361262 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+ }
12381272 }
12391273}
12401274void DisplayListBuilder::saveLayer (const SkRect* bounds,
12411275 bool restore_with_paint) {
1242- save_level_++;
12431276 bounds //
12441277 ? Push<SaveLayerBoundsOp>(0 , 1 , *bounds, restore_with_paint)
12451278 : Push<SaveLayerOp>(0 , 1 , restore_with_paint);
1279+ CheckLayerOpacityCompatibility (restore_with_paint);
1280+ layer_stack_.emplace_back (true );
1281+ current_layer_ = &layer_stack_.back ();
12461282}
12471283
12481284void DisplayListBuilder::translate (SkScalar tx, SkScalar ty) {
@@ -1356,21 +1392,27 @@ void DisplayListBuilder::clipPath(const SkPath& path,
13561392
13571393void DisplayListBuilder::drawPaint () {
13581394 Push<DrawPaintOp>(0 , 1 );
1395+ CheckLayerOpacityCompatibility ();
13591396}
13601397void DisplayListBuilder::drawColor (SkColor color, SkBlendMode mode) {
13611398 Push<DrawColorOp>(0 , 1 , color, mode);
1399+ CheckLayerOpacityCompatibility (mode);
13621400}
13631401void DisplayListBuilder::drawLine (const SkPoint& p0, const SkPoint& p1) {
13641402 Push<DrawLineOp>(0 , 1 , p0, p1);
1403+ CheckLayerOpacityCompatibility ();
13651404}
13661405void DisplayListBuilder::drawRect (const SkRect& rect) {
13671406 Push<DrawRectOp>(0 , 1 , rect);
1407+ CheckLayerOpacityCompatibility ();
13681408}
13691409void DisplayListBuilder::drawOval (const SkRect& bounds) {
13701410 Push<DrawOvalOp>(0 , 1 , bounds);
1411+ CheckLayerOpacityCompatibility ();
13711412}
13721413void DisplayListBuilder::drawCircle (const SkPoint& center, SkScalar radius) {
13731414 Push<DrawCircleOp>(0 , 1 , center, radius);
1415+ CheckLayerOpacityCompatibility ();
13741416}
13751417void DisplayListBuilder::drawRRect (const SkRRect& rrect) {
13761418 if (rrect.isRect ()) {
@@ -1379,21 +1421,29 @@ void DisplayListBuilder::drawRRect(const SkRRect& rrect) {
13791421 drawOval (rrect.rect ());
13801422 } else {
13811423 Push<DrawRRectOp>(0 , 1 , rrect);
1424+ CheckLayerOpacityCompatibility ();
13821425 }
13831426}
13841427void DisplayListBuilder::drawDRRect (const SkRRect& outer,
13851428 const SkRRect& inner) {
13861429 Push<DrawDRRectOp>(0 , 1 , outer, inner);
1430+ CheckLayerOpacityCompatibility ();
13871431}
13881432void DisplayListBuilder::drawPath (const SkPath& path) {
13891433 Push<DrawPathOp>(0 , 1 , path);
1434+ CheckLayerOpacityHairlineCompatibility ();
13901435}
13911436
13921437void DisplayListBuilder::drawArc (const SkRect& bounds,
13931438 SkScalar start,
13941439 SkScalar sweep,
13951440 bool useCenter) {
13961441 Push<DrawArcOp>(0 , 1 , bounds, start, sweep, useCenter);
1442+ if (useCenter) {
1443+ CheckLayerOpacityHairlineCompatibility ();
1444+ } else {
1445+ CheckLayerOpacityCompatibility ();
1446+ }
13971447}
13981448void DisplayListBuilder::drawPoints (SkCanvas::PointMode mode,
13991449 uint32_t count,
@@ -1416,10 +1466,19 @@ void DisplayListBuilder::drawPoints(SkCanvas::PointMode mode,
14161466 return ;
14171467 }
14181468 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 );
14191475}
14201476void DisplayListBuilder::drawVertices (const sk_sp<SkVertices> vertices,
14211477 SkBlendMode mode) {
14221478 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 );
14231482}
14241483
14251484void DisplayListBuilder::drawImage (const sk_sp<SkImage> image,
@@ -1429,6 +1488,7 @@ void DisplayListBuilder::drawImage(const sk_sp<SkImage> image,
14291488 render_with_attributes
14301489 ? Push<DrawImageWithAttrOp>(0 , 1 , std::move (image), point, sampling)
14311490 : Push<DrawImageOp>(0 , 1 , std::move (image), point, sampling);
1491+ CheckLayerOpacityCompatibility (render_with_attributes);
14321492}
14331493void DisplayListBuilder::drawImageRect (const sk_sp<SkImage> image,
14341494 const SkRect& src,
@@ -1438,6 +1498,7 @@ void DisplayListBuilder::drawImageRect(const sk_sp<SkImage> image,
14381498 SkCanvas::SrcRectConstraint constraint) {
14391499 Push<DrawImageRectOp>(0 , 1 , std::move (image), src, dst, sampling,
14401500 render_with_attributes, constraint);
1501+ CheckLayerOpacityCompatibility (render_with_attributes);
14411502}
14421503void DisplayListBuilder::drawImageNine (const sk_sp<SkImage> image,
14431504 const SkIRect& center,
@@ -1448,6 +1509,7 @@ void DisplayListBuilder::drawImageNine(const sk_sp<SkImage> image,
14481509 ? Push<DrawImageNineWithAttrOp>(0 , 1 , std::move (image), center, dst,
14491510 filter)
14501511 : Push<DrawImageNineOp>(0 , 1 , std::move (image), center, dst, filter);
1512+ CheckLayerOpacityCompatibility (render_with_attributes);
14511513}
14521514void DisplayListBuilder::drawImageLattice (const sk_sp<SkImage> image,
14531515 const SkCanvas::Lattice& lattice,
@@ -1469,6 +1531,7 @@ void DisplayListBuilder::drawImageLattice(const sk_sp<SkImage> image,
14691531 filter, render_with_attributes);
14701532 CopyV (pod, lattice.fXDivs , xDivCount, lattice.fYDivs , yDivCount,
14711533 lattice.fColors , cellCount, lattice.fRectTypes , cellCount);
1534+ CheckLayerOpacityCompatibility (render_with_attributes);
14721535}
14731536void DisplayListBuilder::drawAtlas (const sk_sp<SkImage> atlas,
14741537 const SkRSXform xform[],
@@ -1503,6 +1566,10 @@ void DisplayListBuilder::drawAtlas(const sk_sp<SkImage> atlas,
15031566 }
15041567 CopyV (data_ptr, xform, count, tex, count);
15051568 }
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 );
15061573}
15071574
15081575void DisplayListBuilder::drawPicture (const sk_sp<SkPicture> picture,
@@ -1520,6 +1587,7 @@ void DisplayListBuilder::drawPicture(const sk_sp<SkPicture> picture,
15201587 // This behavior is identical to the way SkPicture computes nested op counts.
15211588 nested_op_count_ += picture->approximateOpCount (true ) - 1 ;
15221589 nested_bytes_ += picture->approximateBytesUsed ();
1590+ CheckLayerOpacityCompatibility (render_with_attributes);
15231591}
15241592void DisplayListBuilder::drawDisplayList (
15251593 const sk_sp<DisplayList> display_list) {
@@ -1532,11 +1600,13 @@ void DisplayListBuilder::drawDisplayList(
15321600 // This behavior is identical to the way SkPicture computes nested op counts.
15331601 nested_op_count_ += display_list->op_count (true ) - 1 ;
15341602 nested_bytes_ += display_list->bytes (true );
1603+ UpdateLayerOpacityCompatibility (display_list->can_apply_group_opacity ());
15351604}
15361605void DisplayListBuilder::drawTextBlob (const sk_sp<SkTextBlob> blob,
15371606 SkScalar x,
15381607 SkScalar y) {
15391608 Push<DrawTextBlobOp>(0 , 1 , std::move (blob), x, y);
1609+ CheckLayerOpacityCompatibility ();
15401610}
15411611void DisplayListBuilder::drawShadow (const SkPath& path,
15421612 const SkColor color,
@@ -1546,6 +1616,7 @@ void DisplayListBuilder::drawShadow(const SkPath& path,
15461616 transparent_occluder //
15471617 ? Push<DrawShadowTransparentOccluderOp>(0 , 1 , path, color, elevation, dpr)
15481618 : Push<DrawShadowOp>(0 , 1 , path, color, elevation, dpr);
1619+ UpdateLayerOpacityCompatibility (false );
15491620}
15501621
15511622// clang-format off
0 commit comments