diff --git a/engine/src/flutter/ci/licenses_golden/licenses_flutter b/engine/src/flutter/ci/licenses_golden/licenses_flutter index 4f805f0c653..030be169a8d 100644 --- a/engine/src/flutter/ci/licenses_golden/licenses_flutter +++ b/engine/src/flutter/ci/licenses_golden/licenses_flutter @@ -107,6 +107,7 @@ FILE: ../../../flutter/display_list/display_list_tile_mode.h FILE: ../../../flutter/display_list/display_list_unittests.cc FILE: ../../../flutter/display_list/display_list_utils.cc FILE: ../../../flutter/display_list/display_list_utils.h +FILE: ../../../flutter/display_list/display_list_utils_unittests.cc FILE: ../../../flutter/display_list/display_list_vertices.cc FILE: ../../../flutter/display_list/display_list_vertices.h FILE: ../../../flutter/display_list/display_list_vertices_unittests.cc diff --git a/engine/src/flutter/display_list/BUILD.gn b/engine/src/flutter/display_list/BUILD.gn index c3442b4a44e..26cd0a06afe 100644 --- a/engine/src/flutter/display_list/BUILD.gn +++ b/engine/src/flutter/display_list/BUILD.gn @@ -99,6 +99,7 @@ if (enable_unittests) { "display_list_paint_unittests.cc", "display_list_path_effect_unittests.cc", "display_list_unittests.cc", + "display_list_utils_unittests.cc", "display_list_vertices_unittests.cc", ] diff --git a/engine/src/flutter/display_list/display_list_utils.cc b/engine/src/flutter/display_list/display_list_utils.cc index 58fa227056f..25c88dea6cd 100644 --- a/engine/src/flutter/display_list/display_list_utils.cc +++ b/engine/src/flutter/display_list/display_list_utils.cc @@ -33,6 +33,9 @@ void SkPaintDispatchHelper::save_opacity(SkScalar child_opacity) { set_opacity(child_opacity); } void SkPaintDispatchHelper::restore_opacity() { + if (save_stack_.empty()) { + return; + } set_opacity(save_stack_.back().opacity); save_stack_.pop_back(); } @@ -163,6 +166,9 @@ void SkMatrixDispatchHelper::save() { saved_.push_back(matrix_); } void SkMatrixDispatchHelper::restore() { + if (saved_.empty()) { + return; + } matrix_ = saved_.back(); matrix33_ = matrix_.asM33(); saved_.pop_back(); @@ -233,6 +239,9 @@ void ClipBoundsDispatchHelper::save() { } } void ClipBoundsDispatchHelper::restore() { + if (saved_.empty()) { + return; + } bounds_ = saved_.back(); saved_.pop_back(); has_clip_ = (bounds_.fLeft <= bounds_.fRight && // diff --git a/engine/src/flutter/display_list/display_list_utils_unittests.cc b/engine/src/flutter/display_list/display_list_utils_unittests.cc new file mode 100644 index 00000000000..3141ffd0ebb --- /dev/null +++ b/engine/src/flutter/display_list/display_list_utils_unittests.cc @@ -0,0 +1,41 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/display_list/display_list_utils.h" +#include "gtest/gtest.h" + +namespace flutter { +namespace testing { + +class MockDispatchHelper final : public virtual Dispatcher, + public virtual SkPaintDispatchHelper, + public virtual SkMatrixDispatchHelper, + public virtual ClipBoundsDispatchHelper, + public virtual IgnoreDrawDispatchHelper { + public: + void save() override { + SkPaintDispatchHelper::save_opacity(0.5f); + SkMatrixDispatchHelper::save(); + ClipBoundsDispatchHelper::save(); + } + + void restore() override { + SkPaintDispatchHelper::restore_opacity(); + SkMatrixDispatchHelper::restore(); + ClipBoundsDispatchHelper::restore(); + } +}; + +// Regression test for https://github.com/flutter/flutter/issues/100176. +TEST(DisplayListUtils, OverRestore) { + MockDispatchHelper helper; + helper.save(); + helper.restore(); + // There should be a protection here for over-restore to keep the program from + // crashing. + helper.restore(); +} + +} // namespace testing +} // namespace flutter