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

Add logic to support nested Svgs #23

Merged
merged 3 commits into from
Apr 8, 2021
Merged
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
8 changes: 7 additions & 1 deletion example/examples/Polygon.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import React from 'react';
import {Example} from '../components/Example';
import {Page} from '../components/Page';
import {Svg, G, Polygon} from 'react-native-svg';
import {Svg, G, Polygon, Path} from 'react-native-svg';

export const PolygonPage: React.FunctionComponent<{}> = () => {
return (
Expand Down Expand Up @@ -49,6 +49,12 @@ export const PolygonPage: React.FunctionComponent<{}> = () => {
strokeWidth="5"
/>
</G>
<Svg width="18" height="17" viewBox="0 0 18 17">
<G fill="red" fillRule="evenodd">
<Path d="M3.304 15.294h10.993V4.284H3.304v11.01zM16.87 2.997H.732c-.403 0-.732.29-.732.644 0 .353.33.643.732.643H1.99v11.652c0 .354.296.644.657.644H14.91c.008 0 .015-.005.022-.005.008 0 .014.005.022.005.363 0 .658-.29.658-.644V4.284h1.258c.402 0 .731-.29.731-.643 0-.353-.329-.644-.731-.644z" />
<Path d="M7.355 13.28V6.763a.558.558 0 0 0-.562-.55.558.558 0 0 0-.563.55v6.519c0 .301.253.55.563.55a.558.558 0 0 0 .562-.55M11.442 13.28V6.763a.558.558 0 0 0-.562-.55.558.558 0 0 0-.563.55v6.519c0 .301.253.55.563.55a.558.558 0 0 0 .562-.55M12.737 1.267C12.327.498 11.435.014 10.574.004 10.07-.002 9.545 0 9.264.002 8.624 0 7.532-.002 7.028.004c-.861.01-1.752.494-2.163 1.263-.289.543-.321.85-.343 1.143h1.209c.178-1.212 1.03-1.196 1.759-1.212.056-.002 1.134-.003 1.782-.004.293.001.784.002.84.004.728.016 1.58 0 1.76 1.212h1.208c-.022-.293-.054-.6-.343-1.143" />
</G>
</Svg>
</Svg>
</Example>
</Page>
Expand Down
1 change: 1 addition & 0 deletions windows/RNSVG/BrushView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ void BrushView::SetBounds(Windows::Foundation::Rect const &rect) {
}

void BrushView::Unload() {
m_brush.Close();
m_brush = nullptr;

__super::Unload();
Expand Down
6 changes: 3 additions & 3 deletions windows/RNSVG/GroupView.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ struct GroupView : GroupViewT<GroupView, RNSVG::implementation::RenderableView>
GroupView() = default;
GroupView(Microsoft::ReactNative::IReactContext const &context) : m_reactContext(context) {}

Windows::Foundation::Collections::IVector<RNSVG::RenderableView> Children() { return m_children; }
Windows::Foundation::Collections::IVector<RNSVG::IRenderable> Children() { return m_children; }

hstring FontFamily() { return m_fontFamily; }
void FontFamily(hstring const &value) { m_fontFamily = value; }
Expand Down Expand Up @@ -38,8 +38,8 @@ struct GroupView : GroupViewT<GroupView, RNSVG::implementation::RenderableView>

private:
Microsoft::ReactNative::IReactContext m_reactContext{nullptr};
Windows::Foundation::Collections::IVector<RNSVG::RenderableView> m_children{
winrt::single_threaded_vector<RNSVG::RenderableView>()};
Windows::Foundation::Collections::IVector<RNSVG::IRenderable> m_children{
winrt::single_threaded_vector<RNSVG::IRenderable>()};

float m_fontSize{12.0f};
hstring m_fontFamily{L"Segoe UI"};
Expand Down
2 changes: 1 addition & 1 deletion windows/RNSVG/GroupViewManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ IMapView<hstring, ViewManagerPropertyType> GroupViewManager::NativeProps() {
// IViewManagerWithChildren
void GroupViewManager::AddView(FrameworkElement const &parent, UIElement const &child, int64_t /*index*/) {
if (auto const &groupView{parent.try_as<RNSVG::GroupView>()}) {
if (auto const &childView{child.try_as<RNSVG::RenderableView>()}) {
if (auto const &childView{child.try_as<IRenderable>()}) {
childView.SvgParent(parent);
groupView.Children().Append(childView);
childView.MergeProperties(groupView);
Expand Down
15 changes: 9 additions & 6 deletions windows/RNSVG/RenderableView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,10 +193,7 @@ void RenderableView::SaveDefinition() {
}
}

void RenderableView::Render(
UI::Xaml::CanvasControl const &canvas,
CanvasDrawingSession const &session)
{
void RenderableView::Render(UI::Xaml::CanvasControl const &canvas, CanvasDrawingSession const &session) {
auto const &resourceCreator{canvas.try_as<ICanvasResourceCreator>()};
if (m_recreateResources) {
CreateGeometry(canvas);
Expand Down Expand Up @@ -287,13 +284,19 @@ void RenderableView::MergeProperties(RNSVG::RenderableView const &other) {
RNSVG::SvgView RenderableView::SvgRoot() {
if (SvgParent()) {
if (auto const &svgView{SvgParent().try_as<RNSVG::SvgView>()}) {
return svgView;
if (svgView.SvgParent()) {
if (auto const &parent{svgView.SvgParent().try_as<RNSVG::RenderableView>()}) {
return parent.SvgRoot();
}
} else {
return svgView;
}
} else if (auto const &renderable{SvgParent().try_as<RNSVG::RenderableView>()}) {
return renderable.SvgRoot();
}
}

return {nullptr};
return nullptr;
}

void RenderableView::Unload() {
Expand Down
160 changes: 110 additions & 50 deletions windows/RNSVG/SvgView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,45 +20,83 @@ SvgView::SvgView(IReactContext const &context) : m_reactContext(context) {
m_scale = static_cast<float>(DisplayInformation::GetForCurrentView().ResolutionScale()) / 100;

m_canvasDrawRevoker = m_canvas.Draw(winrt::auto_revoke, {get_weak(), &SvgView::Canvas_Draw});
m_canvaSizeChangedRevoker = m_canvas.SizeChanged(winrt::auto_revoke, {get_weak(), &SvgView::Canvas_SizeChanged});
m_canvasSizeChangedRevoker = m_canvas.SizeChanged(winrt::auto_revoke, {get_weak(), &SvgView::Canvas_SizeChanged});
m_panelUnloadedRevoker = Unloaded(winrt::auto_revoke, {get_weak(), &SvgView::Panel_Unloaded});

Children().Append(m_canvas);
}

void SvgView::UpdateProperties(IJSValueReader const &reader) {
auto const &propertyMap{JSValueObject::ReadFrom(reader)};

for (auto const &pair : propertyMap) {
auto const &propertyName{pair.first};
auto const &propertyValue{pair.second};

if (propertyName == "width") {
m_width = SVGLength::From(propertyValue);
} else if (propertyName == "height") {
m_height = SVGLength::From(propertyValue);
} else if (propertyName == "bbWidth") {
m_bbWidth = SVGLength::From(propertyValue);
Width(m_bbWidth.Value());
} else if (propertyName == "bbHeight") {
m_bbHeight = SVGLength::From(propertyValue);
Height(m_bbHeight.Value());
} else if (propertyName == "vbWidth") {
m_vbWidth = Utils::JSValueAsFloat(propertyValue);
} else if (propertyName == "vbHeight") {
m_vbHeight = Utils::JSValueAsFloat(propertyValue);
} else if (propertyName == "minX") {
m_minX = Utils::JSValueAsFloat(propertyValue);
} else if (propertyName == "minY") {
m_minY = Utils::JSValueAsFloat(propertyValue);
} else if (propertyName == "align") {
m_align = Utils::JSValueAsString(propertyValue);
} else if (propertyName == "meetOrSlice") {
m_meetOrSlice = Utils::GetMeetOrSlice(propertyValue);
void SvgView::SvgParent(Windows::UI::Xaml::FrameworkElement const &value) {
if (value) {
m_canvasDrawRevoker.revoke();
m_canvasSizeChangedRevoker.revoke();
m_panelUnloadedRevoker.revoke();
m_canvas.RemoveFromVisualTree();
m_canvas = nullptr;
m_parent = value;
}
}

void SvgView::UpdateProperties(IJSValueReader const &reader, bool forceUpdate, bool invalidate) {
// If forceUpdate is false, that means this is a nested Svg
// and we're inheriting props. Pass those along to the group.
if (!forceUpdate && m_group) {
m_group.UpdateProperties(reader, forceUpdate, invalidate);
} else {
auto const &propertyMap{JSValueObject::ReadFrom(reader)};

for (auto const &pair : propertyMap) {
auto const &propertyName{pair.first};
auto const &propertyValue{pair.second};

if (propertyName == "name") {
if (m_parent && m_group) {
m_group.SvgRoot().Templates().Remove(m_id);
}
m_id = to_hstring(Utils::JSValueAsString(propertyValue));
if (m_parent) {
SaveDefinition();
}
} else if (propertyName == "width") {
m_width = SVGLength::From(propertyValue);
} else if (propertyName == "height") {
m_height = SVGLength::From(propertyValue);
} else if (propertyName == "bbWidth") {
m_bbWidth = SVGLength::From(propertyValue);
Width(m_bbWidth.Value());
} else if (propertyName == "bbHeight") {
m_bbHeight = SVGLength::From(propertyValue);
Height(m_bbHeight.Value());
} else if (propertyName == "vbWidth") {
m_vbWidth = Utils::JSValueAsFloat(propertyValue);
} else if (propertyName == "vbHeight") {
m_vbHeight = Utils::JSValueAsFloat(propertyValue);
} else if (propertyName == "minX") {
m_minX = Utils::JSValueAsFloat(propertyValue);
} else if (propertyName == "minY") {
m_minY = Utils::JSValueAsFloat(propertyValue);
} else if (propertyName == "align") {
m_align = Utils::JSValueAsString(propertyValue);
} else if (propertyName == "meetOrSlice") {
m_meetOrSlice = Utils::GetMeetOrSlice(propertyValue);
}
}

InvalidateCanvas();
}
}

InvalidateCanvas();
void SvgView::SaveDefinition() {
if (m_id != L"" && m_group) {
m_group.SvgRoot().Templates().Insert(m_id, *this);
m_group.SaveDefinition();
}
}

void SvgView::MergeProperties(RNSVG::RenderableView const &other) {
if (m_group) {
m_group.MergeProperties(other);
}
}

Size SvgView::MeasureOverride(Size availableSize) {
Expand All @@ -75,48 +113,70 @@ Size SvgView::ArrangeOverride(Size finalSize) {
return finalSize;
}

void SvgView::Canvas_Draw(UI::Xaml::CanvasControl const &sender, UI::Xaml::CanvasDrawEventArgs const &args) {
if (!m_hasRendered) {
m_hasRendered = true;
}

void SvgView::Render(UI::Xaml::CanvasControl const & canvas, CanvasDrawingSession const & session) {
if (m_align != "") {
Rect vbRect{m_minX * m_scale, m_minY * m_scale, m_vbWidth * m_scale, m_vbHeight * m_scale};
Rect elRect{0, 0, static_cast<float>(sender.ActualWidth()), static_cast<float>(sender.ActualHeight())};
float width{static_cast<float>(canvas.ActualWidth())};
float height{static_cast<float>(canvas.ActualHeight())};
bool nested{m_parent};

args.DrawingSession().Transform(Utils::GetViewBoxTransform(vbRect, elRect, m_align, m_meetOrSlice));
if (nested) {
width = Utils::GetAbsoluteLength(m_bbWidth, width);
height = Utils::GetAbsoluteLength(m_bbHeight, height);
}

Rect elRect{0, 0, width, height};

session.Transform(Utils::GetViewBoxTransform(vbRect, elRect, m_align, m_meetOrSlice));
}

if (m_group) {
m_group.SaveDefinition();
m_group.Render(sender, args.DrawingSession());
m_group.Render(canvas, session);
}
}

void SvgView::Canvas_Draw(UI::Xaml::CanvasControl const &sender, UI::Xaml::CanvasDrawEventArgs const &args) {
if (!m_hasRendered) {
m_hasRendered = true;
}

m_brushes.Clear();
m_templates.Clear();

Render(sender, args.DrawingSession());
}

void SvgView::Canvas_SizeChanged(
IInspectable const & /*sender*/,
Windows::UI::Xaml::SizeChangedEventArgs const & /*args*/) {
// sender.Invalidate();
}

void SvgView::InvalidateCanvas() {
if (m_hasRendered) {
m_canvas.Invalidate();
void SvgView::Panel_Unloaded(IInspectable const &sender, Windows::UI::Xaml::RoutedEventArgs const & /*args*/) {
if (auto const &svgView{sender.try_as<RNSVG::SvgView>()}) {
svgView.Unload();
}
}

void SvgView::Panel_Unloaded(IInspectable const &sender, Windows::UI::Xaml::RoutedEventArgs const & /*args*/) {
if (auto const &svgView{sender.try_as<RNSVG::SvgView>()}) {
m_reactContext = nullptr;
m_templates.Clear();
m_brushes.Clear();
void SvgView::Unload() {
m_reactContext = nullptr;
m_templates.Clear();
m_brushes.Clear();

if (m_group) {
m_group.Unload();
}
if (m_group) {
m_group.Unload();
}

if (m_canvas) {
m_canvas.RemoveFromVisualTree();
m_canvas = nullptr;
}
}

void SvgView::InvalidateCanvas() {
if (m_hasRendered) {
m_canvas.Invalidate();
}
}
} // namespace winrt::RNSVG::implementation
26 changes: 20 additions & 6 deletions windows/RNSVG/SvgView.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,32 @@ struct SvgView : SvgViewT<SvgView> {

Microsoft::Graphics::Canvas::UI::Xaml::CanvasControl Canvas() { return m_canvas; }

Windows::UI::Xaml::FrameworkElement SvgParent() { return m_parent; }
void SvgParent(Windows::UI::Xaml::FrameworkElement const &value);

RNSVG::GroupView Group() { return m_group; }
void Group(RNSVG::GroupView const &value) { m_group = value; }

Microsoft::Graphics::Canvas::Geometry::CanvasGeometry Geometry() { return m_group ? m_group.Geometry() : nullptr; }
void Geometry(Microsoft::Graphics::Canvas::Geometry::CanvasGeometry /*value*/) { }

float SvgScale() { return m_scale; }

Windows::Foundation::Collections::IMap<hstring, RNSVG::RenderableView> Templates() {
Windows::Foundation::Collections::IMap<hstring, RNSVG::IRenderable> Templates() {
return m_templates;
}
Windows::Foundation::Collections::IMap<hstring, RNSVG::BrushView> Brushes() {
return m_brushes;
}

void UpdateProperties(Microsoft::ReactNative::IJSValueReader const &reader);
// IRenderable
void UpdateProperties(Microsoft::ReactNative::IJSValueReader const &reader, bool forceUpdate = true, bool invalidate = true);
void Render(
Microsoft::Graphics::Canvas::UI::Xaml::CanvasControl const &canvas,
Microsoft::Graphics::Canvas::CanvasDrawingSession const &session);
void MergeProperties(RNSVG::RenderableView const &other);
void SaveDefinition();
void Unload();

// Overrides
Windows::Foundation::Size MeasureOverride(Windows::Foundation::Size availableSize);
Expand All @@ -33,7 +46,6 @@ struct SvgView : SvgViewT<SvgView> {
void Canvas_Draw(
Microsoft::Graphics::Canvas::UI::Xaml::CanvasControl const &sender,
Microsoft::Graphics::Canvas::UI::Xaml::CanvasDrawEventArgs const &args);

void Canvas_SizeChanged(
Windows::Foundation::IInspectable const &sender,
Windows::UI::Xaml::SizeChangedEventArgs const &args);
Expand All @@ -46,7 +58,9 @@ struct SvgView : SvgViewT<SvgView> {
bool m_hasRendered{false};
Microsoft::ReactNative::IReactContext m_reactContext{nullptr};
Microsoft::Graphics::Canvas::UI::Xaml::CanvasControl m_canvas{};
Windows::UI::Xaml::FrameworkElement m_parent{nullptr};
RNSVG::GroupView m_group{nullptr};
hstring m_id{L""};
float m_scale{0.0f};
float m_minX{0.0f};
float m_minY{0.0f};
Expand All @@ -59,12 +73,12 @@ struct SvgView : SvgViewT<SvgView> {
std::string m_align{""};
RNSVG::MeetOrSlice m_meetOrSlice{RNSVG::MeetOrSlice::Meet};

Windows::Foundation::Collections::IMap<hstring, RNSVG::RenderableView> m_templates{
winrt::single_threaded_map<hstring, RNSVG::RenderableView>()};
Windows::Foundation::Collections::IMap<hstring, RNSVG::IRenderable> m_templates{
winrt::single_threaded_map<hstring, RNSVG::IRenderable>()};
Windows::Foundation::Collections::IMap<hstring, RNSVG::BrushView> m_brushes{
winrt::single_threaded_map<hstring, RNSVG::BrushView>()};
Microsoft::Graphics::Canvas::UI::Xaml::CanvasControl::Draw_revoker m_canvasDrawRevoker{};
Microsoft::Graphics::Canvas::UI::Xaml::CanvasControl::SizeChanged_revoker m_canvaSizeChangedRevoker{};
Microsoft::Graphics::Canvas::UI::Xaml::CanvasControl::SizeChanged_revoker m_canvasSizeChangedRevoker{};
Windows::UI::Xaml::FrameworkElement::Unloaded_revoker m_panelUnloadedRevoker{};
};
} // namespace winrt::RNSVG::implementation
Expand Down
6 changes: 4 additions & 2 deletions windows/RNSVG/SvgViewManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ IMapView<hstring, ViewManagerPropertyType> SvgViewManager::NativeProps() {
nativeProps.Insert(L"minY", ViewManagerPropertyType::Number);
nativeProps.Insert(L"vbWidth", ViewManagerPropertyType::Number);
nativeProps.Insert(L"vbHeight", ViewManagerPropertyType::Number);
nativeProps.Insert(L"bbWidth", ViewManagerPropertyType::Number);
nativeProps.Insert(L"bbHeight", ViewManagerPropertyType::Number);

// preserveAspectRatio
nativeProps.Insert(L"align", ViewManagerPropertyType::String);
Expand All @@ -58,8 +60,8 @@ IMapView<hstring, ViewManagerPropertyType> SvgViewManager::NativeProps() {
}

void SvgViewManager::UpdateProperties(FrameworkElement const &view, IJSValueReader const &propertyMapReader) {
if (auto const &svgView{view.try_as<RNSVG::SvgView>()}) {
svgView.UpdateProperties(propertyMapReader);
if (auto const &svgView{view.try_as<SvgView>()}) {
svgView->UpdateProperties(propertyMapReader);
}
}

Expand Down
2 changes: 1 addition & 1 deletion windows/RNSVG/UseView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ void UseView::Render(UI::Xaml::CanvasControl const &canvas, CanvasDrawingSession
}
}

RNSVG::RenderableView UseView::GetRenderableTemplate() {
RNSVG::IRenderable UseView::GetRenderableTemplate() {
if (auto const &root{SvgRoot()}) {
return root.Templates().TryLookup(m_href);
}
Expand Down
Loading