Skip to content

Commit eb74b62

Browse files
author
reunion-maestro-bot
committed
Syncing content from committish 51a9c754ac08c43e58cfaa61726d1dabcb4d9937
1 parent 059fe6a commit eb74b62

12 files changed

Lines changed: 253 additions & 32 deletions

File tree

src/dxaml/xcp/components/imaging/RenderTargetBitmapImplUsingSpriteVisuals.cpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@
3030
#include <microsoft.ui.composition.internal.h>
3131
#include <microsoft.ui.composition.internal.interop.h>
3232
#include <microsoft.ui.composition.private.interop.h>
33+
#include "FrameworkUdk/Containment.h"
34+
35+
#define WINAPPSDK_CHANGEID_61936248 61936248, WinAppSDK_1_8_8
3336

3437
class CaptureAsyncCompletionState
3538
{
@@ -115,9 +118,21 @@ RenderTargetBitmapImplUsingSpriteVisuals::PreCommit(
115118
HWCompTreeNode* elementCompNodeNoRef = m_uiElement->GetCompositionPeer();
116119
if (elementCompNodeNoRef == nullptr)
117120
{
118-
// The element is being rendered with a LayoutTransitionElement, and doesn't have a comp node. Instead, get the comp node
119-
// from the LTE itself. The LTE will contain all the SpriteVisual content in the element's subtree.
120-
ASSERT(m_uiElement->IsHiddenForLayoutTransition());
121+
if (WinAppSdk::Containment::IsChangeEnabled<WINAPPSDK_CHANGEID_61936248>())
122+
{
123+
// The composition peer can be null for reasons other than layout transitions.
124+
// Check for an LTE before dereferencing.
125+
if (!m_uiElement->IsHiddenForLayoutTransition())
126+
{
127+
return E_FAIL;
128+
}
129+
}
130+
else
131+
{
132+
// The element is being rendered with a LayoutTransitionElement, and doesn't have a comp node. Instead, get the comp node
133+
// from the LTE itself. The LTE will contain all the SpriteVisual content in the element's subtree.
134+
ASSERT(m_uiElement->IsHiddenForLayoutTransition());
135+
}
121136
elementCompNodeNoRef = m_uiElement->GetFirstLTETargetingThis()->GetCompositionPeer();
122137
}
123138

src/dxaml/xcp/core/core/elements/Popup.cpp

Lines changed: 78 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@
4040
#include "XamlRoot_Partial.h"
4141
#include <Microsoft.UI.Composition.h>
4242
#include <FrameworkUdk/Theming.h>
43+
#include <FrameworkUdk/Containment.h>
44+
45+
#define WINAPPSDK_CHANGEID_61884734 61884734, WinAppSDK_1_8_8
4346
#include "WinRTExpressionConversionContext.h"
4447
#include "VisualDebugTags.h"
4548
#include "xcpwindow.h"
@@ -1328,6 +1331,27 @@ float CPopup::GetWindowedPopupRasterizationScale() const
13281331
return rasterizationScale;
13291332
}
13301333

1334+
float CPopup::GetWindowedPopupRootVisualScaleCompensation() const
1335+
{
1336+
// Windowed popups render in a separate ContentIsland whose RasterizationScale is driven by the system (popup HWND DPI).
1337+
// For XAML Islands, the effective XamlRoot scale may be overridden (e.g. DesktopWindowXamlSource.OverrideScale).
1338+
// The main island cancels/adjusts system scale via RootScale. Windowed popups need the same compensation.
1339+
if (!m_contentIsland)
1340+
{
1341+
return 1.0f;
1342+
}
1343+
1344+
const float systemScaleForPopupIsland = GetWindowedPopupRasterizationScale();
1345+
const float effectiveScaleForPopup = GetEffectiveRootScale();
1346+
1347+
if (systemScaleForPopupIsland <= 0.0f || effectiveScaleForPopup <= 0.0f)
1348+
{
1349+
return 1.0f;
1350+
}
1351+
1352+
return effectiveScaleForPopup / systemScaleForPopupIsland;
1353+
}
1354+
13311355
wrl::ComPtr<ixp::IPointerPoint> CPopup::GetPreviousPointerPoint()
13321356
{
13331357
return m_inputSiteAdapter->GetPreviousPointerPoint();
@@ -1627,12 +1651,26 @@ _Check_return_ HRESULT CPopup::PositionAndSizeWindowForWindowedPopup()
16271651
undoY += insets.top;
16281652
}
16291653

1654+
float rootScaleCompensation = 1.0f;
1655+
if (WinAppSdk::Containment::IsChangeEnabled<WINAPPSDK_CHANGEID_61884734>())
1656+
{
1657+
rootScaleCompensation = GetWindowedPopupRootVisualScaleCompensation();
1658+
}
1659+
16301660
if (m_contentIslandRootVisual)
16311661
{
16321662
// Set any scale inherited from the ancestor chain
16331663
CMILMatrix rootTransform(true);
1634-
rootTransform.SetM11(scaleX);
1635-
rootTransform.SetM22(scaleY);
1664+
if (WinAppSdk::Containment::IsChangeEnabled<WINAPPSDK_CHANGEID_61884734>())
1665+
{
1666+
rootTransform.SetM11(scaleX * rootScaleCompensation);
1667+
rootTransform.SetM22(scaleY * rootScaleCompensation);
1668+
}
1669+
else
1670+
{
1671+
rootTransform.SetM11(scaleX);
1672+
rootTransform.SetM22(scaleY);
1673+
}
16361674

16371675
// Set premultiplied "undo" transform on the window's root visual
16381676
CMILMatrix undo(true);
@@ -1682,11 +1720,26 @@ _Check_return_ HRESULT CPopup::PositionAndSizeWindowForWindowedPopup()
16821720
// Tell the windowed popup inputsite adapter the offset of the popup window from the content
16831721
// root. We do this by using the position passed to MoveAndSize (either earlier in this function
16841722
// or updated by AdjustWindowedPopupBoundsForDropShadow), converted to island coords in dips.
1685-
wf::Point transformedOffset{
1686-
PhysicalPixelsToDips(static_cast<float>(m_windowedPopupMoveAndResizeRect.X - rootOffsetPhysical.x)),
1687-
PhysicalPixelsToDips(static_cast<float>(m_windowedPopupMoveAndResizeRect.Y - rootOffsetPhysical.y))};
1723+
if (WinAppSdk::Containment::IsChangeEnabled<WINAPPSDK_CHANGEID_61884734>())
1724+
{
1725+
const float popupIslandRasterizationScale = m_contentIsland ? GetWindowedPopupRasterizationScale() : 0.0f;
1726+
const float offsetXPhysical = static_cast<float>(m_windowedPopupMoveAndResizeRect.X - rootOffsetPhysical.x);
1727+
const float offsetYPhysical = static_cast<float>(m_windowedPopupMoveAndResizeRect.Y - rootOffsetPhysical.y);
1728+
1729+
wf::Point transformedOffset{
1730+
popupIslandRasterizationScale > 0.0f ? (offsetXPhysical / popupIslandRasterizationScale) : PhysicalPixelsToDips(offsetXPhysical),
1731+
popupIslandRasterizationScale > 0.0f ? (offsetYPhysical / popupIslandRasterizationScale) : PhysicalPixelsToDips(offsetYPhysical)};
1732+
1733+
IFC_RETURN(UpdateTranslationFromContentRoot(transformedOffset, /*forceUpdate*/ false, rootScaleCompensation));
1734+
}
1735+
else
1736+
{
1737+
wf::Point transformedOffset{
1738+
PhysicalPixelsToDips(static_cast<float>(m_windowedPopupMoveAndResizeRect.X - rootOffsetPhysical.x)),
1739+
PhysicalPixelsToDips(static_cast<float>(m_windowedPopupMoveAndResizeRect.Y - rootOffsetPhysical.y))};
16881740

1689-
IFC_RETURN(UpdateTranslationFromContentRoot(transformedOffset, /*forceUpdate*/ false));
1741+
IFC_RETURN(UpdateTranslationFromContentRoot(transformedOffset, /*forceUpdate*/ false));
1742+
}
16901743

16911744
// Play the MenuPopupThemeTransition, if we have one
16921745
if (m_animationRootVisual && m_secretTransitionTarget && m_secretTransitionTarget->IsDirty())
@@ -2296,9 +2349,9 @@ HWND CPopup::GetPopupPositioningWindow() const
22962349
}
22972350

22982351
// Converts between logical and physical pixels
2299-
float CPopup::GetEffectiveRootScale()
2352+
float CPopup::GetEffectiveRootScale() const
23002353
{
2301-
const auto scale = RootScale::GetRasterizationScaleForElement(this);
2354+
const auto scale = RootScale::GetRasterizationScaleForElement(const_cast<CPopup*>(this));
23022355
return scale;
23032356
}
23042357

@@ -2714,7 +2767,7 @@ CPopup::ClearUCRemoveLogicalParentFlag(
27142767
//
27152768
//------------------------------------------------------------------------
27162769
_Check_return_ HRESULT
2717-
CPopup::UpdateTranslationFromContentRoot(const wf::Point& offset, bool forceUpdate)
2770+
CPopup::UpdateTranslationFromContentRoot(const wf::Point& offset, bool forceUpdate, float rootScaleCompensation)
27182771
{
27192772
IFCEXPECT_RETURN(m_inputSiteAdapter);
27202773

@@ -2725,6 +2778,16 @@ CPopup::UpdateTranslationFromContentRoot(const wf::Point& offset, bool forceUpda
27252778
m_offsetFromMainWindow.X = offset.X;
27262779
m_offsetFromMainWindow.Y = offset.Y;
27272780

2781+
// Pointer points for windowed popups are delivered in the coordinate space of the popup's content island.
2782+
// When DesktopWindowXamlSource.OverrideScale is used, the popup island's rasterization scale (system DPI)
2783+
// can differ from the XamlRoot effective scale. We compensate the visuals by scaling the island root visual;
2784+
// mirror that compensation for input by scaling pointer coordinates by the inverse ratio.
2785+
float inputScaleCompensation = 1.0f;
2786+
if (WinAppSdk::Containment::IsChangeEnabled<WINAPPSDK_CHANGEID_61884734>())
2787+
{
2788+
inputScaleCompensation = (rootScaleCompensation != 0.0f) ? (1.0f / rootScaleCompensation) : 1.0f;
2789+
}
2790+
27282791
auto dxamlCore = DXamlCore::GetCurrent();
27292792
auto coreServices = dxamlCore->GetHandle();
27302793
CREATEPARAMETERS cp(coreServices);
@@ -2734,6 +2797,12 @@ CPopup::UpdateTranslationFromContentRoot(const wf::Point& offset, bool forceUpda
27342797
xref_ptr<CMatrix> matrix;
27352798
xref_ptr<CMatrixTransform> matrixTransform;
27362799

2800+
if (WinAppSdk::Containment::IsChangeEnabled<WINAPPSDK_CHANGEID_61884734>())
2801+
{
2802+
matTransform.SetM11(inputScaleCompensation);
2803+
matTransform.SetM22(inputScaleCompensation);
2804+
}
2805+
27372806
IFC_RETURN(CMatrixTransform::Create(reinterpret_cast<CDependencyObject**>(matrixTransform.ReleaseAndGetAddressOf()), &cp));
27382807
IFC_RETURN(CMatrix::Create(reinterpret_cast<CDependencyObject**>(matrix.ReleaseAndGetAddressOf()), &cp));
27392808

src/dxaml/xcp/core/core/elements/uielement.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@
5757
#include "XStringUtils.h"
5858

5959
#include <CValueBoxer.h>
60+
#include <rendertargetbitmapmgr.h>
61+
#include "FrameworkUdk/Containment.h"
62+
63+
#define WINAPPSDK_CHANGEID_61936248 61936248, WinAppSDK_1_8_8
6064

6165
using namespace DirectUI;
6266
using namespace DCompHelpers;
@@ -1628,6 +1632,21 @@ _Check_return_ HRESULT CUIElement::LeaveImpl(_In_ CDependencyObject *pNamescopeO
16281632
const bool isParentEnabled = params.fCoercedIsEnabled;
16291633
bool alreadyCanceledTransitions = false;
16301634

1635+
// If this element is targeted by an RTB, cancel the in-flight render.
1636+
// The composition peer is about to be removed, and PreCommit would crash
1637+
// trying to access it.
1638+
if (WinAppSdk::Containment::IsChangeEnabled<WINAPPSDK_CHANGEID_61936248>())
1639+
{
1640+
if (params.fIsLive && m_isRenderTargetSource)
1641+
{
1642+
auto pRTBManager = core->GetRenderTargetBitmapManager();
1643+
if (pRTBManager != nullptr)
1644+
{
1645+
IGNOREHR(pRTBManager->CancelRenderForElement(this));
1646+
}
1647+
}
1648+
}
1649+
16311650
// If parent is enabled, but local value of IsEnabled is FALSE, need to disable children.
16321651
if (isParentEnabled && !GetIsEnabled())
16331652
{

src/dxaml/xcp/core/dll/rendertargetbitmapmgr.cpp

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
#include <UIThreadScheduler.h>
99
#include <D3D11Device.h>
1010
#include <WindowsGraphicsDeviceManager.h>
11+
#include "FrameworkUdk/Containment.h"
12+
13+
#define WINAPPSDK_CHANGEID_61936248 61936248, WinAppSDK_1_8_8
1114

1215
//------------------------------------------------------------------------
1316
//
@@ -521,7 +524,24 @@ CRenderTargetBitmapManager::PreCommit(
521524
FALSE /* bSignaled */,
522525
FALSE /* bManual */));
523526

524-
IFC_RETURN(renderTargetElement->PreCommit(renderTarget, completionEvent));
527+
if (WinAppSdk::Containment::IsChangeEnabled<WINAPPSDK_CHANGEID_61936248>())
528+
{
529+
// PreCommit may fail if the target element has left the visual tree
530+
// (e.g., popup closed). Call the outer FailRender to properly transition
531+
// to Idle and complete the async action with an error.
532+
// scope_exit closes the event; no wait was submitted so no hang.
533+
HRESULT preCommitHr = renderTargetElement->PreCommit(renderTarget, completionEvent);
534+
if (FAILED(preCommitHr))
535+
{
536+
IGNOREHR(renderTargetElement->FailRender(preCommitHr));
537+
current = next;
538+
continue;
539+
}
540+
}
541+
else
542+
{
543+
IFC_RETURN(renderTargetElement->PreCommit(renderTarget, completionEvent));
544+
}
525545

526546
AddWaitItem(renderTargetElement, completionEvent);
527547

@@ -956,6 +976,38 @@ CRenderTargetBitmapManager::CountElementJobs(
956976
return elementJobs;
957977
}
958978

979+
//------------------------------------------------------------------------
980+
//
981+
// Synopsis:
982+
// Cancels RTB operations targeting the given element that have not
983+
// yet reached the capture phase (pending and rendering lists only).
984+
// RTBs in the drawing list have already completed CaptureAsync and
985+
// will finish safely without accessing the element's composition peer.
986+
// Called when an element leaves the visual tree (e.g., popup close)
987+
// to prevent PreCommit from accessing stale composition state.
988+
// Uses IterateList which safely captures 'next' before the callback,
989+
// so FailRender can safely modify the list during iteration.
990+
//
991+
//------------------------------------------------------------------------
992+
_Check_return_ HRESULT
993+
CRenderTargetBitmapManager::CancelRenderForElement(
994+
_In_ CUIElement* pElement)
995+
{
996+
auto cancelCallback = [&] (_In_ IRenderTargetElement* element)
997+
{
998+
if ((element->GetRenderTargetElementData() != nullptr) &&
999+
(element->GetRenderTargetElementData()->GetRenderElement() == pElement))
1000+
{
1001+
IGNOREHR(element->FailRender(E_ABORT));
1002+
}
1003+
};
1004+
1005+
IterateList(m_pPendingListNoRef, cancelCallback);
1006+
IterateList(m_pRenderingListNoRef, cancelCallback);
1007+
1008+
return S_OK;
1009+
}
1010+
9591011
void
9601012
CRenderTargetBitmapManager::EnsureWaitList()
9611013
{

src/dxaml/xcp/core/inc/Popup.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ class CPopup : public CFrameworkElement
119119

120120
_Check_return_ HRESULT ClearUCRemoveLogicalParentFlag(_In_ CUIElement* pChild);
121121

122-
_Check_return_ HRESULT UpdateTranslationFromContentRoot(const wf::Point& offset, bool forceUpdate = false);
122+
_Check_return_ HRESULT UpdateTranslationFromContentRoot(const wf::Point& offset, bool forceUpdate = false, float rootScaleCompensation = 0.0f);
123123

124124
protected:
125125
_Check_return_ HRESULT EnterImpl(_In_ CDependencyObject *pNamescopeOwner, _In_ EnterParams params) override;
@@ -447,7 +447,8 @@ class CPopup : public CFrameworkElement
447447
_Check_return_ HRESULT AdjustWindowedPopupBoundsForDropShadow(_In_ const XRECTF* popupWindowBounds);
448448
bool ShouldPopupRendersDropShadow() const;
449449
XTHICKNESS GetInsetsForDropShadow();
450-
float GetEffectiveRootScale();
450+
float GetEffectiveRootScale() const;
451+
float GetWindowedPopupRootVisualScaleCompensation() const;
451452
float DipsToPhysicalPixels(_In_ float dips);
452453
float PhysicalPixelsToDips(_In_ float physicalPixels);
453454
void DipsToPhysicalPixelsRect(_Inout_ XRECTF* rect);

src/dxaml/xcp/core/inc/rendertargetbitmapmgr.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,11 @@ class CRenderTargetBitmapManager : public CXcpObjectBase<IObject>
9090

9191
int CountElementJobs(_In_ CUIElement* uiElement);
9292

93+
// Cancel any in-flight RTB operations targeting this element.
94+
// Called when an element leaves the visual tree to prevent PreCommit
95+
// from accessing stale composition state.
96+
_Check_return_ HRESULT CancelRenderForElement(_In_ CUIElement* pElement);
97+
9398
private:
9499

95100
CRenderTargetBitmapManager(_In_ CCoreServices *pCore);

src/dxaml/xcp/dxaml/lib/UIAffinityReleaseQueue.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
#include "MUX-ETWEvents.h"
99
#include "BuildTreeService.g.h"
1010
#include "BudgetManager.g.h"
11+
#include "FrameworkUdk/Containment.h"
12+
13+
// Bug 62097119: [1.8 Servicing][WASDK] Fix re-entrancy crash: PauseDispatch during UIAffinityReleaseQueue::DoCleanup
14+
#define WINAPPSDK_CHANGEID_62097119 62097119, WinAppSDK_1_8_8
1115

1216
using namespace DirectUI;
1317
using namespace Instrumentation;
@@ -176,6 +180,20 @@ HRESULT UIAffinityReleaseQueue::DoCleanup( _In_ BOOLEAN bSync, _Out_ BOOLEAN *co
176180

177181

178182
// Process objects for final release.
183+
//
184+
// Pause XAML dispatch during final releases. Object release calls can trigger
185+
// cross-apartment COM RPCs (e.g., RemoteReleaseRifRef for proxy teardown),
186+
// which enter a COM modal loop that pumps messages via PeekMessage. Without
187+
// pausing, CoreMessaging can fire the DispatcherQueueTimer re-entrantly during
188+
// the pump, causing a CReentrancyGuard fail-fast in
189+
// OnReentrancyProtectedWindowMessage. PauseDispatch sets m_state to Suspended,
190+
// which MessageTimerCallback checks before dispatching — preventing the
191+
// re-entrant dispatch. ResumeDispatch restarts the timer if there is pending
192+
// work, so no messages are lost.
193+
if (WinAppSdk::Containment::IsChangeEnabled<WINAPPSDK_CHANGEID_62097119>())
194+
{
195+
DXamlCore::GetCurrent()->PauseDispatchAtControl();
196+
}
179197

180198
*completed = TRUE;
181199
firstRelease = m_queuedObjectsForFinalRelease.begin();
@@ -262,6 +280,13 @@ HRESULT UIAffinityReleaseQueue::DoCleanup( _In_ BOOLEAN bSync, _Out_ BOOLEAN *co
262280
m_bInCleanup = FALSE;
263281

264282
Cleanup:
283+
// Resume dispatch — must happen on all paths (normal and error) to avoid
284+
// permanently stalling the dispatcher. Paired with PauseDispatchAtControl above.
285+
if (WinAppSdk::Containment::IsChangeEnabled<WINAPPSDK_CHANGEID_62097119>())
286+
{
287+
DXamlCore::GetCurrent()->ResumeDispatchAtControl();
288+
}
289+
265290
TraceReleaseQueueCleanupEnd();
266291

267292
//Telemetry Notify ,UIFinalizer ended

0 commit comments

Comments
 (0)