Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Image] Implement 'center' and 'repeat' resizeModes #2581

Merged
merged 12 commits into from
Jun 18, 2019
2 changes: 1 addition & 1 deletion vnext/ReactUWP/Base/UwpReactInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
#include <Views/TextViewManager.h>
#include <Views/VirtualTextViewManager.h>
#include <Views/ViewViewManager.h>
#include <Views/ImageViewManager.h>
#include <Views/Image/ImageViewManager.h>
#include <Views/WebViewManager.h>

// Polyester View Managers // TODO: Move Polyester implementations out of this library and depot
Expand Down
15 changes: 13 additions & 2 deletions vnext/ReactUWP/ReactUWP.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
<GenerateWindowsMetadata>true</GenerateWindowsMetadata>
<GenerateDebugInformation>DebugFull</GenerateDebugInformation>
<AdditionalOptions>-minpdbpathlen:256</AdditionalOptions>
<AdditionalDependencies>dxguid.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<Midl>
<AdditionalIncludeDirectories>$(ProjectDir)ABI\idl</AdditionalIncludeDirectories>
Expand Down Expand Up @@ -189,15 +190,23 @@
<ClInclude Include="Utils\PropertyUtils.h" />
<ClInclude Include="Views\ActivityIndicatorViewManager.h" />
<ClInclude Include="Views\CheckboxViewManager.h" />
<ClInclude Include="Views\cppwinrt\Microsoft.UI.Composition.Effects.BorderEffect.g.h" />
<ClInclude Include="Views\cppwinrt\react.uwp.DynamicAutomationPeer.g.h" />
<ClInclude Include="Views\cppwinrt\winrt\impl\Microsoft.UI.Composition.Effects.0.h" />
<ClInclude Include="Views\cppwinrt\winrt\impl\Microsoft.UI.Composition.Effects.1.h" />
<ClInclude Include="Views\cppwinrt\winrt\impl\Microsoft.UI.Composition.Effects.2.h" />
<ClInclude Include="Views\cppwinrt\winrt\impl\react.uwp.0.h" />
<ClInclude Include="Views\cppwinrt\winrt\impl\react.uwp.1.h" />
<ClInclude Include="Views\cppwinrt\winrt\impl\react.uwp.2.h" />
<ClInclude Include="Views\cppwinrt\winrt\Microsoft.UI.Composition.Effects.h" />
<ClInclude Include="Views\cppwinrt\winrt\react.uwp.h" />
<ClInclude Include="Views\DatePickerViewManager.h" />
<ClInclude Include="Views\ExpressionAnimationStore.h" />
<ClInclude Include="Views\FlyoutViewManager.h" />
<ClInclude Include="Views\ImageViewManager.h" />
<ClInclude Include="Views\Image\BorderEffect.h" />
<ClInclude Include="Views\Image\ImageViewManager.h" />
<ClInclude Include="Views\Image\ReactImage.h" />
<ClInclude Include="Views\Image\ReactImageBrush.h" />
<ClInclude Include="Views\Impl\ScrollViewUWPImplementation.h" />
<ClInclude Include="Views\Impl\SnapPointManagingContentControl.h" />
<ClInclude Include="Views\PickerViewManager.h" />
Expand Down Expand Up @@ -273,7 +282,9 @@
<ClCompile Include="Views\ExpressionAnimationStore.cpp" />
<ClCompile Include="Views\FlyoutViewManager.cpp" />
<ClCompile Include="Views\FrameworkElementViewManager.cpp" />
<ClCompile Include="Views\ImageViewManager.cpp" />
<ClCompile Include="Views\Image\ImageViewManager.cpp" />
<ClCompile Include="Views\Image\ReactImage.cpp" />
<ClCompile Include="Views\Image\ReactImageBrush.cpp" />
<ClCompile Include="Views\Impl\ScrollViewUWPImplementation.cpp" />
<ClCompile Include="Views\Impl\SnapPointManagingContentControl.cpp" />
<ClCompile Include="Views\PickerViewManager.cpp" />
Expand Down
75 changes: 57 additions & 18 deletions vnext/ReactUWP/ReactUWP.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,6 @@
<ClCompile Include="Views\FrameworkElementViewManager.cpp">
<Filter>Views</Filter>
</ClCompile>
<ClCompile Include="Views\ImageViewManager.cpp">
<Filter>Views</Filter>
</ClCompile>
<ClCompile Include="Views\RawTextViewManager.cpp">
<Filter>Views</Filter>
</ClCompile>
Expand Down Expand Up @@ -219,6 +216,15 @@
<ClCompile Include="Views\ScrollContentViewManager.cpp">
<Filter>Views</Filter>
</ClCompile>
<ClCompile Include="Views\Image\ImageViewManager.cpp">
<Filter>Views\Image</Filter>
</ClCompile>
<ClCompile Include="Views\Image\ReactImageBrush.cpp">
<Filter>Views\Image</Filter>
</ClCompile>
<ClCompile Include="Views\Image\ReactImage.cpp">
<Filter>Views\Image</Filter>
</ClCompile>
<ClCompile Include="Views\ExpressionAnimationStore.cpp">
<Filter>Views</Filter>
</ClCompile>
Expand Down Expand Up @@ -311,9 +317,6 @@
<ClInclude Include="ABI\HStringHelper.h">
<Filter>ABI</Filter>
</ClInclude>
<ClInclude Include="Views\ImageViewManager.h">
<Filter>Views</Filter>
</ClInclude>
<ClInclude Include="Views\RawTextViewManager.h">
<Filter>Views</Filter>
</ClInclude>
Expand Down Expand Up @@ -416,18 +419,6 @@
<ClInclude Include="Views\cppwinrt\react.uwp.DynamicAutomationPeer.g.h">
<Filter>Views\cppwinrt</Filter>
</ClInclude>
<ClInclude Include="Views\cppwinrt\winrt\react.uwp.h">
<Filter>Views\cppwinrt</Filter>
</ClInclude>
<ClInclude Include="Views\cppwinrt\winrt\impl\react.uwp.0.h">
<Filter>Views\cppwinrt</Filter>
</ClInclude>
<ClInclude Include="Views\cppwinrt\winrt\impl\react.uwp.1.h">
<Filter>Views\cppwinrt</Filter>
</ClInclude>
<ClInclude Include="Views\cppwinrt\winrt\impl\react.uwp.2.h">
<Filter>Views\cppwinrt</Filter>
</ClInclude>
<ClInclude Include="Views\ViewControl.h">
<Filter>Views</Filter>
</ClInclude>
Expand All @@ -441,6 +432,45 @@
<ClInclude Include="Views\ScrollContentViewManager.h">
<Filter>Views</Filter>
</ClInclude>
<ClInclude Include="Views\Image\ImageViewManager.h">
<Filter>Views\Image</Filter>
</ClInclude>
<ClInclude Include="Views\cppwinrt\winrt\react.uwp.h">
<Filter>Views\cppwinrt\winrt</Filter>
</ClInclude>
<ClInclude Include="Views\cppwinrt\winrt\impl\react.uwp.0.h">
<Filter>Views\cppwinrt\winrt\impl</Filter>
</ClInclude>
<ClInclude Include="Views\cppwinrt\winrt\impl\react.uwp.1.h">
<Filter>Views\cppwinrt\winrt\impl</Filter>
</ClInclude>
<ClInclude Include="Views\cppwinrt\winrt\impl\react.uwp.2.h">
<Filter>Views\cppwinrt\winrt\impl</Filter>
</ClInclude>
<ClInclude Include="Views\cppwinrt\winrt\impl\Microsoft.UI.Composition.Effects.0.h">
<Filter>Views\cppwinrt\winrt\impl</Filter>
</ClInclude>
<ClInclude Include="Views\cppwinrt\winrt\impl\Microsoft.UI.Composition.Effects.1.h">
<Filter>Views\cppwinrt\winrt\impl</Filter>
</ClInclude>
<ClInclude Include="Views\cppwinrt\winrt\impl\Microsoft.UI.Composition.Effects.2.h">
<Filter>Views\cppwinrt\winrt\impl</Filter>
</ClInclude>
<ClInclude Include="Views\cppwinrt\winrt\Microsoft.UI.Composition.Effects.h">
<Filter>Views\cppwinrt\winrt</Filter>
</ClInclude>
<ClInclude Include="Views\cppwinrt\Microsoft.UI.Composition.Effects.BorderEffect.g.h">
<Filter>Views\cppwinrt</Filter>
</ClInclude>
<ClInclude Include="Views\Image\BorderEffect.h">
<Filter>Views\Image</Filter>
</ClInclude>
<ClInclude Include="Views\Image\ReactImageBrush.h">
<Filter>Views\Image</Filter>
</ClInclude>
<ClInclude Include="Views\Image\ReactImage.h">
<Filter>Views\Image</Filter>
</ClInclude>
<ClInclude Include="Views\ExpressionAnimationStore.h">
<Filter>Views</Filter>
</ClInclude>
Expand Down Expand Up @@ -572,6 +602,15 @@
<Filter Include="Views\Impl">
<UniqueIdentifier>{101c2d4a-d343-4771-969f-29af0c9f46b2}</UniqueIdentifier>
</Filter>
<Filter Include="Views\Image">
<UniqueIdentifier>{6d877886-1c5c-45b8-8eae-2e1354cf673e}</UniqueIdentifier>
</Filter>
<Filter Include="Views\cppwinrt\winrt">
<UniqueIdentifier>{e5234a36-e9ee-4ba3-9b11-02e7bd2ca6f0}</UniqueIdentifier>
</Filter>
<Filter Include="Views\cppwinrt\winrt\impl">
<UniqueIdentifier>{24ea7245-f460-4176-82b1-3cac4cd54621}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<MidlRT Include="ABI\idl\Module.idl">
Expand Down
218 changes: 218 additions & 0 deletions vnext/ReactUWP/Views/Image/BorderEffect.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
#pragma once
#include <Views/cppwinrt/Microsoft.UI.Composition.Effects.BorderEffect.g.h>

