Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<WindowsXamlEnableOverview>true</WindowsXamlEnableOverview>
<AppxGeneratePrisForPortableLibrariesEnabled>false</AppxGeneratePrisForPortableLibrariesEnabled>
<LangVersion>7.3</LangVersion>
<RunAutolinkCheck>false</RunAutolinkCheck>
</PropertyGroup>
<PropertyGroup Label="NuGet">
<AssetTargetFallback>$(AssetTargetFallback);native</AssetTargetFallback>
Expand Down
60 changes: 56 additions & 4 deletions packages/e2e-test-app/windows/RNTesterApp/packages.lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,19 @@
"type": "Direct",
"requested": "[0.11.0-ms.6, )",
"resolved": "0.11.0-ms.6",
"contentHash": "7KGeDHh4QR4ua5+aSNAfuhj1sF2PBJbTHJ9m520xo1GZZRW4cxJlyNDNjW5t/sFGeHWw/Uhs7ZrWE2maL9BOEw=="
"contentHash": "WAVLsSZBV4p/3hNC3W67su7xu3f/ZMSKxu0ON7g2GaKRbkJmH0Qyif1IlzcJwtvR48kuOdfgPu7Bgtz3AY+gqg=="
},
"XamlTreeDump": {
"type": "Direct",
"requested": "[1.0.9, )",
"resolved": "1.0.9",
"contentHash": "rvh/RZghhSG28PDL1dw56nTZRN0/ViV2TIja/ykU9FHn0gtM8pwtgD8Ebo1nobu0QnSjn8Cg6Ncu39VV19rkrw=="
},
"boost": {
"type": "Transitive",
"resolved": "1.76.0",
"contentHash": "p+w3YvNdXL8Cu9Fzrmexssu0tZbWxuf6ywsQqHjDlKFE5ojXHof1HIyMC3zDLfLnh80dIeFcEUAuR2Asg/XHRA=="
},
"Microsoft.Net.Native.Compiler": {
"type": "Transitive",
"resolved": "2.2.7-rel-27913-00",
Expand All @@ -58,6 +63,16 @@
"resolved": "2.1.0",
"contentHash": "ok+RPAtESz/9MUXeIEz6Lv5XAGQsaNmEYXMsgVALj4D7kqC8gveKWXWXbufLySR2fWrwZf8smyN5RmHu0e4BHA=="
},
"Microsoft.Windows.CppWinRT": {
"type": "Transitive",
"resolved": "2.0.211028.7",
"contentHash": "JBGI0c3WLoU6aYJRy9Qo0MLDQfObEp+d4nrhR95iyzf7+HOgjRunHDp/6eGFREd7xq3OI1mll9ecJrMfzBvlyg=="
},
"Microsoft.Windows.SDK.BuildTools": {
"type": "Transitive",
"resolved": "10.0.22000.194",
"contentHash": "4L0P3zqut466SIqT3VBeLTNUQTxCBDOrTRymRuROCRJKazcK7ibLz9yAO1nKWRt50ttCj39oAa2Iuz9ZTDmLlg=="
},
"NETStandard.Library": {
"type": "Transitive",
"resolved": "2.0.3",
Expand Down Expand Up @@ -134,28 +149,65 @@
"contentHash": "qF6RRZKaflI+LR1YODNyWYjq5YoX8IJ2wx5y8O+AW2xO+1t/Q6Mm+jQ38zJbWnmXbrcOqUYofn7Y3/KC6lTLBQ=="
},
"automationchannel": {
"type": "Project",
"dependencies": {
"Microsoft.ReactNative": "1.0.0",
"Microsoft.UI.Xaml": "2.7.0",
"Microsoft.Windows.CppWinRT": "2.0.211028.7"
}
},
"common": {
"type": "Project"
},
"microsoft.reactnative": {
"fmt": {
"type": "Project"
},
"folly": {
"type": "Project",
"dependencies": {
"boost": "1.76.0",
"fmt": "1.0.0"
}
},
"microsoft.reactnative": {
"type": "Project",
"dependencies": {
"Common": "1.0.0",
"Folly": "1.0.0",
"Microsoft.UI.Xaml": "2.7.0",
"Microsoft.Windows.CppWinRT": "2.0.211028.7",
"Microsoft.Windows.SDK.BuildTools": "10.0.22000.194",
"ReactCommon": "1.0.0",
"ReactNative.Hermes.Windows": "0.11.0-ms.6",
"boost": "1.76.0"
}
},
"microsoft.reactnative.managed": {
"type": "Project",
"dependencies": {
"Microsoft.NETCore.UniversalWindowsPlatform": "6.2.9",
"Microsoft.ReactNative": "1.0.0"
}
},
"reactcommon": {
"type": "Project",
"dependencies": {
"Folly": "1.0.0",
"boost": "1.76.0"
}
},
"reactnativepicker": {
"type": "Project",
"dependencies": {
"Microsoft.ReactNative": "1.0.0"
"Microsoft.ReactNative": "1.0.0",
"Microsoft.UI.Xaml": "2.7.0"
}
},
"reactnativexaml": {
"type": "Project",
"dependencies": {
"Microsoft.ReactNative": "1.0.0"
"Microsoft.ReactNative": "1.0.0",
"Microsoft.UI.Xaml": "2.7.0"
}
}
},
Expand Down
4 changes: 2 additions & 2 deletions vnext/Microsoft.ReactNative.Managed/packages.lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
"Microsoft.NETCore.Platforms": {
"type": "Transitive",
"resolved": "2.1.0",
"contentHash": "GmkKfoyerqmsHMn7OZj0AKpcBabD+GaafqphvX2Mw406IwiJRy1pKcKqdCfKJfYmkRyJ6+e+RaUylgdJoDa1jQ=="
"contentHash": "ok+RPAtESz/9MUXeIEz6Lv5XAGQsaNmEYXMsgVALj4D7kqC8gveKWXWXbufLySR2fWrwZf8smyN5RmHu0e4BHA=="
},
"Microsoft.SourceLink.Common": {
"type": "Transitive",
Expand All @@ -83,7 +83,7 @@
"NETStandard.Library": {
"type": "Transitive",
"resolved": "2.0.3",
"contentHash": "548M6mnBSJWxsIlkQHfbzoYxpiYFXZZSL00p4GHYv8PkiqFBnnT68mW5mGEsA/ch9fDO9GkPgkFQpWiXZN7mAQ==",
"contentHash": "st47PosZSHrjECdjeIzZQbzivYBJFv6P2nv4cj2ypdI204DO+vZ7l5raGMiX4eXMJ53RfOIg+/s4DHVZ54Nu2A==",
"dependencies": {
"Microsoft.NETCore.Platforms": "1.1.0"
}
Expand Down
151 changes: 145 additions & 6 deletions vnext/Microsoft.ReactNative/ABIViewManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,124 @@
#include <Views/ShadowNodeBase.h>
#include "ReactHost/MsoUtils.h"

#include "NativeMeasuringPanel.g.h"
#include <Modules/NativeUIManager.h>
#include <Modules/PaperUIManagerModule.h>
#include <cdebug.h>

namespace winrt::Microsoft::ReactNative::implementation {
struct NativeMeasuringPanel : NativeMeasuringPanelT<NativeMeasuringPanel> {
using super = xaml::Controls::Grid;
NativeMeasuringPanel() = default;

static YGSize
SelfMeasureFunc(YGNodeRef node, float width, YGMeasureMode widthMode, float height, YGMeasureMode heightMode) {
auto context = reinterpret_cast<::Microsoft::ReactNative::YogaContext *>(YGNodeGetContext(node));

// TODO: VEC context != nullptr, DefaultYogaSelfMeasureFunc expects a context.

auto view = context->view;
auto element = view.as<xaml::UIElement>();

float constrainToWidth =
widthMode == YGMeasureMode::YGMeasureModeUndefined ? std::numeric_limits<float>::max() : width;
float constrainToHeight =
heightMode == YGMeasureMode::YGMeasureModeUndefined ? std::numeric_limits<float>::max() : height;
winrt::Windows::Foundation::Size availableSpace(constrainToWidth, constrainToHeight);
element.Measure(availableSpace);

YGSize desiredSize{element.DesiredSize().Width, element.DesiredSize().Height};

return desiredSize;
}

static implementation::NativeMeasuringPanel* GetFromWrapped(::Microsoft::ReactNative::XamlView view)
{
if (auto grid = view.try_as<xaml::Controls::Grid>()) {
if (grid.Children().Size() == 1) {
if (auto nmp = grid.Children().GetAt(0).try_as<winrt::Microsoft::ReactNative::NativeMeasuringPanel>()) {
return winrt::get_self<implementation::NativeMeasuringPanel>(nmp);
}
}
}
return nullptr;
}

Size MeasureOverride(Size const &available) {
if (Children().Size() == 0) {
return {};
}
auto child = Children().GetAt(0).as<xaml::FrameworkElement>();

const auto ret = NativeMeasuringPanelT<NativeMeasuringPanel>::MeasureOverride(available);
const bool wasMeasuring = m_isMeasuring;
if (ret != m_last && (ret.Width * ret.Height) != 0 && !m_isMeasuring) {
m_isMeasuring = true;
m_last = ret;
if (auto nativeParent = this->Parent()) {
nativeParent.ClearValue(xaml::FrameworkElement::WidthProperty());
nativeParent.ClearValue(xaml::FrameworkElement::HeightProperty());
}

auto x = 0;
auto &ctx = m_shadowNode->GetViewManager()->GetReactContext();
if (auto nativeUIManager = ::Microsoft::ReactNative::GetNativeUIManager(ctx).lock()) {
nativeUIManager->DirtyYogaNode(m_shadowNode->m_tag);
nativeUIManager->ensureInBatch();
nativeUIManager->onBatchComplete();
}
m_isMeasuring = false;
}
cdebug << L"MeasureOverride " << winrt::get_class_name(child).c_str() << L" available (" << available.Width << L", "
<< available.Height << L")" << L" (" << m_last.Width << L", " << m_last.Height << L")" << L" measuring = "
<< wasMeasuring << L"\n\n";
return ret;
}

Size m_last{};
::Microsoft::ReactNative::ShadowNodeBase *m_shadowNode{nullptr};
bool m_isMeasuring{false};
};
} // namespace winrt::Microsoft::ReactNative::implementation

namespace winrt::Microsoft::ReactNative::factory_implementation {
struct NativeMeasuringPanel : NativeMeasuringPanelT<NativeMeasuringPanel, implementation::NativeMeasuringPanel> {};
} // namespace winrt::Microsoft::ReactNative::factory_implementation

#if __has_include("NativeMeasuringPanel.g.cpp")
#include "NativeMeasuringPanel.g.cpp"
#endif


namespace winrt::Microsoft::ReactNative {


xaml::DependencyObject WrapNativeView(xaml::DependencyObject created) {
auto panel = NativeMeasuringPanel();
panel.Children().Append(created.as<xaml::UIElement>());

auto grid = xaml::Controls::Grid();
grid.Children().Append(panel);
#ifdef DEBUG
panel.Name(L"Measuring panel for native view");
grid.Name(L"Wrapped native view");
#endif
return grid;
}

xaml::DependencyObject UnwrapNativeView(xaml::DependencyObject o) {
if (auto grid = o.try_as<xaml::Controls::Grid>()) {
if (grid.Children().Size() == 1) {
if (auto panel = grid.Children().GetAt(0).try_as<NativeMeasuringPanel>()) {
if (panel.Children().Size() == 1) {
return panel.Children().GetAt(0);
}
}
}
}
return nullptr;
}

class ABIShadowNode : public ::Microsoft::ReactNative::ShadowNodeBase {
using Super = ShadowNodeBase;

Expand All @@ -24,6 +140,14 @@ class ABIShadowNode : public ::Microsoft::ReactNative::ShadowNodeBase {
return m_needsForceLayout;
}

void createView(const winrt::Microsoft::ReactNative::JSValueObject &props) override {
Super::createView(props);

auto nmp = implementation::NativeMeasuringPanel::GetFromWrapped(m_view);

nmp->m_shadowNode = this;
}

private:
bool m_needsForceLayout;
};
Expand Down Expand Up @@ -55,15 +179,21 @@ const wchar_t *ABIViewManager::GetName() const {
return m_name.c_str();
}



xaml::DependencyObject ABIViewManager::CreateViewCore(
int64_t,
const winrt::Microsoft::ReactNative::JSValueObject &props) {
xaml::DependencyObject created{nullptr};
if (auto viewCreateProps = m_viewManager.try_as<IViewManagerCreateWithProperties>()) {
auto view = viewCreateProps.CreateViewWithProperties(
MakeJSValueTreeReader(winrt::Microsoft::ReactNative::JSValue(props.Copy())));
return view.as<xaml::DependencyObject>();
created = view.as<xaml::DependencyObject>();
} else {
created = m_viewManager.CreateView();
}
return m_viewManager.CreateView();

return WrapNativeView(created);
}

void ABIViewManager::GetExportedViewConstants(const winrt::Microsoft::ReactNative::IJSValueWriter &writer) const {
Expand Down Expand Up @@ -118,7 +248,7 @@ void ABIViewManager::UpdateProperties(
}

if (m_viewManagerWithNativeProperties) {
auto view = nodeToUpdate->GetView().as<xaml::FrameworkElement>();
auto view = UnwrapNativeView(nodeToUpdate->GetView()).as<xaml::FrameworkElement>();

if (props.size() > 0) {
m_viewManagerWithNativeProperties.UpdateProperties(
Expand Down Expand Up @@ -178,10 +308,19 @@ void ABIViewManager::GetExportedCustomDirectEventTypeConstants(
}

void ABIViewManager::AddView(const xaml::DependencyObject &parent, const xaml::DependencyObject &child, int64_t index) {
auto parentView = UnwrapNativeView(parent);
auto childView = UnwrapNativeView(child);
if (!parentView || !childView) {
assert(false && "failed to unwrap a native view");
return;
}
auto childNMP = child.as<xaml::Controls::Grid>().Children().GetAt(0).as<NativeMeasuringPanel>();
childNMP.Children().Clear(); // need to unparent the real element before we parent it

if (m_viewManagerWithChildren) {
m_viewManagerWithChildren.AddView(parent.as<xaml::FrameworkElement>(), child.as<xaml::UIElement>(), index);
m_viewManagerWithChildren.AddView(parentView.as<xaml::FrameworkElement>(), childView.as<xaml::UIElement>(), index);
} else {
Super::AddView(parent, child, index);
Super::AddView(parentView, childView, index);
}
}

Expand Down Expand Up @@ -215,7 +354,7 @@ void ABIViewManager::ReplaceChild(

YGMeasureFunc ABIViewManager::GetYogaCustomMeasureFunc() const {
if (m_viewManagerRequiresNativeLayout && m_viewManagerRequiresNativeLayout.RequiresNativeLayout()) {
return ::Microsoft::ReactNative::DefaultYogaSelfMeasureFunc;
return implementation::NativeMeasuringPanel::SelfMeasureFunc;
} else {
return nullptr;
}
Expand Down
17 changes: 17 additions & 0 deletions vnext/Microsoft.ReactNative/Views/ViewManagerBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,19 @@ void ViewManagerBase::NotifyUnimplementedProperty(
#endif // DEBUG
}

static xaml::DependencyObject UnwrapNativeView(xaml::DependencyObject o) {
if (auto grid = o.try_as<xaml::Controls::Grid>()) {
if (grid.Children().Size() == 1) {
if (auto panel = grid.Children().GetAt(0).try_as<winrt::Microsoft::ReactNative::NativeMeasuringPanel>()) {
if (panel.Children().Size() == 1) {
return panel.Children().GetAt(0);
}
}
}
}
return nullptr;
}

void ViewManagerBase::SetLayoutProps(
ShadowNodeBase &nodeToUpdate,
const XamlView &viewToUpdate,
Expand All @@ -343,6 +356,10 @@ void ViewManagerBase::SetLayoutProps(
}
}

if (auto unwrapped = UnwrapNativeView(viewToUpdate)) {
auto cn = winrt::get_class_name(unwrapped);
}

auto element = viewToUpdate.as<xaml::UIElement>();
if (element == nullptr) {
// TODO: Assert
Expand Down
8 changes: 8 additions & 0 deletions vnext/Microsoft.ReactNative/Views/cppwinrt/ViewPanel.idl
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,12 @@ namespace Microsoft.ReactNative

ViewPanel GetPanel();
}


[default_interface]
[webhosthidden]
runtimeclass NativeMeasuringPanel : XAML_NAMESPACE.Controls.Grid {
NativeMeasuringPanel();
}

}