From 103280fff8b93d7492b8df5a6144367bfb8f8375 Mon Sep 17 00:00:00 2001 From: Collin Schneide <27441618+FaithfulAudio@users.noreply.github.com> Date: Thu, 20 Aug 2026 18:48:17 -0500 Subject: [PATCH] Fix hosted ContentIsland rendering at reduced size on scaled displays The child site reports ShouldApplyRasterizationScale = false, meaning the host owns applying the island rasterization scale at presentation. The placement visual lives in the physical-pixel composition tree unscaled, so hosted content laid out in DIPs and rasterized at RasterizationScale presented at 1x: on a 200% display, islands rendered at exactly half size in the top-left of their frame. Scale the placement visual by pointScaleFactor; at 100% display scale this is an identity transform. --- .../Composition/ContentIslandComponentView.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/vnext/Microsoft.ReactNative/Fabric/Composition/ContentIslandComponentView.cpp b/vnext/Microsoft.ReactNative/Fabric/Composition/ContentIslandComponentView.cpp index 46f404be61f..5b2d8253631 100644 --- a/vnext/Microsoft.ReactNative/Fabric/Composition/ContentIslandComponentView.cpp +++ b/vnext/Microsoft.ReactNative/Fabric/Composition/ContentIslandComponentView.cpp @@ -68,6 +68,24 @@ void ContentIslandComponentView::ConnectInternal() noexcept { ChildSiteLink().ActualSize({m_layoutMetrics.frame.size.width, m_layoutMetrics.frame.size.height}); + // The child site reports ShouldApplyRasterizationScale = false: the host is + // responsible for applying the island's rasterization scale at presentation. + // This placement visual lives in the physical-pixel composition tree, so + // without a scale the hosted content lays out at DIP size, rasterizes at + // RasterizationScale, and presents unscaled - on a display above 100% scale, + // hosted islands render proportionally smaller in the top-left of their + // frame (observed with a WebView2-hosted island at 200%: site ActualSize + // 1368x728 DIPs, RasterizationScale 2.0, rendered at exactly half size). + // Scaling the placement visual by pointScaleFactor is the missing host-side + // step; at 100% scale this is Scale(1,1,1), a no-op. + { + auto placementVisual = + winrt::Microsoft::ReactNative::Composition::Experimental::CompositionContextHelper::InnerVisual(Visual()) + .as(); + const float placementScale = m_layoutMetrics.pointScaleFactor; + placementVisual.Scale({placementScale, placementScale, 1.0f}); + } + // Issue #15557: Set initial LocalToParentTransformMatrix synchronously before Connect. // This fixes popup position being wrong even without scrolling. // Note: getClientRect() returns physical pixels, but LocalToParentTransformMatrix expects DIPs.