#include <wrl.h>
#include <d2d1_1.h>
#include <d2d1effects_2.h>
#include <functional>

#include <windows.graphics.effects.interop.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.UI.h>

#define CATCH_RETURN \
Copy link
Member

@chrisglein chrisglein Jun 17, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like this (and probably the DECLARE macros below?) should be in a separate header. #Resolved

return S_OK; \
} catch (...) { \
auto hr = winrt::to_hresult(); \
__analysis_assume(FAILED(hr)); \
return hr;

namespace abi
{
using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::Graphics::Effects;
}

namespace winrt
{
using namespace winrt::Microsoft::UI::Composition::Effects;
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Graphics::Effects;
using namespace winrt::Windows::UI;
}

inline winrt::IGraphicsEffectSource& to_winrt(abi::IGraphicsEffectSource*& instance)
{
return reinterpret_cast<winrt::IGraphicsEffectSource&>(instance);
}

inline winrt::IPropertyValue& to_winrt(abi::IPropertyValue*& instance)
{
return reinterpret_cast<winrt::IPropertyValue&>(instance);
}

namespace winrt::Microsoft::UI::Composition::Effects::implementation
{
// Base class for Win2D-like effect descriptions
class EffectBase :
public winrt::implements<
EffectBase,
abi::IGraphicsEffectD2D1Interop>
{
protected:
// This is a header file so we can't use "using namespace", but we can do this:
typedef winrt::Color UIColor; // Renamed because we use "Color" as a field name
typedef winrt::PropertyValue PropertyValue;
typedef abi::GRAPHICS_EFFECT_PROPERTY_MAPPING PropertyMapping;

public:
// IGraphicsEffect
winrt::hstring Name() { return m_Name; }
void Name(winrt::hstring const& value) { m_Name = value; }

// IGraphicsEffectD2D1Interop
IFACEMETHODIMP GetSourceCount(_Out_ UINT* count) override { *count = 0; return S_OK; }
IFACEMETHODIMP GetPropertyCount(_Out_ UINT* count) override { *count = 0; return S_OK; }

IFACEMETHODIMP GetSource(UINT, _Outptr_ abi::IGraphicsEffectSource**) override
{
return E_INVALIDARG;
}

IFACEMETHODIMP GetProperty(UINT, _Outptr_ abi::IPropertyValue**) override
{
return E_INVALIDARG;
}

IFACEMETHODIMP GetNamedPropertyMapping(LPCWSTR, _Out_ UINT*,
_Out_ abi::GRAPHICS_EFFECT_PROPERTY_MAPPING*) override
{
return E_INVALIDARG;
}

protected:
// Invokes a functor with the pointer to the property factory
static HRESULT UsePropertyFactory(_Outptr_ abi::IPropertyValue** value, std::function<winrt::IInspectable()> const& func) try
{
auto ret = func();
auto propertyValue = ret.as<winrt::IPropertyValue>();
to_winrt(*value) = propertyValue;
CATCH_RETURN;
}

template<UINT32 ComponentCount>
static winrt::IInspectable CreateColor(UIColor color)
{
static_assert(ComponentCount == 3 || ComponentCount == 4, "Unexpected color component count.");
float values[] = { color.R / 255.0f, color.G / 255.0f, color.B / 255.0f, color.A / 255.0f };
return winrt::PropertyValue::CreateSingleArray(reinterpret_cast<std::array<float, ComponentCount>&>(values));
}

// Helpers to implement GetNamedPropertyMapping more succintly
struct NamedProperty
{
const wchar_t* Name; // Compile-time constant
UINT Index; // Property index
abi::GRAPHICS_EFFECT_PROPERTY_MAPPING Mapping;
};

HRESULT GetNamedPropertyMappingImpl(
_In_count_(mappingCount) const NamedProperty* namedProperties,
Copy link
Member

@chrisglein chrisglein Jun 17, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should that be _In_count(namedPropertyCount)? #Resolved

UINT namedPropertyCount,
LPCWSTR name,
_Out_ UINT* index,
_Out_ abi::GRAPHICS_EFFECT_PROPERTY_MAPPING* mapping)
{
for (UINT i = 0; i < namedPropertyCount; ++i)
{
const auto& prop = namedProperties[i];
if (_wcsicmp(name, prop.Name) == 0)
{
*index = prop.Index;
*mapping = prop.Mapping;
return S_OK;
}
}
return E_INVALIDARG;
}

// M_PI requires us to be the first to include math.h, not worth it
static constexpr float k_PI = 3.14159265358979f;
static constexpr float k_DegreesPerRadian = 180.0f / k_PI;

public:
winrt::hstring m_Name;
};

//-----------------------------------------------------------------------------------------------------------------
// Helper macros to make implementation more succint
//-----------------------------------------------------------------------------------------------------------------

#pragma push_macro("DECLARE_D2D_GUID")
#undef DECLARE_D2D_GUID
#define DECLARE_D2D_GUID(Guid) \
IFACEMETHODIMP GetEffectId(_Out_ GUID * id) override { *id = Guid; return S_OK; }

#pragma push_macro("DECLARE_SOURCE")
#undef DECLARE_SOURCE
#define DECLARE_SOURCE(Name) \
winrt::IGraphicsEffectSource m_##Name; \
winrt::IGraphicsEffectSource Name() { return m_##Name; } \
void Name(winrt::IGraphicsEffectSource const& value) { m_##Name = value; }

#pragma push_macro("DECLARE_SINGLE_SOURCE")
#undef DECLARE_SINGLE_SOURCE
#define DECLARE_SINGLE_SOURCE(Name) \
DECLARE_SOURCE(Name) \
IFACEMETHODIMP GetSourceCount(_Out_ UINT * count) override { *count = 1; return S_OK; } \
IFACEMETHODIMP GetSource(UINT index, _Outptr_ abi::IGraphicsEffectSource ** source) override try \
{ \
if (index == 0) to_winrt(*source) = m_##Name; \
else throw winrt::hresult_invalid_argument(); \
CATCH_RETURN; \
}

#pragma push_macro("DECLARE_POD_PROPERTY")
#undef DECLARE_POD_PROPERTY
#define DECLARE_POD_PROPERTY(Name, Type, InitialValue, Condition) \
private: \
Type m_##Name = InitialValue; \
public: \
Type Name() { return m_##Name; } \
void Name(Type const& value) \
{ \
if (!(0, Condition)) { throw winrt::hresult_invalid_argument(); } \
m_##Name = value; \
}

#pragma push_macro("DECLARE_NAMED_PROPERTY_MAPPING")
#undef DECLARE_NAMED_PROPERTY_MAPPING
#define DECLARE_NAMED_PROPERTY_MAPPING(...) \
IFACEMETHODIMP GetNamedPropertyMapping(LPCWSTR name, _Out_ UINT * index, \
_Out_ abi::GRAPHICS_EFFECT_PROPERTY_MAPPING * mapping) override \
{ \
static const NamedProperty s_Properties[] = { __VA_ARGS__ }; \
return GetNamedPropertyMappingImpl(s_Properties, _countof(s_Properties), name, index, mapping); \
}

//-----------------------------------------------------------------------------------------------------------------

class BorderEffect :
public BorderEffectT<BorderEffect, EffectBase>
{
public:
DECLARE_D2D_GUID(CLSID_D2D1Border);
DECLARE_SINGLE_SOURCE(Source);
DECLARE_POD_PROPERTY(ExtendX, winrt::CanvasEdgeBehavior, winrt::CanvasEdgeBehavior::Clamp, true);
DECLARE_POD_PROPERTY(ExtendY, winrt::CanvasEdgeBehavior, winrt::CanvasEdgeBehavior::Clamp, true);
DECLARE_NAMED_PROPERTY_MAPPING(
{ L"ExtendX", D2D1_BORDER_PROP_EDGE_MODE_X, PropertyMapping::GRAPHICS_EFFECT_PROPERTY_MAPPING_DIRECT },
{ L"ExtendY", D2D1_BORDER_PROP_EDGE_MODE_Y, PropertyMapping::GRAPHICS_EFFECT_PROPERTY_MAPPING_DIRECT });

public:
IFACEMETHODIMP GetPropertyCount(_Out_ UINT* count) override { *count = 2; return S_OK; }

IFACEMETHODIMP GetProperty(UINT index, _Outptr_ abi::IPropertyValue** value) override
{
return UsePropertyFactory(value, [=]()
{
switch (index)
{
case D2D1_BORDER_PROP_EDGE_MODE_X: return winrt::PropertyValue::CreateUInt32((UINT32)m_ExtendX);
case D2D1_BORDER_PROP_EDGE_MODE_Y: return winrt::PropertyValue::CreateUInt32((UINT32)m_ExtendY);
default: throw winrt::hresult_invalid_argument();
}
});
}
};
}
Loading