diff --git a/controls/dev/AnnotatedScrollBar/AnnotatedScrollBar.cpp b/controls/dev/AnnotatedScrollBar/AnnotatedScrollBar.cpp index ac78dabe26..70fde742c1 100644 --- a/controls/dev/AnnotatedScrollBar/AnnotatedScrollBar.cpp +++ b/controls/dev/AnnotatedScrollBar/AnnotatedScrollBar.cpp @@ -18,6 +18,10 @@ #include "AnnotatedScrollBarValueFromScrollOffsetRequestedEventArgs.h" #include "AnnotatedScrollBarDetailLabelRequestedEventArgs.h" #include "Vector.h" +#include + +// Bug 51993634: [1.4 servicing] - Prevent crash in AnnotatedScrollBar::LayoutLabels() method at app-shutdown time. +#define WINAPPSDK_CHANGEID_51993634 51993634 // Change to 'true' to turn on debugging outputs in Output window bool AnnotatedScrollBarTrace::s_IsDebugOutputEnabled{ false }; @@ -325,20 +329,47 @@ void AnnotatedScrollBar::QueueLayoutLabels(unsigned int millisecondWait) if (!m_labelsDebounce.test_and_set()) { - auto strongThis = get_strong(); // ensure object lifetime during coroutines - auto runLayoutLabelsAction = [&, strongThis]() + if (WinAppSdk::Containment::IsChangeEnabled()) { - strongThis->m_labelsDebounce.clear(); - strongThis->LayoutLabels(); - }; + auto weakThis = get_weak(); + auto runLayoutLabelsAction = [weakThis]() + { + /* WindowsXamlManager::GetForCurrentThread does not exist in WinAppSDK 1.4. + if (winrt::WindowsXamlManager::GetForCurrentThread() == nullptr) + { + // Exit early if Xaml core has already shut down. + return; + } + */ - SharedHelpers::ScheduleActionAfterWait(runLayoutLabelsAction, millisecondWait); + if (auto strongThis = weakThis.get()) + { + strongThis->m_labelsDebounce.clear(); + strongThis->LayoutLabels(); + } + }; + + SharedHelpers::ScheduleActionAfterWait(runLayoutLabelsAction, millisecondWait); + } + else + { + auto strongThis = get_strong(); // ensure object lifetime during coroutines + auto runLayoutLabelsAction = [&, strongThis]() + { + strongThis->m_labelsDebounce.clear(); + strongThis->LayoutLabels(); + }; + + SharedHelpers::ScheduleActionAfterWait(runLayoutLabelsAction, millisecondWait); + } } } void AnnotatedScrollBar::LayoutLabels() { - auto labelsGrid = m_labelsGrid.get(); + auto labelsGrid = WinAppSdk::Containment::IsChangeEnabled() ? + m_labelsGrid.safe_get() : m_labelsGrid.get(); + if (!labelsGrid) { return; diff --git a/dxaml/xcp/components/elements/UIElementLayout.cpp b/dxaml/xcp/components/elements/UIElementLayout.cpp index 431c256d6d..f796822ab0 100644 --- a/dxaml/xcp/components/elements/UIElementLayout.cpp +++ b/dxaml/xcp/components/elements/UIElementLayout.cpp @@ -8,6 +8,10 @@ #include #include #include +#include + +// Bug 51993827: [1.4 servicing] BreadcrumbBar ellipsis flyout doesn't render all items if the window is small +#define WINAPPSDK_CHANGEID_51993827 51993827 void ComputeUnidimensionalEffectiveViewport( _In_ const std::vector& viewports, @@ -427,11 +431,23 @@ _Check_return_ HRESULT CUIElement::EffectiveViewportWalk( if (currentChild->GetIsViewportDirtyOrOnViewportDirtyPath() || (newDirtyFound && currentChild->GetWantsViewportOrContributesToViewport())) { - IFC_RETURN(currentChild->EffectiveViewportWalk( - newDirtyFound, - transformsToViewports, - horizontalViewports, - verticalViewports)); + if (WinAppSdk::Containment::IsChangeEnabled()) + { + IFC_RETURN(EffectiveViewportWalkToChild( + currentChild, + newDirtyFound, + transformsToViewports, + horizontalViewports, + verticalViewports)); + } + else + { + IFC_RETURN(currentChild->EffectiveViewportWalk( + newDirtyFound, + transformsToViewports, + horizontalViewports, + verticalViewports)); + } } // If at least one of the children still has the viewport @@ -446,7 +462,12 @@ _Check_return_ HRESULT CUIElement::EffectiveViewportWalk( // traversing the rest of the visual tree. if (addedViewports) { + // This one is a little tricky. CXamlIslandRoot::EffectiveViewportWalkCore will push two viewports without + // pushing a transform, so we technically can't blindly pop all three vectors. But given CXamlIslandRoot is + // always the first element to push anything, the transform vector will be empty anyway when we get back up + // to CXamlIslandRoot to pop things. transformsToViewports.pop_back(); + horizontalViewports.pop_back(); verticalViewports.pop_back(); } @@ -454,3 +475,19 @@ _Check_return_ HRESULT CUIElement::EffectiveViewportWalk( return S_OK; } + +_Check_return_ HRESULT CUIElement::EffectiveViewportWalkToChild( + _In_ CUIElement* child, + const bool dirtyFound, + _In_ std::vector& transformsToViewports, + _In_ std::vector& horizontalViewports, + _In_ std::vector& verticalViewports) +{ + IFC_RETURN(child->EffectiveViewportWalk( + dirtyFound, + transformsToViewports, + horizontalViewports, + verticalViewports)); + + return S_OK; +} \ No newline at end of file diff --git a/dxaml/xcp/core/core/elements/Popup.cpp b/dxaml/xcp/core/core/elements/Popup.cpp index 9df376e1ee..63fdfe37cc 100644 --- a/dxaml/xcp/core/core/elements/Popup.cpp +++ b/dxaml/xcp/core/core/elements/Popup.cpp @@ -5358,3 +5358,72 @@ bool CPopupRoot::ComputeDepthInOpenPopups() return false; } + +_Check_return_ HRESULT CPopupRoot::EffectiveViewportWalkToChild( + _In_ CUIElement* child, + const bool dirtyFound, + _In_ std::vector& transformsToViewports, + _In_ std::vector& horizontalViewports, + _In_ std::vector& verticalViewports) +{ + // We expect the popup root at the tree, so there should be at most one viewport (from the main Xaml island) that we've discovered so far. + ASSERT(horizontalViewports.size() == verticalViewports.size()); + ASSERT(transformsToViewports.size() <= 1); + ASSERT(horizontalViewports.size() <= 1); + + bool poppedViewport = false; + UnidimensionalViewportInformation poppedHorizontalViewport(0, 0); + UnidimensionalViewportInformation poppedVerticalViewport(0, 0); + + bool poppedTransform = false; + TransformToPreviousViewport poppedTransformToViewport(nullptr, nullptr); + + // + // Windowed popups aren't limited to the bounds of the main Xaml island. If we walk through a windowed popup during + // the viewport walk, make sure we clear out the implicit viewport from the main Xaml island bounds. + // + xref_ptr popup; + IFC_RETURN(GetOpenPopupForElement(child, popup.ReleaseAndGetAddressOf())); + if (popup & popup->IsWindowed()) + { + if (horizontalViewports.size() == 1) + { + poppedHorizontalViewport = horizontalViewports[0]; + horizontalViewports.pop_back(); + + poppedVerticalViewport = verticalViewports[0]; + verticalViewports.pop_back(); + + poppedViewport = true; + } + + if (transformsToViewports.size() == 1) + { + poppedTransformToViewport = transformsToViewports[0]; + transformsToViewports.pop_back(); + + poppedTransform = true; + } + } + + IFC_RETURN(child->EffectiveViewportWalk( + dirtyFound, + transformsToViewports, + horizontalViewports, + verticalViewports)); + + if (poppedViewport) + { + ASSERT(horizontalViewports.size() == 0); + horizontalViewports.push_back(poppedHorizontalViewport); + verticalViewports.push_back(poppedVerticalViewport); + } + + if (poppedTransform) + { + ASSERT(transformsToViewports.size() == 0); + transformsToViewports.push_back(poppedTransformToViewport); + } + + return S_OK; +} diff --git a/dxaml/xcp/core/inc/Popup.h b/dxaml/xcp/core/inc/Popup.h index 77e0802150..504676efe3 100644 --- a/dxaml/xcp/core/inc/Popup.h +++ b/dxaml/xcp/core/inc/Popup.h @@ -714,6 +714,13 @@ class CPopupRoot final : public CPanel _In_ const D2DRenderParams& printParams ) override; + _Check_return_ HRESULT EffectiveViewportWalkToChild( + _In_ CUIElement* child, + const bool dirtyFound, + _In_ std::vector& transformsToViewports, + _In_ std::vector& horizontalViewports, + _In_ std::vector& verticalViewports) override; + public: KnownTypeIndex GetTypeIndex() const override diff --git a/dxaml/xcp/core/inc/uielement.h b/dxaml/xcp/core/inc/uielement.h index 7b0e604b00..65076f4f8a 100644 --- a/dxaml/xcp/core/inc/uielement.h +++ b/dxaml/xcp/core/inc/uielement.h @@ -1677,6 +1677,13 @@ class CUIElement : public CDependencyObject _In_ std::vector& verticalViewports, _Out_ bool& addedViewports); + virtual _Check_return_ HRESULT EffectiveViewportWalkToChild( + _In_ CUIElement* child, + const bool dirtyFound, + _In_ std::vector& transformsToViewports, + _In_ std::vector& horizontalViewports, + _In_ std::vector& verticalViewports); + private: float LayoutRoundHelper(const float value, const bool useCeiling); diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index c08d5bc38c..8abb66105c 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -6,13 +6,13 @@ https://dev.azure.com/microsoft/ProjectReunion/_git/WindowsAppSDK 5e13356548a275bd6963d391a7e227b6614174f5 - + https://dev.azure.com/microsoft/LiftedIXP/_git/DCPP - 6b9f6f6f4f2977b56b347e943e6804b29886ed19 + 534b0b3660f84e948237f93c52b11bb816fb985c - + https://dev.azure.com/microsoft/LiftedIXP/_git/DCPP - 6b9f6f6f4f2977b56b347e943e6804b29886ed19 + 534b0b3660f84e948237f93c52b11bb816fb985c