Skip to content

Commit

Permalink
Expose ImageProps from ImageComponentView's and add ImageSource type (#…
Browse files Browse the repository at this point in the history
…13206)

* Expose ImageProps from ImageComponentView's and add ImageSource type

* Change files

* fix

* fix

* Move ImageProps property to ViewProps property

* update lock file

* desktop fix
  • Loading branch information
acoates-ms authored May 13, 2024
1 parent 7abc1eb commit 8f366c5
Show file tree
Hide file tree
Showing 34 changed files with 592 additions and 666 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Expose ImageProps from ImageComponentView's and add ImageSource type",
"packageName": "react-native-windows",
"email": "30809111+acoates-ms@users.noreply.github.com",
"dependentChangeType": "patch"
}
4 changes: 4 additions & 0 deletions vnext/Microsoft.ReactNative.Cxx/JSValueComposition.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ inline void WriteValue(IJSValueWriter const &writer, const Color &value) noexcep
winrt::Microsoft::ReactNative::Color::WriteValue(writer, value);
}

inline void ReadValue(IJSValueReader const &reader, ImageSource &value) noexcept {
value = winrt::Microsoft::ReactNative::ImageSource::ReadValue(reader);
}

} // namespace winrt::Microsoft::ReactNative

#endif // MICROSOFT_REACTNATIVE_JSVALUECOMPOSITION
15 changes: 8 additions & 7 deletions vnext/Microsoft.ReactNative/CompositionComponentView.idl
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ namespace Microsoft.ReactNative.Composition
[experimental]
[webhosthidden]
[default_interface]
unsealed runtimeclass SwitchComponentView : ComponentView {
unsealed runtimeclass SwitchComponentView : ViewComponentView {
};

[experimental]
Expand All @@ -99,31 +99,32 @@ namespace Microsoft.ReactNative.Composition
[experimental]
[webhosthidden]
[default_interface]
unsealed runtimeclass ActivityIndicatorComponentView : ComponentView {
unsealed runtimeclass ActivityIndicatorComponentView : ViewComponentView {
};

[experimental]
[webhosthidden]
[default_interface]
unsealed runtimeclass WindowsModalHostComponentView : ComponentView {
unsealed runtimeclass WindowsModalHostComponentView : ViewComponentView {
};

[experimental]
[webhosthidden]
[default_interface]
unsealed runtimeclass ImageComponentView : ComponentView {
unsealed runtimeclass ImageComponentView : ViewComponentView {
Microsoft.ReactNative.ImageProps ViewProps { get; };
};

[experimental]
[webhosthidden]
[default_interface]
unsealed runtimeclass ParagraphComponentView : ComponentView {
unsealed runtimeclass ParagraphComponentView : ViewComponentView {
};

[experimental]
[webhosthidden]
[default_interface]
unsealed runtimeclass ScrollViewComponentView : ComponentView {
unsealed runtimeclass ScrollViewComponentView : ViewComponentView {
};

[experimental]
Expand All @@ -135,7 +136,7 @@ namespace Microsoft.ReactNative.Composition
[experimental]
[webhosthidden]
[default_interface]
unsealed runtimeclass WindowsTextInputComponentView : ComponentView {
unsealed runtimeclass WindowsTextInputComponentView : ViewComponentView {
};

} // namespace Microsoft.ReactNative
1 change: 1 addition & 0 deletions vnext/Microsoft.ReactNative/CompositionRootView.idl
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ namespace Microsoft.ReactNative
Microsoft.ReactNative.Composition.ICustomResourceLoader Resources;

Microsoft.ReactNative.Composition.Theme Theme { get; };
Int64 RootTag { get; };

#ifdef USE_WINUI3
Microsoft.UI.Content.ContentIsland Island { get; };
Expand Down
4 changes: 4 additions & 0 deletions vnext/Microsoft.ReactNative/CompositionUIService.idl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the MIT License.

import "ReactInstanceSettings.idl";
import "ComponentView.idl";

#include "DocString.h"

Expand All @@ -22,5 +23,8 @@ namespace Microsoft.ReactNative.Composition
"Gets the Compositor used by this ReactNative instance.")
static Microsoft.UI.Composition.Compositor GetCompositor(Microsoft.ReactNative.IReactPropertyBag properties);

DOC_STRING("Gets the ComponentView from a react tag.")
static Microsoft.ReactNative.ComponentView ComponentFromReactTag(Microsoft.ReactNative.IReactContext context, Int64 reactTag);

}
} // namespace Microsoft.ReactNative.Composition
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ facebook::react::Props::Shared AbiViewComponentDescriptor::cloneProps(
// auto shadowNodeProps = std::make_shared<ShadowNodeT::Props>(context, rawProps, props);
auto shadowNodeProps = std::make_shared<AbiViewProps>(
context, props ? static_cast<AbiViewProps const &>(*props) : *ShadowNodeT::defaultSharedProps(), rawProps);
auto viewProps = winrt::make<winrt::Microsoft::ReactNative::implementation::UserViewProps>(shadowNodeProps);
auto viewProps =
winrt::make<winrt::Microsoft::ReactNative::implementation::ViewProps>(shadowNodeProps, false /*holdRef*/);
auto userProps =
winrt::get_self<winrt::Microsoft::ReactNative::Composition::ReactCompositionViewComponentBuilder>(m_builder)
->CreateProps(viewProps);
Expand Down
125 changes: 106 additions & 19 deletions vnext/Microsoft.ReactNative/Fabric/AbiViewProps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@

#include <Fabric/Composition/Theme.h>
#include <JSValueReader.h>
#include <react/renderer/components/image/ImageProps.h>
#include <winrt/Microsoft.ReactNative.h>
#include <winrt/Windows.Foundation.h>

#if __has_include("Color.g.cpp")
#include "Color.g.cpp"
#endif
#include "ImageSource.g.cpp"

namespace Microsoft::ReactNative {

Expand All @@ -21,24 +23,24 @@ AbiViewProps::AbiViewProps(
: facebook::react::ViewProps(context, sourceProps, rawProps) {}

AbiViewProps::~AbiViewProps() {
if (m_userProps) {
winrt::get_self<winrt::Microsoft::ReactNative::implementation::UserViewProps>(m_userProps)->Disconnect();
if (m_innerProps) {
winrt::get_self<winrt::Microsoft::ReactNative::implementation::ViewProps>(m_innerProps)->Disconnect();
}
}

void AbiViewProps::SetUserProps(
winrt::Microsoft::ReactNative::IComponentProps componentProps,
winrt::Microsoft::ReactNative::ViewProps userProps) noexcept {
m_componentProps = componentProps;
winrt::Microsoft::ReactNative::IComponentProps userProps,
winrt::Microsoft::ReactNative::ViewProps innerProps) noexcept {
m_userProps = userProps;
m_innerProps = innerProps;
}

winrt::Microsoft::ReactNative::IComponentProps AbiViewProps::UserProps() const noexcept {
return m_componentProps;
return m_userProps;
}

winrt::Microsoft::ReactNative::ViewProps AbiViewProps::ViewProps() const noexcept {
return m_userProps;
return m_innerProps;
}

} // namespace Microsoft::ReactNative
Expand Down Expand Up @@ -124,29 +126,114 @@ winrt::Microsoft::ReactNative::Color Color::White() noexcept {
return winrt::make<Color>(facebook::react::whiteColor());
}

UserViewProps::UserViewProps(std::shared_ptr<::Microsoft::ReactNative::AbiViewProps const> viewProps) noexcept
: m_viewProps(viewProps.get()) {}
ImageSource::ImageSource(const facebook::react::ImageSource &imageSource) : m_imageSource(imageSource) {}

ImageSourceType ImageSource::Type() noexcept {
static_assert(
winrt::Microsoft::ReactNative::ImageSourceType::Invalid ==
static_cast<winrt::Microsoft::ReactNative::ImageSourceType>(facebook::react::ImageSource::Type::Invalid));
static_assert(
winrt::Microsoft::ReactNative::ImageSourceType::Remote ==
static_cast<winrt::Microsoft::ReactNative::ImageSourceType>(facebook::react::ImageSource::Type::Remote));
static_assert(
winrt::Microsoft::ReactNative::ImageSourceType::Local ==
static_cast<winrt::Microsoft::ReactNative::ImageSourceType>(facebook::react::ImageSource::Type::Local));
return static_cast<winrt::Microsoft::ReactNative::ImageSourceType>(m_imageSource.type);
}

winrt::hstring ImageSource::Uri() noexcept {
return winrt::to_hstring(m_imageSource.uri);
}

void UserViewProps::Disconnect() noexcept {
winrt::hstring ImageSource::Bundle() noexcept {
return winrt::to_hstring(m_imageSource.bundle);
}

float ImageSource::Scale() noexcept {
return m_imageSource.scale;
}

winrt::Windows::Foundation::Size ImageSource::Size() noexcept {
return {m_imageSource.size.width, m_imageSource.size.height};
}

winrt::Microsoft::ReactNative::ImageSource ImageSource::ReadValue(
const winrt::Microsoft::ReactNative::IJSValueReader &reader) noexcept {
facebook::react::ImageSource imageSource;
switch (reader.ValueType()) {
case JSValueType::String: {
imageSource.type = facebook::react::ImageSource::Type::Remote;
imageSource.uri = winrt::to_string(reader.GetString());
break;
}
case JSValueType::Object: {
imageSource.type = facebook::react::ImageSource::Type::Remote;

winrt::hstring propertyName;
while (reader.GetNextObjectProperty(/*out*/ propertyName)) {
if (propertyName == L"__packager_asset") {
imageSource.type = facebook::react::ImageSource::Type::Local;
} else if (propertyName == L"width") {
imageSource.size.width = static_cast<float>(reader.GetDouble());
} else if (propertyName == L"height") {
imageSource.size.height = static_cast<float>(reader.GetDouble());
} else if (propertyName == L"scale") {
imageSource.scale = static_cast<float>(reader.GetDouble());
} else if (propertyName == L"uri") {
imageSource.uri = winrt::to_string(reader.GetString());
} else if (propertyName == L"url") {
imageSource.uri = winrt::to_string(reader.GetString());
} else if (propertyName == L"bundle") {
imageSource.bundle = winrt::to_string(reader.GetString());
imageSource.type = facebook::react::ImageSource::Type::Local;
}
}
break;
}
default: {
imageSource.type = facebook::react::ImageSource::Type::Invalid;
break;
}
}
return winrt::make<ImageSource>(imageSource);
}

ViewProps::ViewProps(facebook::react::SharedViewProps props, bool holdRef) noexcept
: m_props(holdRef ? props : nullptr), m_viewProps(static_cast<const facebook::react::ViewProps *>(props.get())) {}

void ViewProps::Disconnect() noexcept {
m_viewProps = nullptr;
}

float UserViewProps::Opacity() noexcept {
float ViewProps::Opacity() noexcept {
return m_viewProps ? m_viewProps->opacity : 1.0f;
}

winrt::Microsoft::ReactNative::Color UserViewProps::BackgroundColor() noexcept {
winrt::Microsoft::ReactNative::Color ViewProps::BackgroundColor() noexcept {
return winrt::make<Color>(m_viewProps ? m_viewProps->backgroundColor : facebook::react::clearColor());
}

ViewProps::ViewProps(facebook::react::SharedViewProps props) noexcept : m_props(props) {}
winrt::hstring ViewProps::TestId() noexcept {
return m_viewProps ? winrt::to_hstring(m_viewProps->testId) : winrt::hstring{};
}

float ViewProps::Opacity() noexcept {
return m_props->opacity;
winrt::hstring ViewProps::AccessibilityLabel() noexcept {
return m_viewProps ? winrt::to_hstring(m_viewProps->accessibilityLabel) : winrt::hstring{};
}

winrt::Microsoft::ReactNative::Color ViewProps::BackgroundColor() noexcept {
return winrt::make<Color>(m_props->backgroundColor);
ImageProps::ImageProps(facebook::react::SharedViewProps props) noexcept : Super(props) {}

winrt::Windows::Foundation::Collections::IVectorView<winrt::Microsoft::ReactNative::ImageSource>
ImageProps::Sources() noexcept {
winrt::Windows::Foundation::Collections::IVector<winrt::Microsoft::ReactNative::ImageSource> sources{
winrt::single_threaded_vector<winrt::Microsoft::ReactNative::ImageSource>()};
const auto imageProps = std::static_pointer_cast<const facebook::react::ImageProps>(m_props);

for (const auto &source : imageProps->sources) {
sources.Append(winrt::make<ImageSource>(source));
}

return sources.GetView();
}

} // namespace winrt::Microsoft::ReactNative::implementation
58 changes: 45 additions & 13 deletions vnext/Microsoft.ReactNative/Fabric/AbiViewProps.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@
#pragma once

#include "Color.g.h"
#include "ImageProps.g.h"
#include "ImageSource.g.h"
#include "ViewProps.g.h"

#include <react/renderer/components/view/ViewProps.h>
#include <react/renderer/imagemanager/primitives.h>
#include "winrt/Microsoft.ReactNative.Composition.Experimental.h"
#include "winrt/Microsoft.ReactNative.h"

Expand All @@ -22,14 +25,14 @@ class AbiViewProps final : public facebook::react::ViewProps {
~AbiViewProps();

void SetUserProps(
winrt::Microsoft::ReactNative::IComponentProps componentProps,
winrt::Microsoft::ReactNative::ViewProps userProps) noexcept;
winrt::Microsoft::ReactNative::IComponentProps userProps,
winrt::Microsoft::ReactNative::ViewProps innerProps) noexcept;
winrt::Microsoft::ReactNative::IComponentProps UserProps() const noexcept;
winrt::Microsoft::ReactNative::ViewProps ViewProps() const noexcept;

private:
winrt::Microsoft::ReactNative::IComponentProps m_componentProps{nullptr};
winrt::Microsoft::ReactNative::ViewProps m_userProps{nullptr};
winrt::Microsoft::ReactNative::IComponentProps m_userProps{nullptr};
winrt::Microsoft::ReactNative::ViewProps m_innerProps{nullptr};
};

} // namespace Microsoft::ReactNative
Expand Down Expand Up @@ -60,33 +63,62 @@ struct Color : ColorT<Color, Composition::Experimental::IInternalColor> {
facebook::react::SharedColor m_color;
};

struct UserViewProps : ViewPropsT<UserViewProps> {
UserViewProps(std::shared_ptr<::Microsoft::ReactNative::AbiViewProps const> viewProps) noexcept;
struct ImageSource : ImageSourceT<ImageSource> {
ImageSource(const facebook::react::ImageSource &imageSource);

float Opacity() noexcept;
winrt::Microsoft::ReactNative::Color BackgroundColor() noexcept;
ImageSourceType Type() noexcept;
winrt::hstring Uri() noexcept;
winrt::hstring Bundle() noexcept;
float Scale() noexcept;
winrt::Windows::Foundation::Size Size() noexcept;

void Disconnect() noexcept;
static winrt::Microsoft::ReactNative::ImageSource ReadValue(
const winrt::Microsoft::ReactNative::IJSValueReader &reader) noexcept;

static void WriteValue(
const winrt::Microsoft::ReactNative::IJSValueWriter &writer,
const winrt::Microsoft::ReactNative::ImageSource &value) noexcept;

private:
// Use a raw pointer here to avoid a ref cycle with AbiViewProps. ~AbiViewProps will clear this pointer
::Microsoft::ReactNative::AbiViewProps const *m_viewProps{nullptr};
const facebook::react::ImageSource m_imageSource;
};

/**
* When providing a external ViewProps object on a normal ComponentView, ViewProps will hold a reference to the internal
* facebook::react::ViewProps object since the ComponentView could release the object at any time. However, when
* providing a ViewProps object on a custom ComponentView that has a custom app provided props, the AbiViewProps object
* will already be holding a reference to this object, so we only hold onto a weak reference.
*/
struct ViewProps : ViewPropsT<ViewProps> {
ViewProps(facebook::react::SharedViewProps props) noexcept;
ViewProps(facebook::react::SharedViewProps props, bool holdRef = true) noexcept;

// Notification when the owning AbiViewProps is going away.
void Disconnect() noexcept;

float Opacity() noexcept;
winrt::Microsoft::ReactNative::Color BackgroundColor() noexcept;
winrt::hstring TestId() noexcept;
winrt::hstring AccessibilityLabel() noexcept;

private:
protected:
facebook::react::SharedViewProps m_props;

// Use a raw pointer here to avoid a ref cycle with AbiViewProps. ~AbiViewProps will clear this pointer
facebook::react::ViewProps const *m_viewProps{nullptr};
};

struct ImageProps : ImagePropsT<ImageProps, ViewProps> {
using Super = ImagePropsT<ImageProps, ViewProps>;
ImageProps(facebook::react::SharedViewProps props) noexcept;

winrt::Windows::Foundation::Collections::IVectorView<winrt::Microsoft::ReactNative::ImageSource> Sources() noexcept;
};

} // namespace winrt::Microsoft::ReactNative::implementation

namespace winrt::Microsoft::ReactNative::factory_implementation {

struct Color : ColorT<Color, implementation::Color> {};
struct ImageSource : ImageSourceT<ImageSource, implementation::ImageSource> {};

} // namespace winrt::Microsoft::ReactNative::factory_implementation
Loading

0 comments on commit 8f366c5

Please sign in to comment.