From 07b9ca53f4d54847e9a1127a7cea6c7d56e8bf16 Mon Sep 17 00:00:00 2001 From: Eric Rozell Date: Wed, 3 Jan 2024 09:48:22 -0500 Subject: [PATCH] Fix crash when SVG is unloaded by XAML (#2195) XAML may unload the root SVG panel, which will trigger a recursive unload. For GroupView, this unload will clear the child collection. However, active operations on the SVG from the React Native UIManager may still be in flight, in which case we may attempt to remove a child that has already been cleared by the root unload. --- windows/RNSVG/GroupViewManager.cpp | 10 ++++++---- windows/RNSVG/RenderableView.cpp | 3 ++- windows/RNSVG/RenderableView.h | 5 ++++- windows/RNSVG/Views.idl | 1 + 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/windows/RNSVG/GroupViewManager.cpp b/windows/RNSVG/GroupViewManager.cpp index 742e4d0d8..dc1b7d279 100644 --- a/windows/RNSVG/GroupViewManager.cpp +++ b/windows/RNSVG/GroupViewManager.cpp @@ -71,11 +71,13 @@ void GroupViewManager::RemoveAllChildren(FrameworkElement const &parent) { void GroupViewManager::RemoveChildAt(FrameworkElement const &parent, int64_t index) { if (auto const &groupView{parent.try_as()}) { - auto const &child{groupView.Children().GetAt(static_cast(index))}; - child.Unload(); - child.SvgParent(nullptr); + if (!groupView.IsUnloaded()) { + auto const &child{groupView.Children().GetAt(static_cast(index))}; + child.Unload(); + child.SvgParent(nullptr); - groupView.Children().RemoveAt(static_cast(index)); + groupView.Children().RemoveAt(static_cast(index)); + } if (auto const &root{groupView.SvgRoot()}) { root.Invalidate(); diff --git a/windows/RNSVG/RenderableView.cpp b/windows/RNSVG/RenderableView.cpp index 4033d9a86..a70e2325e 100644 --- a/windows/RNSVG/RenderableView.cpp +++ b/windows/RNSVG/RenderableView.cpp @@ -358,6 +358,7 @@ void RenderableView::Unload() { m_propList.clear(); m_propSetMap.clear(); m_strokeDashArray.Clear(); + m_isUnloaded = true; } RNSVG::IRenderable RenderableView::HitTest(Point const &point) { @@ -370,7 +371,7 @@ RNSVG::IRenderable RenderableView::HitTest(Point const &point) { if (auto const &svgRoot{SvgRoot()}) { float canvasDiagonal{Utils::GetCanvasDiagonal(svgRoot.ActualSize())}; float strokeWidth{Utils::GetAbsoluteLength(StrokeWidth(), canvasDiagonal)}; - + check_hresult(geometry->StrokeContainsPoint(pointD2D, strokeWidth, nullptr, nullptr, &strokeContainsPoint)); } diff --git a/windows/RNSVG/RenderableView.h b/windows/RNSVG/RenderableView.h index 9e0b9469f..1e8294bdd 100644 --- a/windows/RNSVG/RenderableView.h +++ b/windows/RNSVG/RenderableView.h @@ -25,6 +25,8 @@ struct RenderableView : RenderableViewT { bool IsResponsible() { return m_isResponsible; } void IsResponsible(bool isResponsible) { m_isResponsible = isResponsible; } + bool IsUnloaded() { return m_isUnloaded; } + hstring FillBrushId() { return m_fillBrushId; } Windows::UI::Color Fill() { return m_fill; } float FillOpacity() { return m_fillOpacity; } @@ -73,7 +75,8 @@ struct RenderableView : RenderableViewT { RNSVG::D2DGeometry m_geometry{nullptr}; bool m_recreateResources{true}; bool m_isResponsible{false}; - + bool m_isUnloaded{false}; + hstring m_id{L""}; hstring m_clipPathId{L""}; Numerics::float3x2 m_transformMatrix{Numerics::make_float3x2_rotation(0)}; diff --git a/windows/RNSVG/Views.idl b/windows/RNSVG/Views.idl index 83c8e57ac..9342b6aad 100644 --- a/windows/RNSVG/Views.idl +++ b/windows/RNSVG/Views.idl @@ -38,6 +38,7 @@ namespace RNSVG { RenderableView(Microsoft.ReactNative.IReactContext context); SvgView SvgRoot{ get; }; + Boolean IsUnloaded { get; }; String Id{ get; }; Windows.Foundation.Numerics.Matrix3x2 SvgTransform{ get; };