From 854f3c70bdf76f43e78381983b0bc724317e3bb7 Mon Sep 17 00:00:00 2001 From: Randy Flynn Date: Thu, 4 Apr 2019 12:52:03 -0700 Subject: [PATCH 01/10] Reduce and rationalize some header file includes related to ShadowNodeBase & ViewManagerBase. Reduces dependencies for build. --- RNWCPP/ReactUWP/Polyester/ButtonViewManager.cpp | 2 ++ RNWCPP/ReactUWP/Polyester/HyperlinkViewManager.cpp | 2 ++ RNWCPP/ReactUWP/Utils/PropertyUtils.h | 2 ++ RNWCPP/ReactUWP/Views/CheckboxViewManager.cpp | 2 ++ RNWCPP/ReactUWP/Views/ControlViewManager.cpp | 1 + RNWCPP/ReactUWP/Views/DatePickerViewManager.cpp | 2 ++ RNWCPP/ReactUWP/Views/ImageViewManager.cpp | 2 ++ RNWCPP/ReactUWP/Views/ImageViewManager.h | 4 ++++ RNWCPP/ReactUWP/Views/PickerViewManager.cpp | 2 ++ RNWCPP/ReactUWP/Views/ScrollViewManager.cpp | 2 ++ RNWCPP/ReactUWP/Views/ShadowNodeBase.cpp | 7 +++++++ RNWCPP/ReactUWP/Views/SwitchViewManager.cpp | 2 ++ RNWCPP/ReactUWP/Views/TextInputViewManager.cpp | 2 ++ RNWCPP/ReactUWP/Views/ViewManagerBase.cpp | 3 ++- RNWCPP/ReactUWP/Views/ViewViewManager.cpp | 1 + RNWCPP/ReactUWP/Views/WebViewManager.cpp | 2 ++ RNWCPP/include/ReactUWP/Views/ControlViewManager.h | 4 ++-- RNWCPP/include/ReactUWP/Views/ShadowNodeBase.h | 11 ++++++++--- RNWCPP/include/ReactUWP/Views/ViewManagerBase.h | 3 --- 19 files changed, 47 insertions(+), 9 deletions(-) diff --git a/RNWCPP/ReactUWP/Polyester/ButtonViewManager.cpp b/RNWCPP/ReactUWP/Polyester/ButtonViewManager.cpp index 32880546e11..c673eef02dd 100644 --- a/RNWCPP/ReactUWP/Polyester/ButtonViewManager.cpp +++ b/RNWCPP/ReactUWP/Polyester/ButtonViewManager.cpp @@ -8,6 +8,8 @@ #include #include +#include + #include #include diff --git a/RNWCPP/ReactUWP/Polyester/HyperlinkViewManager.cpp b/RNWCPP/ReactUWP/Polyester/HyperlinkViewManager.cpp index e047be14908..8651355dec8 100644 --- a/RNWCPP/ReactUWP/Polyester/HyperlinkViewManager.cpp +++ b/RNWCPP/ReactUWP/Polyester/HyperlinkViewManager.cpp @@ -8,6 +8,8 @@ #include #include +#include + #include #include diff --git a/RNWCPP/ReactUWP/Utils/PropertyUtils.h b/RNWCPP/ReactUWP/Utils/PropertyUtils.h index cf54b8812dd..304498e1f48 100644 --- a/RNWCPP/ReactUWP/Utils/PropertyUtils.h +++ b/RNWCPP/ReactUWP/Utils/PropertyUtils.h @@ -22,6 +22,8 @@ using namespace Windows::UI::Xaml; namespace react { namespace uwp { +struct ShadowNodeBase; + static double DefaultOrOverride(double defaultValue, double x) { return x != c_UndefinedEdge ? x : defaultValue; }; diff --git a/RNWCPP/ReactUWP/Views/CheckboxViewManager.cpp b/RNWCPP/ReactUWP/Views/CheckboxViewManager.cpp index e9a80fed7ef..a4f3549605c 100644 --- a/RNWCPP/ReactUWP/Views/CheckboxViewManager.cpp +++ b/RNWCPP/ReactUWP/Views/CheckboxViewManager.cpp @@ -8,6 +8,8 @@ #include +#include + #include #include diff --git a/RNWCPP/ReactUWP/Views/ControlViewManager.cpp b/RNWCPP/ReactUWP/Views/ControlViewManager.cpp index fcac3c95a81..6ee91d45d61 100644 --- a/RNWCPP/ReactUWP/Views/ControlViewManager.cpp +++ b/RNWCPP/ReactUWP/Views/ControlViewManager.cpp @@ -4,6 +4,7 @@ #include "pch.h" #include +#include #include diff --git a/RNWCPP/ReactUWP/Views/DatePickerViewManager.cpp b/RNWCPP/ReactUWP/Views/DatePickerViewManager.cpp index 2cc930e3a5f..b93874160a3 100644 --- a/RNWCPP/ReactUWP/Views/DatePickerViewManager.cpp +++ b/RNWCPP/ReactUWP/Views/DatePickerViewManager.cpp @@ -8,6 +8,8 @@ #include +#include + #include #include #include diff --git a/RNWCPP/ReactUWP/Views/ImageViewManager.cpp b/RNWCPP/ReactUWP/Views/ImageViewManager.cpp index 8c6bb34a309..f944bfe1e54 100644 --- a/RNWCPP/ReactUWP/Views/ImageViewManager.cpp +++ b/RNWCPP/ReactUWP/Views/ImageViewManager.cpp @@ -15,6 +15,8 @@ #include #include +#include + #include #include #include diff --git a/RNWCPP/ReactUWP/Views/ImageViewManager.h b/RNWCPP/ReactUWP/Views/ImageViewManager.h index 9695ed7ab99..d1fcd549b9d 100644 --- a/RNWCPP/ReactUWP/Views/ImageViewManager.h +++ b/RNWCPP/ReactUWP/Views/ImageViewManager.h @@ -7,6 +7,10 @@ namespace winrt::Windows::UI::Xaml::Media { enum class Stretch; } +namespace facebook { namespace react { + class MessageQueueThread; +} } + namespace react { namespace uwp { class ImageViewManager : public FrameworkElementViewManager diff --git a/RNWCPP/ReactUWP/Views/PickerViewManager.cpp b/RNWCPP/ReactUWP/Views/PickerViewManager.cpp index 760288d1b88..8fe01e2382b 100644 --- a/RNWCPP/ReactUWP/Views/PickerViewManager.cpp +++ b/RNWCPP/ReactUWP/Views/PickerViewManager.cpp @@ -9,6 +9,8 @@ #include #include "UnicodeConversion.h" +#include + #include #include #include diff --git a/RNWCPP/ReactUWP/Views/ScrollViewManager.cpp b/RNWCPP/ReactUWP/Views/ScrollViewManager.cpp index 112408c8094..13a82a24f12 100644 --- a/RNWCPP/ReactUWP/Views/ScrollViewManager.cpp +++ b/RNWCPP/ReactUWP/Views/ScrollViewManager.cpp @@ -8,6 +8,8 @@ #include #include +#include + #include #include #include diff --git a/RNWCPP/ReactUWP/Views/ShadowNodeBase.cpp b/RNWCPP/ReactUWP/Views/ShadowNodeBase.cpp index 04eddb5ec24..7058d0b3c31 100644 --- a/RNWCPP/ReactUWP/Views/ShadowNodeBase.cpp +++ b/RNWCPP/ReactUWP/Views/ShadowNodeBase.cpp @@ -3,7 +3,9 @@ #include "pch.h" +#include #include +#include namespace react { namespace uwp { @@ -12,6 +14,11 @@ ShadowNodeBase::ShadowNodeBase() { } +ViewManagerBase* ShadowNodeBase::GetViewManager() const +{ + return static_cast(m_viewManager); +} + void ShadowNodeBase::updateProperties(const folly::dynamic&& props) { GetViewManager()->UpdateProperties(this, props); diff --git a/RNWCPP/ReactUWP/Views/SwitchViewManager.cpp b/RNWCPP/ReactUWP/Views/SwitchViewManager.cpp index 4f68de44be8..976c7cf503d 100644 --- a/RNWCPP/ReactUWP/Views/SwitchViewManager.cpp +++ b/RNWCPP/ReactUWP/Views/SwitchViewManager.cpp @@ -6,6 +6,8 @@ #include "SwitchViewManager.h" #include +#include + #include namespace winrt { diff --git a/RNWCPP/ReactUWP/Views/TextInputViewManager.cpp b/RNWCPP/ReactUWP/Views/TextInputViewManager.cpp index 905b46618a5..4e1a996384f 100644 --- a/RNWCPP/ReactUWP/Views/TextInputViewManager.cpp +++ b/RNWCPP/ReactUWP/Views/TextInputViewManager.cpp @@ -11,6 +11,8 @@ #include #include +#include + #include #include #include diff --git a/RNWCPP/ReactUWP/Views/ViewManagerBase.cpp b/RNWCPP/ReactUWP/Views/ViewManagerBase.cpp index a50cd080bb2..82a552db637 100644 --- a/RNWCPP/ReactUWP/Views/ViewManagerBase.cpp +++ b/RNWCPP/ReactUWP/Views/ViewManagerBase.cpp @@ -5,12 +5,13 @@ #include -#include #include "ViewPanel.h" #include +#include #include +#include #include using namespace folly; diff --git a/RNWCPP/ReactUWP/Views/ViewViewManager.cpp b/RNWCPP/ReactUWP/Views/ViewViewManager.cpp index 1233e63f0cf..92ef37be604 100644 --- a/RNWCPP/ReactUWP/Views/ViewViewManager.cpp +++ b/RNWCPP/ReactUWP/Views/ViewViewManager.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include diff --git a/RNWCPP/ReactUWP/Views/WebViewManager.cpp b/RNWCPP/ReactUWP/Views/WebViewManager.cpp index 97f499ccffa..45248f8a50d 100644 --- a/RNWCPP/ReactUWP/Views/WebViewManager.cpp +++ b/RNWCPP/ReactUWP/Views/WebViewManager.cpp @@ -9,6 +9,8 @@ #include +#include + #include #include diff --git a/RNWCPP/include/ReactUWP/Views/ControlViewManager.h b/RNWCPP/include/ReactUWP/Views/ControlViewManager.h index 56a238cdb71..35ec48b7373 100644 --- a/RNWCPP/include/ReactUWP/Views/ControlViewManager.h +++ b/RNWCPP/include/ReactUWP/Views/ControlViewManager.h @@ -5,10 +5,10 @@ #include "FrameworkElementViewManager.h" -#include - namespace react { namespace uwp { +struct ShadowNodeBase; + class REACTWINDOWS_EXPORT ControlViewManager : public FrameworkElementViewManager { using Super = FrameworkElementViewManager; diff --git a/RNWCPP/include/ReactUWP/Views/ShadowNodeBase.h b/RNWCPP/include/ReactUWP/Views/ShadowNodeBase.h index d6d5e61ab2c..e60bb1925da 100644 --- a/RNWCPP/include/ReactUWP/Views/ShadowNodeBase.h +++ b/RNWCPP/include/ReactUWP/Views/ShadowNodeBase.h @@ -3,13 +3,18 @@ #pragma once -#include "ViewManagerBase.h" - #include #include +#include +#include + +#include + namespace react { namespace uwp { +class ViewManagerBase; + enum ShadowEdges : uint8_t { Left = 0, @@ -88,7 +93,7 @@ struct REACTWINDOWS_EXPORT ShadowNodeBase : public facebook::react::ShadowNode virtual void ReplaceChild(XamlView oldChildView, XamlView newChildView); virtual bool ImplementsPadding() { return false; } - ViewManagerBase* GetViewManager() const { return static_cast(m_viewManager); } + ViewManagerBase* GetViewManager() const; XamlView GetView() const { return m_view; } int64_t GetParent() const { return m_parent; } diff --git a/RNWCPP/include/ReactUWP/Views/ViewManagerBase.h b/RNWCPP/include/ReactUWP/Views/ViewManagerBase.h index 54495ae9a4c..afaa10e7404 100644 --- a/RNWCPP/include/ReactUWP/Views/ViewManagerBase.h +++ b/RNWCPP/include/ReactUWP/Views/ViewManagerBase.h @@ -5,14 +5,11 @@ #include -#include #include #include #include -#include - #include namespace facebook { namespace react { From 4ad2e3ecc5bb165c34c2cb858b501135fcd5d9e8 Mon Sep 17 00:00:00 2001 From: Randy Flynn Date: Tue, 16 Apr 2019 11:12:06 -0700 Subject: [PATCH 02/10] Checkpoint. --- RNWCPP/ReactUWP/Views/ViewPanel.cpp | 205 +++++++-------------- RNWCPP/ReactUWP/Views/ViewPanel.h | 11 +- RNWCPP/ReactUWP/Views/ViewViewManager.cpp | 207 ++++++++++++++-------- RNWCPP/ReactUWP/Views/ViewViewManager.h | 4 +- RNWCPP/Universal.SampleApp/view.uwp.js | 114 ++++++++++++ 5 files changed, 317 insertions(+), 224 deletions(-) create mode 100644 RNWCPP/Universal.SampleApp/view.uwp.js diff --git a/RNWCPP/ReactUWP/Views/ViewPanel.cpp b/RNWCPP/ReactUWP/Views/ViewPanel.cpp index a58e01109d0..5138d48e500 100644 --- a/RNWCPP/ReactUWP/Views/ViewPanel.cpp +++ b/RNWCPP/ReactUWP/Views/ViewPanel.cpp @@ -186,7 +186,7 @@ winrt::Size ViewPanel::ArrangeOverride(winrt::Size finalSize) double childWidth = 0.0; // A Border or inner ViewPanel should take up the same space as this panel - if ((child == m_border) || (child == m_innerElement)) + if (child == m_border) { childWidth = finalSize.Width; childHeight = finalSize.Height; @@ -220,72 +220,25 @@ winrt::Size ViewPanel::ArrangeOverride(winrt::Size finalSize) void ViewPanel::InsertAt(uint32_t const index, winrt::UIElement const& value) const { - auto innerPanel = GetInnerPanel(); - if (innerPanel != nullptr) - innerPanel->InsertAt(index, value); - else - Children().InsertAt(index, value); + Children().InsertAt(index, value); } void ViewPanel::RemoveAt(uint32_t const index) const { - auto innerPanel = GetInnerPanel(); - if (innerPanel != nullptr) - innerPanel->RemoveAt(index); - else - Children().RemoveAt(index); + Children().RemoveAt(index); } void ViewPanel::Remove(winrt::UIElement element) const { - auto innerPanel = GetInnerPanel(); - if (innerPanel != nullptr) - { - innerPanel->Remove(element); - } - else - { - uint32_t index; + uint32_t index; - if (Children().IndexOf(element, index)) - Children().RemoveAt(index); - } + if (Children().IndexOf(element, index)) + Children().RemoveAt(index); } void ViewPanel::Clear() const { - auto innerPanel = GetInnerPanel(); - if (innerPanel != nullptr) - innerPanel->Clear(); - else - Children().Clear(); -} - -winrt::UIElement ViewPanel::GetAt(uint32_t const index) const -{ - auto innerPanel = GetInnerPanel(); - if (innerPanel != nullptr) - return innerPanel->GetAt(index); - else - return Children().GetAt(index); -} - -uint32_t ViewPanel::Size() const -{ - auto innerPanel = GetInnerPanel(); - if (innerPanel != nullptr) - { - return innerPanel->Size(); - } - else - { - auto size = Children().Size(); - - if (m_border != nullptr) - size -= 1; - - return size; - } + Children().Clear(); } void ViewPanel::Background(winrt::Brush const& value) @@ -313,40 +266,6 @@ void ViewPanel::ClipChildren(bool value) SetValue(ClipChildrenProperty(), winrt::box_value(value)); } -void ViewPanel::EnsureBorder() -{ - if (m_border == nullptr) - { - m_border = winrt::Border(); - Children().Append(m_border); - } -} - -void ViewPanel::EnsureInnerPanel() -{ - // ASSERT: Need to have a Border to put the ViewPanel into - assert(m_border != nullptr); - - if (m_innerElement == nullptr) - { - auto innerPanel = ViewPanel::Create(); - m_innerElement = innerPanel.try_as(); - - // If there are any children other than our own border then we need to transfer them to the inner panel - for (uint32_t i = Children().Size(); i > 0; --i) - { - auto child = Children().GetAt(i - 1); - if (child != m_border) - { - Children().RemoveAt(i - 1); - innerPanel->InsertAt(0, child); - } - } - - m_border.Child(m_innerElement); - } -} - void ViewPanel::FinalizeProperties() { if (!m_propertiesChanged) @@ -354,20 +273,17 @@ void ViewPanel::FinalizeProperties() // There are 3 different solutions // - // A) Have Border with Inner Panel child that contains real children - // >> border and background properties go on the Border - // ** This solution only used when there is a corner radius - // B) Have Border with no child and this Panel contains the Border and the real children - // >> border properties go on Border, background goes on this Panel - // ** This solution used when there are border properties but no corner radius - // C) No Border and real children contained by this Panel - // >> background goes on this Panel - // ** This solution used when there are no border properties or corner radius + // A) No Border + // -- No need for any border properties so just contain real children + // >> Background applied to ViewPanel // - // What we need to know: - // 1. Do we need an inner panel? Only if we have a corner radius and need clipping. - // 2. Do we need a Border? NOTE: Includes any time we need an inner panel! - // 3. Where do we apply the background? (implied by #1) + // B) Inner Border (child of this panel along with real children) + // -- Border created and made a child of this panel, alongside standard children + // >> Border* properties applied to Border, Background applied to ViewPanel + // + // C) Outer Border + // -- Border created but handed out to view manager to make parent of this ViewPanel + // >> Border* properties and Background applied to Border const auto unsetValue = winrt::DependencyProperty::UnsetValue(); @@ -377,14 +293,41 @@ void ViewPanel::FinalizeProperties() bool hasCornerRadius = ReadLocalValue(CornerRadiusProperty()) != unsetValue; bool displayBorder = hasBorderBrush && hasBorderThickness; - bool needInnerPanel = hasCornerRadius && (ClipChildren() || !displayBorder); - bool needBorder = needInnerPanel || hasCornerRadius || (hasBorderThickness && hasBorderBrush); + // Determine which scenario our current properties have put us into + enum Scenario { OuterBorder, InnerBorder, NoBorder } scenario; + if (hasCornerRadius) + { + scenario = Scenario::OuterBorder; + m_hasOuterBorder = true; + } + else if (!displayBorder) + { + scenario = Scenario::NoBorder; + m_hasOuterBorder = false; + } + else if (ClipChildren()) + { + scenario = Scenario::OuterBorder; + m_hasOuterBorder = true; + } + else + { + scenario = Scenario::InnerBorder; + m_hasOuterBorder = false; + } // Border element - if (needBorder) + if (scenario != Scenario::NoBorder) { - // Ensure Border is created and set properties - EnsureBorder(); + // Ensure Border is created + if (m_border == nullptr) + { + m_border = winrt::Border(); + + // Add border as the top child if using as inner border + if (scenario == Scenario::InnerBorder) + Children().Append(m_border); + } // TODO: Can Binding be used here? if (hasBorderBrush) @@ -409,35 +352,22 @@ void ViewPanel::FinalizeProperties() m_border = nullptr; } - // Inner ViewPanel element - if (needInnerPanel) - { - EnsureInnerPanel(); - } - else if (m_innerElement != nullptr) - { - Remove(m_innerElement); - m_innerElement = nullptr; - } - - // Background property: On Border if there's an inner Panel, on this Panel otherwise - if (needInnerPanel) + if (scenario == Scenario::OuterBorder) { - // Remove any background set on this Panel - Super::ClearValue(winrt::Panel::BackgroundProperty()); - - // Set any background on the Border if (hasBackground) m_border.Background(Background()); else m_border.ClearValue(winrt::Border::BackgroundProperty()); + + ClearValue(winrt::Panel::BackgroundProperty()); } else { - // Remove any background set on the Border and set it on this Panel - if (m_border != nullptr) - m_border.ClearValue(winrt::Border::BackgroundProperty()); - + // Set any background on this Panel + if (hasBackground) + SetValue(winrt::Panel::BackgroundProperty(), Background()); + else + ClearValue(winrt::Panel::BackgroundProperty()); // Set any background on this Panel if (hasBackground) SetValue(winrt::Panel::BackgroundProperty(), Background()); @@ -450,12 +380,18 @@ void ViewPanel::FinalizeProperties() m_propertiesChanged = false; } -void ViewPanel::UpdateClip() +winrt::Border ViewPanel::GetOuterBorder() { - // Clipping is only applied to the outer panel. If the inner Panel is used it implies that - // clipping will happen and be handled by the Border element. + if (m_hasOuterBorder && (m_border != nullptr)) + return m_border; + else + return winrt::Border(nullptr); +} - if (ClipChildren()) +void ViewPanel::UpdateClip() +{ + // When an outer Border is used it will handle the clipping, otherwise this panel must do so + if (!m_hasOuterBorder && ClipChildren()) { winrt::RectangleGeometry clipGeometry; clipGeometry.Rect(winrt::Rect(0, 0, static_cast(ActualWidth()), static_cast(ActualHeight()))); @@ -468,11 +404,4 @@ void ViewPanel::UpdateClip() } } -ViewPanel* ViewPanel::GetInnerPanel() const -{ - return (m_innerElement != nullptr) - ? m_innerElement.try_as().get() - : nullptr; -} - } } diff --git a/RNWCPP/ReactUWP/Views/ViewPanel.h b/RNWCPP/ReactUWP/Views/ViewPanel.h index 42b9202b01e..cf0110b6a4e 100644 --- a/RNWCPP/ReactUWP/Views/ViewPanel.h +++ b/RNWCPP/ReactUWP/Views/ViewPanel.h @@ -31,10 +31,8 @@ struct ViewPanel : winrt::Windows::UI::Xaml::Controls::PanelT void RemoveAt(uint32_t const index) const; void Clear() const; - winrt::Windows::UI::Xaml::UIElement GetAt(uint32_t const index) const; - uint32_t Size() const; - void FinalizeProperties(); + winrt::Windows::UI::Xaml::Controls::Border GetOuterBorder(); // Public Properties winrt::Windows::UI::Xaml::Media::Brush Background() { return GetValue(BackgroundProperty()).try_as(); } @@ -70,11 +68,6 @@ struct ViewPanel : winrt::Windows::UI::Xaml::Controls::PanelT static double GetLeft(winrt::Windows::UI::Xaml::UIElement& element) { return winrt::unbox_value(element.GetValue(LeftProperty())); } private: - // Managing the Border & Background Elements - void EnsureBorder(); - void EnsureInnerPanel(); - ViewPanel* GetInnerPanel() const; - void Remove(winrt::Windows::UI::Xaml::UIElement element) const; void UpdateClip(); @@ -86,7 +79,7 @@ struct ViewPanel : winrt::Windows::UI::Xaml::Controls::PanelT // Child Elements winrt::Windows::UI::Xaml::Controls::Border m_border { nullptr }; - winrt::Windows::UI::Xaml::UIElement m_innerElement { nullptr }; + bool m_hasOuterBorder; private: static void VisualPropertyChanged(winrt::Windows::UI::Xaml::DependencyObject sender, winrt::Windows::UI::Xaml::DependencyPropertyChangedEventArgs e); diff --git a/RNWCPP/ReactUWP/Views/ViewViewManager.cpp b/RNWCPP/ReactUWP/Views/ViewViewManager.cpp index 92ef37be604..6ec0dbfbe72 100644 --- a/RNWCPP/ReactUWP/Views/ViewViewManager.cpp +++ b/RNWCPP/ReactUWP/Views/ViewViewManager.cpp @@ -41,9 +41,17 @@ class ViewShadowNode : public ShadowNodeBase public: ViewShadowNode() = default; + bool ShouldUpdateView(bool isControl, bool hasOuterBorder) + { + return (IsControl() != isControl) || (HasOuterBorder() != hasOuterBorder); + } + bool IsControl() { return m_isControl; } void IsControl(bool isControl) { m_isControl = isControl; } + bool HasOuterBorder() { return m_hasOuterBorder; } + void HasOuterBorder(bool hasOuterBorder) { m_hasOuterBorder = hasOuterBorder; } + bool EnableFocusRing() { return m_enableFocusRing; } void EnableFocusRing(bool enable) { @@ -122,26 +130,41 @@ class ViewShadowNode : public ShadowNodeBase TabIndex(TabIndex()); } - ViewPanel* GetViewPanel() + winrt::com_ptr GetViewPanel() { + XamlView current = m_view; + if (IsControl()) { - auto contentControl = m_view.as(); - return contentControl.Content().as().get(); + auto control = m_view.as(); + current = control.Content().as(); } - else + + if (HasOuterBorder()) { - return m_view.as().get(); + auto border = current.try_as(); + current = border.Child().try_as(); } + + auto panel = current.try_as(); + assert(panel != nullptr); + + return std::move(panel); } winrt::impl::com_ref GetControl() { - return IsControl() ? m_view.as() : nullptr; + auto control = m_view.try_as(); + auto panel = m_view.try_as(); + auto border = m_view.try_as(); + + return IsControl() ? m_view.as() : nullptr; } private: bool m_isControl = false; + bool m_hasOuterBorder = false; + bool m_enableFocusRing = true; bool m_onClick = false; int32_t m_tabIndex = std::numeric_limits::max(); @@ -199,34 +222,27 @@ XamlView ViewViewManager::CreateViewPanel(int64_t tag) XamlView ViewViewManager::CreateViewControl(int64_t tag) { - // Create the ViewPanel which will be nested under the ContentControl - XamlView newViewPanelXamlView(ViewPanel::Create().as()); - auto panel = newViewPanelXamlView.as(); - panel->VerticalAlignment(winrt::VerticalAlignment::Top); - - // Create the ContentControl as the outer/containing element, nest the ViewPanel, set default properties + // Create the ViewControl as the outer/containing element, nest the ViewPanel, set default properties auto contentControlPtr = ViewControl::Create(); - auto contentControl = contentControlPtr.as(); - contentControl.Content(newViewPanelXamlView); // TODO: Remove once existing clients stop using TouchableNativeFeedback.uwp - contentControl.Tapped([=](auto &&, auto &&args) + contentControlPtr->Tapped([=](auto &&, auto &&args) { DispatchEvent(tag, "topPress", std::move(folly::dynamic::object("target", tag))); args.Handled(true); }); - contentControl.GotFocus([=](auto &&, auto &&) + contentControlPtr->GotFocus([=](auto &&, auto &&) { DispatchEvent(tag, "topFocus", std::move(folly::dynamic::object("target", tag))); }); - contentControl.LostFocus([=](auto &&, auto &&) + contentControlPtr->LostFocus([=](auto &&, auto &&) { DispatchEvent(tag, "topBlur", std::move(folly::dynamic::object("target", tag))); }); - contentControl.KeyDown([=](auto &&, winrt::KeyRoutedEventArgs const& e) + contentControlPtr->KeyDown([=](auto &&, winrt::KeyRoutedEventArgs const& e) { if (e.Key() == winrt::VirtualKey::Enter || e.Key() == winrt::VirtualKey::Space) { @@ -262,7 +278,7 @@ XamlView ViewViewManager::CreateViewControl(int64_t tag) } }); - return contentControl.as(); + return contentControlPtr->try_as(); } XamlView ViewViewManager::CreateViewCore(int64_t tag) @@ -296,7 +312,7 @@ void ViewViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate, folly::dyna auto* pViewShadowNode = static_cast(nodeToUpdate); bool shouldBeControl = pViewShadowNode->IsControl(); - auto* pPanel = pViewShadowNode->GetViewPanel(); + auto pPanel = pViewShadowNode->GetViewPanel(); if (pPanel != nullptr) { for (auto& pair : reactDiffMap.items()) @@ -428,75 +444,116 @@ void ViewViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate, folly::dyna pPanel->FinalizeProperties(); - if (shouldBeControl != pViewShadowNode->IsControl()) - ReplaceView(pViewShadowNode, shouldBeControl); + TryUpdateView(pViewShadowNode, pPanel.get(), shouldBeControl); } -XamlView GetPanel(XamlView view) +void ViewViewManager::TryUpdateView(ViewShadowNode* pViewShadowNode, ViewPanel* pPanel, bool useControl) { - // If the view is a ContentControl then its content is the ViewPanel else it is a ViewPanel - winrt::ContentControl contentControl(nullptr); - if (view.try_as(contentControl)) - return contentControl.Content().as(); - else - return view; -} + auto instance = m_wkReactInstance.lock(); + if (instance == nullptr) + return; -void ViewViewManager::TransferProperties(XamlView oldView, XamlView newView) -{ - Super::TransferProperties(oldView, newView); + bool hasOuterBorder = pPanel->GetOuterBorder() != nullptr; - // Retrieve the ViewPanels for use in these transfers since they are the elements that take all the properties - XamlView oldPanel = GetPanel(oldView); - XamlView newPanel = GetPanel(newView); + // This short-circuits all of the update code when we have the same hierarchy + if (!pViewShadowNode->ShouldUpdateView(useControl, hasOuterBorder)) + return; - TransferProperty(oldPanel, newPanel, ViewPanel::BackgroundProperty()); - TransferProperty(oldPanel, newPanel, ViewPanel::BorderBrushProperty()); - TransferProperty(oldPanel, newPanel, ViewPanel::BorderThicknessProperty()); - TransferProperty(oldPanel, newPanel, ViewPanel::ClipChildrenProperty()); - TransferProperty(oldPanel, newPanel, ViewPanel::CornerRadiusProperty()); -} + // 1. Ensure we have the new 'root' and do the child replacement + // This is first to ensure that we can re-parent the Border or ViewPanel we already have + // 2. Transfer properties + // There are likely some complexities to handle here + // 3. Do any sub=parenting + // This means Panel under Border and/or Border under Control + // + // Questions + // + // - What How do we ensure the Border is released when no longer needed? + // - Can we really keep reusing the ViewPanel? Why didn't I do this before? -void ViewViewManager::ReplaceView(ViewShadowNode* pViewShadowNode, bool useControl) -{ - auto instance = m_wkReactInstance.lock(); - if (instance != nullptr) - { - int64_t tag = pViewShadowNode->m_tag; - // Create the ViewPanel we know we'll need either way - XamlView newXamlView(nullptr); + int64_t tag = pViewShadowNode->m_tag; - // If we need a Control then create a ContentControl and nest the ViewPanel inside it - if (useControl) - newXamlView = CreateViewControl(tag); - // Else just use the ViewPanel (already created) - else - newXamlView = CreateViewPanel(tag); + XamlView oldXamlView(pViewShadowNode->GetView()); + XamlView newXamlView(nullptr); - XamlView oldXamlView(pViewShadowNode->GetView()); + // 1. Either create the new Control if needed or cleanup the old one if no longer needed + if (useControl) + { + newXamlView = pViewShadowNode->GetControl().try_as(); + if (newXamlView == nullptr) + newXamlView = CreateViewControl(tag); + } + else if (pViewShadowNode->IsControl()) + { + pViewShadowNode->GetControl()->Content(nullptr); + } - // Transfer properties from old XamlView to the new one - TransferProperties(oldXamlView, newXamlView); + // 2. If need outer border decide if it's our new root, else clean up old outer border + if (hasOuterBorder) + { + if (!useControl) + newXamlView = pPanel->GetOuterBorder().try_as(); + } + else if (pViewShadowNode->HasOuterBorder()) + { + winrt::Border outerBorder = pPanel->GetOuterBorder(); + if (outerBorder.Child() != nullptr) + outerBorder.Child(pPanel->try_as()); + } - // Update the ShadowNode with the new XamlView - pViewShadowNode->ReplaceView(newXamlView); - pViewShadowNode->IsControl(useControl); - pViewShadowNode->RefreshProperties(); + // 3. Determine if the ViewPanel itself should be our root + if (!useControl && !hasOuterBorder) + newXamlView = pPanel->try_as(); - // Inform the parent ShadowNode of this change so the hierarchy can be updated - int64_t parentTag = pViewShadowNode->GetParent(); - auto host = static_cast(instance->NativeUIManager())->getHost(); - auto *pParentNode = static_cast(host->FindShadowNodeForTag(parentTag)); - if (pParentNode != nullptr) - pParentNode->ReplaceChild(oldXamlView, newXamlView); + // ASSERT: One of the three scenarios should be true and we should have a root to use + assert(newXamlView != nullptr); - // Since we transferred properties to the new view we need to make the call to finalize - pViewShadowNode->GetViewPanel()->FinalizeProperties(); + // Transfer properties from old XamlView to the new one + TransferProperties(oldXamlView, newXamlView); - // Inform the NativeUIManager of this change so the yoga layout can be updated - static_cast(instance->NativeUIManager())->ReplaceView(*pViewShadowNode); - } + // Since we transferred properties to the new view we need to make the call to finalize + pPanel->FinalizeProperties(); + + // Update the meta-data in the shadow node + pViewShadowNode->IsControl(useControl); + pViewShadowNode->HasOuterBorder(hasOuterBorder); + + // If we need to change the root of our view, do it now + if (oldXamlView != newXamlView) + { + // Inform the parent ShadowNode of this change so the hierarchy can be updated + int64_t parentTag = pViewShadowNode->GetParent(); + auto host = static_cast(instance->NativeUIManager())->getHost(); + auto *pParentNode = static_cast(host->FindShadowNodeForTag(parentTag)); + if (pParentNode != nullptr) + pParentNode->ReplaceChild(oldXamlView, newXamlView); + + // Update the ShadowNode with the new XamlView + pViewShadowNode->ReplaceView(newXamlView); + pViewShadowNode->RefreshProperties(); + + // Inform the NativeUIManager of this change so the yoga layout can be updated + static_cast(instance->NativeUIManager())->ReplaceView(*pViewShadowNode); + } + + // Ensure parenting is setup properly + auto visualRoot = pPanel->try_as(); + + if (hasOuterBorder) + { + winrt::Border outerBorder = pPanel->GetOuterBorder(); + if (outerBorder.Child() == nullptr) + outerBorder.Child(pPanel->try_as()); + + visualRoot = outerBorder; + } + + if (useControl) + { + // TODO NOW: auto control = pViewShadowNode->GetControl(); + pViewShadowNode->GetControl()->Content(visualRoot); + } } void ViewViewManager::SetLayoutProps(ShadowNodeBase& nodeToUpdate, XamlView viewToUpdate, float left, float top, float width, float height) @@ -506,7 +563,7 @@ void ViewViewManager::SetLayoutProps(ShadowNodeBase& nodeToUpdate, XamlView view auto* pViewShadowNode = static_cast(&nodeToUpdate); if (pViewShadowNode->IsControl()) { - auto* pPanel = pViewShadowNode->GetViewPanel(); + auto pPanel = pViewShadowNode->GetViewPanel(); pPanel->Width(width); pPanel->Height(height); } diff --git a/RNWCPP/ReactUWP/Views/ViewViewManager.h b/RNWCPP/ReactUWP/Views/ViewViewManager.h index 4e82af80082..59eeec4b2f1 100644 --- a/RNWCPP/ReactUWP/Views/ViewViewManager.h +++ b/RNWCPP/ReactUWP/Views/ViewViewManager.h @@ -8,6 +8,7 @@ namespace react { namespace uwp { class ViewShadowNode; +struct ViewPanel; class ViewViewManager : public FrameworkElementViewManager { @@ -28,8 +29,7 @@ class ViewViewManager : public FrameworkElementViewManager protected: XamlView CreateViewCore(int64_t tag) override; - void ReplaceView(ViewShadowNode* viewShadowNode, bool useControl); - void TransferProperties(XamlView oldView, XamlView newView) override; + void TryUpdateView(ViewShadowNode* viewShadowNode, ViewPanel* pPanel, bool useControl); private: void DispatchEvent(int64_t viewTag, std::string eventName, folly::dynamic&& eventData); diff --git a/RNWCPP/Universal.SampleApp/view.uwp.js b/RNWCPP/Universal.SampleApp/view.uwp.js new file mode 100644 index 00000000000..1d6311563f4 --- /dev/null +++ b/RNWCPP/Universal.SampleApp/view.uwp.js @@ -0,0 +1,114 @@ +/** + * Sample React Native App + * https://github.com/facebook/react-native + * @flow + */ + +import React, { Component } from 'react'; +import { + ActivityIndicator, + AppRegistry, + ScrollView, + StyleSheet, + Switch, + Text, + TextInput, + View, +} from 'react-native'; +import { + CheckBox, + DatePicker, + Picker, +} from 'react-native-windows'; + +export default class Bootstrap extends Component { + constructor(props) { + super(props); + this.state = { focusable: true, hasBorder: false, radius: 0 }; + } + + render() { + return ( + + + this.setState({ focusable: value })} + checked={this.state.focusable} /> + acceptsKeyboardFocus + + this.setState({ hasBorder: value })} + checked={this.state.hasBorder} /> + hasBorder + + + The text! + + + ); + } + + fullrender() { + return ( + + + this.setState({ focusable: value })} + checked={this.state.focusable} /> + acceptsKeyboardFocus + + + TEXT + + + + + + + + + + + + + + + + + + + + + + type nothing ... + + + + ); + } +}; + +const styles = StyleSheet.create({ + noBorder: { + padding: 15, + backgroundColor: 'orange' + }, + innerBorder: { + padding: 15, + backgroundColor: 'lime', + borderColor: 'navy', + borderWidth: 1, + }, + outerBorder: { + padding: 15, + backgroundColor: 'pink', + borderColor: 'crimson', + borderWidth: 1, + borderRadius: 5, + }, +}); + +AppRegistry.registerComponent('Bootstrap', () => Bootstrap); From 95e5f1df3cae60c9e2268ab1d8c3b45f5b4cfeb9 Mon Sep 17 00:00:00 2001 From: Randy Flynn Date: Fri, 19 Apr 2019 18:09:25 -0700 Subject: [PATCH 03/10] Remove debugging code. Update view sample to drive three scenarios. --- RNWCPP/ReactUWP/Views/ViewViewManager.cpp | 4 - RNWCPP/Universal.SampleApp/view.uwp.js | 89 +++++++++++++++-------- 2 files changed, 58 insertions(+), 35 deletions(-) diff --git a/RNWCPP/ReactUWP/Views/ViewViewManager.cpp b/RNWCPP/ReactUWP/Views/ViewViewManager.cpp index 6ec0dbfbe72..a8db243d1e9 100644 --- a/RNWCPP/ReactUWP/Views/ViewViewManager.cpp +++ b/RNWCPP/ReactUWP/Views/ViewViewManager.cpp @@ -154,10 +154,6 @@ class ViewShadowNode : public ShadowNodeBase winrt::impl::com_ref GetControl() { - auto control = m_view.try_as(); - auto panel = m_view.try_as(); - auto border = m_view.try_as(); - return IsControl() ? m_view.as() : nullptr; } diff --git a/RNWCPP/Universal.SampleApp/view.uwp.js b/RNWCPP/Universal.SampleApp/view.uwp.js index 1d6311563f4..b1bc3abe981 100644 --- a/RNWCPP/Universal.SampleApp/view.uwp.js +++ b/RNWCPP/Universal.SampleApp/view.uwp.js @@ -24,24 +24,71 @@ import { export default class Bootstrap extends Component { constructor(props) { super(props); - this.state = { focusable: true, hasBorder: false, radius: 0 }; + this.state = { focusable: true, hasBorder: true, radius: true }; } render() { + styles = StyleSheet.create({ + noBorder: { + margin: 20, + padding: 15, + backgroundColor: 'orange', + borderRadius: 0, + }, + innerBorder: { + margin: 20, + padding: 15, + backgroundColor: 'lime', + borderColor: 'navy', + borderWidth: 1, + borderRadius: 0, + }, + outerBorder: { + margin: 20, + padding: 15, + backgroundColor: 'pink', + borderColor: 'crimson', + borderWidth: 1, + borderRadius: 10, + }, + radial: { + margin: 20, + padding: 15, + backgroundColor: 'magenta', + borderRadius: 10, + }, + }); + return ( - + + + + this.setState({ focusable: value })} + checked={this.state.focusable} /> + acceptsKeyboardFocus + - this.setState({ focusable: value })} - checked={this.state.focusable} /> - acceptsKeyboardFocus + + this.setState({ hasBorder: value })} + checked={this.state.hasBorder} /> + hasBorder + - this.setState({ hasBorder: value })} - checked={this.state.hasBorder} /> - hasBorder + + this.setState({ radius: value })} + checked={this.state.radius} /> + hasRadius + - + The text! @@ -91,24 +138,4 @@ export default class Bootstrap extends Component { } }; -const styles = StyleSheet.create({ - noBorder: { - padding: 15, - backgroundColor: 'orange' - }, - innerBorder: { - padding: 15, - backgroundColor: 'lime', - borderColor: 'navy', - borderWidth: 1, - }, - outerBorder: { - padding: 15, - backgroundColor: 'pink', - borderColor: 'crimson', - borderWidth: 1, - borderRadius: 5, - }, -}); - AppRegistry.registerComponent('Bootstrap', () => Bootstrap); From 16105675a91bc7ffcfb5f202a6ac58028a79c737 Mon Sep 17 00:00:00 2001 From: Randy Flynn Date: Wed, 24 Apr 2019 11:48:48 -0700 Subject: [PATCH 04/10] Remove TODO NOW comment. --- RNWCPP/ReactUWP/Views/ViewViewManager.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/RNWCPP/ReactUWP/Views/ViewViewManager.cpp b/RNWCPP/ReactUWP/Views/ViewViewManager.cpp index 8849335b666..71afb8d2076 100644 --- a/RNWCPP/ReactUWP/Views/ViewViewManager.cpp +++ b/RNWCPP/ReactUWP/Views/ViewViewManager.cpp @@ -553,10 +553,7 @@ void ViewViewManager::TryUpdateView(ViewShadowNode* pViewShadowNode, ViewPanel* } if (useControl) - { - // TODO NOW: auto control = pViewShadowNode->GetControl(); pViewShadowNode->GetControl()->Content(visualRoot); - } } void ViewViewManager::SetLayoutProps(ShadowNodeBase& nodeToUpdate, XamlView viewToUpdate, float left, float top, float width, float height) From 4b718b3a9d9cb99100cc1b47ab6db7a3f8915702 Mon Sep 17 00:00:00 2001 From: Randy Flynn Date: Mon, 13 May 2019 16:54:13 -0700 Subject: [PATCH 05/10] Working version of BatchingUIManager. Right now it takes over for the UIManager always though, and that will need to be fixed. --- .../Modules/UIManagerModule.cpp | 213 +++++++++++++++++- .../Modules/UIManagerModule.h | 45 +++- 2 files changed, 244 insertions(+), 14 deletions(-) diff --git a/vnext/ReactWindowsCore/Modules/UIManagerModule.cpp b/vnext/ReactWindowsCore/Modules/UIManagerModule.cpp index b148231a869..bba885ea166 100644 --- a/vnext/ReactWindowsCore/Modules/UIManagerModule.cpp +++ b/vnext/ReactWindowsCore/Modules/UIManagerModule.cpp @@ -368,16 +368,6 @@ void UIManager::onBatchComplete() m_nativeUIManager->onBatchComplete(); } -UIManagerModule::UIManagerModule(std::shared_ptr&& manager) - : m_manager(std::move(manager)) -{ -} - -std::string UIManagerModule::getName() -{ - return "UIManager"; -} - int64_t UIManager::AddMeasuredRootView(IReactRootView* rootView) { auto tag = m_nextRootTag; @@ -424,6 +414,16 @@ ShadowNode& UIManager::GetShadowNodeForTag(int64_t tag) return m_nodeRegistry.getNode(tag); } +UIManagerModule::UIManagerModule(std::shared_ptr&& manager) + : m_manager(std::move(manager)) +{ +} + +std::string UIManagerModule::getName() +{ + return "UIManager"; +} + std::map UIManagerModule::getConstants() { std::map constants {}; @@ -496,14 +496,203 @@ std::vector UIManagerModule::getMeth }; } +BatchingUIManager::BatchingUIManager(std::vector>&& viewManagers, INativeUIManager* nativeManager) + : UIManager(std::move(viewManagers), nativeManager) +{ + m_queue = std::make_unique>>(1024); +} + +void BatchingUIManager::onBatchComplete() +{ + std::function func; + while (m_queue->read(func)) { + func(); + } + + UIManager::onBatchComplete(); +} + +BatchingUIManagerModule::BatchingUIManagerModule(std::shared_ptr&& manager) + : m_manager(std::move(manager)) +{ +} + +std::string BatchingUIManagerModule::getName() +{ + return "UIManager"; +} + +std::map BatchingUIManagerModule::getConstants() +{ + std::map constants {}; + + m_manager->populateViewManagerConstants(constants); + + return constants; +} + +void BatchingUIManager::removeRootView(folly::dynamic&& args) +{ + auto manager = shared_from_this(); + m_queue->write([manager, args]() + { + manager->removeRootView(jsArgAsInt(args, 0)); + }); +} + +void BatchingUIManager::createView(folly::dynamic&& args) +{ + auto manager = shared_from_this(); + m_queue->write([manager, args]() + { + auto arg3 = jsArgAsDynamic(args, 3); + static_cast(manager.get())->createView(jsArgAsInt(args, 0), jsArgAsString(args, 1), jsArgAsInt(args, 2), std::move(arg3)); + }); +} + +void BatchingUIManager::setChildren(folly::dynamic&& args) +{ + auto manager = shared_from_this(); + m_queue->write([manager, args]() + { + auto arg1 = jsArgAsArray(args, 1); + static_cast(manager.get())->setChildren(jsArgAsInt(args, 0), std::move(arg1)); + }); +} + +void BatchingUIManager::updateView(folly::dynamic&& args) +{ + auto manager = shared_from_this(); + m_queue->write([manager, args]() + { + auto arg2 = jsArgAsDynamic(args, 2); + static_cast(manager.get())->updateView(jsArgAsInt(args, 0), jsArgAsString(args, 1), std::move(arg2)); + }); +} + +void BatchingUIManager::removeSubviewsFromContainerWithID(folly::dynamic&& args) +{ + auto manager = shared_from_this(); + m_queue->write([manager, args]() + { + static_cast(manager.get())->removeSubviewsFromContainerWithID(jsArgAsInt(args, 0)); + }); +} + +void BatchingUIManager::manageChildren(folly::dynamic&& args) +{ + auto manager = shared_from_this(); + m_queue->write([manager, args]() + { + auto arg1 = jsArgAsDynamic(args, 1); + auto arg2 = jsArgAsDynamic(args, 2); + auto arg3 = jsArgAsDynamic(args, 3); + auto arg4 = jsArgAsDynamic(args, 4); + auto arg5 = jsArgAsDynamic(args, 5); + static_cast(manager.get())->manageChildren(jsArgAsInt(args, 0), arg1, arg2, arg3, arg4, arg5); + }); +} + +void BatchingUIManager::dispatchViewManagerCommand(folly::dynamic&& args) +{ + auto manager = shared_from_this(); + m_queue->write([manager, args]() + { + auto arg2 = jsArgAsDynamic(args, 2); + static_cast(manager.get())->dispatchViewManagerCommand(jsArgAsInt(args, 0), jsArgAsInt(args, 1), std::move(arg2)); + }); +} + +void BatchingUIManager::replaceExistingNonRootView(folly::dynamic&& args) +{ + auto manager = shared_from_this(); + m_queue->write([manager, args]() + { + static_cast(manager.get())->replaceExistingNonRootView(jsArgAsInt(args, 0), jsArgAsInt(args, 1)); + }); +} + +void BatchingUIManager::measure(folly::dynamic&& args, facebook::xplat::module::CxxModule::Callback cb) +{ + auto manager = shared_from_this(); + m_queue->write([manager, args, cb]() + { + static_cast(manager.get())->measure(jsArgAsInt(args, 0), cb); + }); +} + +std::vector BatchingUIManagerModule::getMethods() +{ + auto manager = std::static_pointer_cast(m_manager); + return + { + Method("getConstantsForViewManager", [manager](dynamic argsJson) -> dynamic + { + auto args = folly::parseJson(argsJson.asString()); + return manager->getConstantsForViewManager(jsArgAsString(args, 0)); + }, SyncTag), + Method("removeRootView", [manager](dynamic args) + { + manager->removeRootView(std::move(args)); + }), + Method("createView", [manager](dynamic args) + { + manager->createView(std::move(args)); + }), + Method("configureNextLayoutAnimation", [manager](dynamic args, Callback cbSuccess, Callback cbError) + { + manager->configureNextLayoutAnimation(std::move(args), cbSuccess, cbError); + }, AsyncTag), + Method("setChildren", [manager](dynamic args) + { + manager->setChildren(std::move(args)); + }), + Method("updateView", [manager](dynamic args) + { + manager->updateView(std::move(args)); + }), + Method("removeSubviewsFromContainerWithID", [manager](dynamic args) + { + manager->removeSubviewsFromContainerWithID(std::move(args)); + }), + Method("manageChildren", [manager](dynamic args) + { + manager->manageChildren(std::move(args)); + }), + Method("replaceExistingNonRootView", [manager](dynamic args) + { + manager->replaceExistingNonRootView(std::move(args)); + }), + Method("dispatchViewManagerCommand", [manager](dynamic args) + { + manager->dispatchViewManagerCommand(std::move(args)); + }), + Method("measure", [manager](dynamic args, facebook::xplat::module::CxxModule::Callback cb) + { + manager->measure(std::move(args), cb); + }), + Method("setJSResponder", [](dynamic args) + { + // TODO: Implement? + //manager->setJSResponder(std::move(args)); + }), + Method("clearJSResponder", []() + { + // TODO: Implement? + //manager->clearJSResponder(); + }), + }; +} + shared_ptr createIUIManager(std::vector>&& viewManagers, INativeUIManager* nativeManager) { - return std::make_shared(std::move(viewManagers), nativeManager); + // TODO NOW: Ability to create batching version or not. + return std::make_shared(std::move(viewManagers), nativeManager); } std::unique_ptr createUIManagerModule(std::shared_ptr uimanager) { - return std::make_unique(std::move(uimanager)); + return std::make_unique(std::move(uimanager)); } } diff --git a/vnext/ReactWindowsCore/Modules/UIManagerModule.h b/vnext/ReactWindowsCore/Modules/UIManagerModule.h index 0db029b0acd..f24958fbf76 100644 --- a/vnext/ReactWindowsCore/Modules/UIManagerModule.h +++ b/vnext/ReactWindowsCore/Modules/UIManagerModule.h @@ -9,6 +9,8 @@ #include #include +#include + namespace facebook { namespace react { struct IReactRootView; @@ -23,10 +25,10 @@ class UIManager : public IUIManager, INativeUIManagerHost void RegisterRootView(IReactRootView* rootView, int64_t rootViewTag, int64_t width, int64_t height); // IUIManager - folly::dynamic getConstantsForViewManager(const std::string& className) override; + folly::dynamic getConstantsForViewManager(const std::string& className) override; void populateViewManagerConstants(std::map& constants) override; void configureNextLayoutAnimation(folly::dynamic&& config, facebook::xplat::module::CxxModule::Callback success, facebook::xplat::module::CxxModule::Callback error) override; - int64_t AddMeasuredRootView(IReactRootView* rootView) override; + int64_t AddMeasuredRootView(IReactRootView* rootView) override; void removeRootView(int64_t rootViewTag) override; void createView(int64_t tag, std::string&& className, int64_t rootViewTag, folly::dynamic&& props) override; void setChildren(int64_t viewTag, folly::dynamic&& childrenTags) override; @@ -73,4 +75,43 @@ class UIManagerModule : public facebook::xplat::module::CxxModule std::shared_ptr m_manager; }; +class BatchingUIManager + : public UIManager + , public ::std::enable_shared_from_this +{ +public: + BatchingUIManager(std::vector>&& viewManagers, INativeUIManager* nativeManager); + virtual ~BatchingUIManager() noexcept {} + + // TODO NOW: Should these be named differently? Should there be a single function? + void removeRootView(folly::dynamic&& args); + void createView(folly::dynamic&& args); + void setChildren(folly::dynamic&& args); + void updateView(folly::dynamic&& args); + void removeSubviewsFromContainerWithID(folly::dynamic&& args); + void manageChildren(folly::dynamic&& args); + void dispatchViewManagerCommand(folly::dynamic&& args); + void replaceExistingNonRootView(folly::dynamic&& args); + void measure(folly::dynamic&& args, facebook::xplat::module::CxxModule::Callback cb); + void configureNextLayoutAnimation(folly::dynamic&& args, facebook::xplat::module::CxxModule::Callback success, facebook::xplat::module::CxxModule::Callback error); + + void onBatchComplete() override; + + std::shared_ptr>> m_queue; +}; + +class BatchingUIManagerModule : public facebook::xplat::module::CxxModule +{ +public: + BatchingUIManagerModule(std::shared_ptr&& manager); + + // CxxModule + std::string getName() override; + std::map getConstants() override; + std::vector getMethods() override; + +private: + std::shared_ptr m_manager; +}; + } } From 2edd70c40a0ca28e80243fcbbf38faed1d4bbc67 Mon Sep 17 00:00:00 2001 From: Randy Flynn Date: Wed, 15 May 2019 13:31:16 -0700 Subject: [PATCH 06/10] Separate Batching components into own file. Temporarily include diagnostic output (which will be removed in later check-in). --- vnext/ReactUWP/Base/UwpReactInstance.cpp | 6 +- .../Threading/UIMessageQueueThread.cpp | 6 + vnext/ReactWindowsCore/IUIManager.h | 3 + .../Modules/BatchingUIManagerModule.cpp | 237 ++++++++++++++++++ .../Modules/BatchingUIManagerModule.h | 60 +++++ .../Modules/UIManagerModule.cpp | 193 +------------- .../Modules/UIManagerModule.h | 41 --- .../ReactWindowsCore/ReactWindowsCore.vcxproj | 2 + .../ReactWindowsCore.vcxproj.filters | 6 + 9 files changed, 319 insertions(+), 235 deletions(-) create mode 100644 vnext/ReactWindowsCore/Modules/BatchingUIManagerModule.cpp create mode 100644 vnext/ReactWindowsCore/Modules/BatchingUIManagerModule.h diff --git a/vnext/ReactUWP/Base/UwpReactInstance.cpp b/vnext/ReactUWP/Base/UwpReactInstance.cpp index bfb7978a966..85f707d1def 100644 --- a/vnext/ReactUWP/Base/UwpReactInstance.cpp +++ b/vnext/ReactUWP/Base/UwpReactInstance.cpp @@ -52,7 +52,7 @@ #include #include #include -#include +#include #include #include #include @@ -125,7 +125,7 @@ REACTWINDOWS_API_(std::shared_ptr) CreateUIManager( viewManagers.push_back(std::make_unique(instance)); // Create UIManager, passing in ViewManagers - return createIUIManager(std::move(viewManagers), new NativeUIManager()); + return createBatchingUIManager(std::move(viewManagers), new NativeUIManager()); } UwpReactInstance::UwpReactInstance( @@ -150,7 +150,7 @@ std::vector GetModules( modules.emplace_back( "UIManager", - [uiManager = std::move(uiManager)]() { return facebook::react::createUIManagerModule(uiManager); }, + [uiManager = std::move(uiManager)]() { return facebook::react::createBatchingUIManagerModule(uiManager); }, messageQueue); modules.emplace_back( diff --git a/vnext/ReactUWP/Threading/UIMessageQueueThread.cpp b/vnext/ReactUWP/Threading/UIMessageQueueThread.cpp index 58bd0aca21b..7b00b1ddc3d 100644 --- a/vnext/ReactUWP/Threading/UIMessageQueueThread.cpp +++ b/vnext/ReactUWP/Threading/UIMessageQueueThread.cpp @@ -23,6 +23,12 @@ void UIMessageQueueThread::runOnQueue(std::function&& func) m_uiDispatcher.RunAsync( winrt::Windows::UI::Core::CoreDispatcherPriority::Normal, [func = std::move(func)]() { + + char buffer[1024]; + static uint32_t cCalls = 0; + _snprintf_s(buffer, _countof(buffer), _TRUNCATE, "UIMessageQueueThread Calls: %u\r\n", ++cCalls); + OutputDebugStringA(buffer); + func(); }); } diff --git a/vnext/ReactWindowsCore/IUIManager.h b/vnext/ReactWindowsCore/IUIManager.h index b8b858f7e88..2669eb2f492 100644 --- a/vnext/ReactWindowsCore/IUIManager.h +++ b/vnext/ReactWindowsCore/IUIManager.h @@ -46,4 +46,7 @@ class IUIManager std::shared_ptr createIUIManager(std::vector>&& viewManagers, INativeUIManager* nativeManager); std::unique_ptr createUIManagerModule(std::shared_ptr uimanager); +std::shared_ptr createBatchingUIManager(std::vector>&& viewManagers, INativeUIManager* nativeManager); +std::unique_ptr createBatchingUIManagerModule(std::shared_ptr uimanager); + }} diff --git a/vnext/ReactWindowsCore/Modules/BatchingUIManagerModule.cpp b/vnext/ReactWindowsCore/Modules/BatchingUIManagerModule.cpp new file mode 100644 index 00000000000..9b5a900720e --- /dev/null +++ b/vnext/ReactWindowsCore/Modules/BatchingUIManagerModule.cpp @@ -0,0 +1,237 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "BatchingUIManagerModule.h" + +#include +#include +#include + +using namespace folly; +using namespace facebook::xplat; +using namespace std; + +namespace facebook { +namespace react { + +BatchingUIManager::BatchingUIManager(std::vector>&& viewManagers, INativeUIManager* nativeManager) + : UIManager(std::move(viewManagers), nativeManager) +{ + m_queue = std::make_unique>>(64000); +} + +void BatchingUIManager::onBatchComplete() +{ + static uint32_t cBatches = 0; + static uint32_t cCalls = 0; + uint32_t theseCalls = 0; + + std::function func; + while (m_queue->read(func)) { + func(); + ++theseCalls; + } + + cCalls += theseCalls; + char buffer[1024]; + _snprintf_s(buffer, _countof(buffer), _TRUNCATE, "BatchingUIManager Batches: %u Calls: %u (%u new)\r\n", ++cBatches, cCalls, theseCalls); + OutputDebugStringA(buffer); + + UIManager::onBatchComplete(); +} + +void BatchingUIManager::removeRootView(folly::dynamic&& args) +{ + auto manager = std::static_pointer_cast(shared_from_this()); + m_queue->write([manager, args]() + { + manager->removeRootView(jsArgAsInt(args, 0)); + }); +} + +void BatchingUIManager::configureNextLayoutAnimation(folly::dynamic&& args, facebook::xplat::module::CxxModule::Callback success, facebook::xplat::module::CxxModule::Callback error) +{ + auto manager = shared_from_this(); + m_queue->write([manager, args, success, error]() + { + auto config = jsArgAsDynamic(args, 3); + manager->configureNextLayoutAnimation(std::move(config), success, error); + }); +} + +void BatchingUIManager::createView(folly::dynamic&& args) +{ + auto manager = shared_from_this(); + m_queue->write([manager, args]() + { + auto arg3 = jsArgAsDynamic(args, 3); + static_cast(manager.get())->createView(jsArgAsInt(args, 0), jsArgAsString(args, 1), jsArgAsInt(args, 2), std::move(arg3)); + }); +} + +void BatchingUIManager::setChildren(folly::dynamic&& args) +{ + auto manager = shared_from_this(); + m_queue->write([manager, args]() + { + auto arg1 = jsArgAsArray(args, 1); + static_cast(manager.get())->setChildren(jsArgAsInt(args, 0), std::move(arg1)); + }); +} + +void BatchingUIManager::updateView(folly::dynamic&& args) +{ + auto manager = shared_from_this(); + m_queue->write([manager, args]() + { + auto arg2 = jsArgAsDynamic(args, 2); + static_cast(manager.get())->updateView(jsArgAsInt(args, 0), jsArgAsString(args, 1), std::move(arg2)); + }); +} + +void BatchingUIManager::removeSubviewsFromContainerWithID(folly::dynamic&& args) +{ + auto manager = shared_from_this(); + m_queue->write([manager, args]() + { + static_cast(manager.get())->removeSubviewsFromContainerWithID(jsArgAsInt(args, 0)); + }); +} + +void BatchingUIManager::manageChildren(folly::dynamic&& args) +{ + auto manager = shared_from_this(); + m_queue->write([manager, args]() + { + auto arg1 = jsArgAsDynamic(args, 1); + auto arg2 = jsArgAsDynamic(args, 2); + auto arg3 = jsArgAsDynamic(args, 3); + auto arg4 = jsArgAsDynamic(args, 4); + auto arg5 = jsArgAsDynamic(args, 5); + static_cast(manager.get())->manageChildren(jsArgAsInt(args, 0), arg1, arg2, arg3, arg4, arg5); + }); +} + +void BatchingUIManager::dispatchViewManagerCommand(folly::dynamic&& args) +{ + auto manager = shared_from_this(); + m_queue->write([manager, args]() + { + auto arg2 = jsArgAsDynamic(args, 2); + static_cast(manager.get())->dispatchViewManagerCommand(jsArgAsInt(args, 0), jsArgAsInt(args, 1), std::move(arg2)); + }); +} + +void BatchingUIManager::replaceExistingNonRootView(folly::dynamic&& args) +{ + auto manager = shared_from_this(); + m_queue->write([manager, args]() + { + static_cast(manager.get())->replaceExistingNonRootView(jsArgAsInt(args, 0), jsArgAsInt(args, 1)); + }); +} + +void BatchingUIManager::measure(folly::dynamic&& args, facebook::xplat::module::CxxModule::Callback cb) +{ + auto manager = shared_from_this(); + m_queue->write([manager, args, cb]() + { + static_cast(manager.get())->measure(jsArgAsInt(args, 0), cb); + }); +} + + +BatchingUIManagerModule::BatchingUIManagerModule(std::shared_ptr&& manager) + : m_manager(std::move(manager)) +{ +} + +std::string BatchingUIManagerModule::getName() +{ + return "UIManager"; +} + +std::map BatchingUIManagerModule::getConstants() +{ + std::map constants {}; + + m_manager->populateViewManagerConstants(constants); + + return constants; +} + +std::vector BatchingUIManagerModule::getMethods() +{ + auto manager = std::static_pointer_cast(m_manager); + return + { + Method("getConstantsForViewManager", [manager](dynamic argsJson) -> dynamic + { + auto args = folly::parseJson(argsJson.asString()); + return manager->getConstantsForViewManager(jsArgAsString(args, 0)); + }, SyncTag), + Method("removeRootView", [manager](dynamic args) + { + manager->removeRootView(std::move(args)); + }), + Method("createView", [manager](dynamic args) + { + manager->createView(std::move(args)); + }), + Method("configureNextLayoutAnimation", [manager](dynamic args, Callback cbSuccess, Callback cbError) + { + manager->configureNextLayoutAnimation(std::move(args), cbSuccess, cbError); + }, AsyncTag), + Method("setChildren", [manager](dynamic args) + { + manager->setChildren(std::move(args)); + }), + Method("updateView", [manager](dynamic args) + { + manager->updateView(std::move(args)); + }), + Method("removeSubviewsFromContainerWithID", [manager](dynamic args) + { + manager->removeSubviewsFromContainerWithID(std::move(args)); + }), + Method("manageChildren", [manager](dynamic args) + { + manager->manageChildren(std::move(args)); + }), + Method("replaceExistingNonRootView", [manager](dynamic args) + { + manager->replaceExistingNonRootView(std::move(args)); + }), + Method("dispatchViewManagerCommand", [manager](dynamic args) + { + manager->dispatchViewManagerCommand(std::move(args)); + }), + Method("measure", [manager](dynamic args, facebook::xplat::module::CxxModule::Callback cb) + { + manager->measure(std::move(args), cb); + }), + Method("setJSResponder", [](dynamic args) + { + // TODO: Implement? + //manager->setJSResponder(std::move(args)); + }), + Method("clearJSResponder", []() + { + // TODO: Implement? + //manager->clearJSResponder(); + }), + }; +} + +shared_ptr createBatchingUIManager(std::vector>&& viewManagers, INativeUIManager* nativeManager) +{ + return std::make_shared(std::move(viewManagers), nativeManager); +} + +std::unique_ptr createBatchingUIManagerModule(std::shared_ptr uimanager) +{ + return std::make_unique(std::move(uimanager)); +} + +} +} // namespace facebook::react diff --git a/vnext/ReactWindowsCore/Modules/BatchingUIManagerModule.h b/vnext/ReactWindowsCore/Modules/BatchingUIManagerModule.h new file mode 100644 index 00000000000..7a346f12830 --- /dev/null +++ b/vnext/ReactWindowsCore/Modules/BatchingUIManagerModule.h @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "UIManagerModule.h" + +#include + +#include +#include +#include + +#include +#include + +namespace facebook { namespace react { + +struct IReactRootView; +struct ShadowNode; + +class BatchingUIManager + : public UIManager + , public ::std::enable_shared_from_this +{ +public: + BatchingUIManager(std::vector>&& viewManagers, INativeUIManager* nativeManager); + virtual ~BatchingUIManager() noexcept {} + + void removeRootView(folly::dynamic&& args); + void createView(folly::dynamic&& args); + void setChildren(folly::dynamic&& args); + void updateView(folly::dynamic&& args); + void removeSubviewsFromContainerWithID(folly::dynamic&& args); + void manageChildren(folly::dynamic&& args); + void dispatchViewManagerCommand(folly::dynamic&& args); + void replaceExistingNonRootView(folly::dynamic&& args); + void measure(folly::dynamic&& args, facebook::xplat::module::CxxModule::Callback cb); + void configureNextLayoutAnimation(folly::dynamic&& args, facebook::xplat::module::CxxModule::Callback success, facebook::xplat::module::CxxModule::Callback error); + + void onBatchComplete() override; + + std::shared_ptr>> m_queue; +}; + +class BatchingUIManagerModule : public facebook::xplat::module::CxxModule +{ +public: + BatchingUIManagerModule(std::shared_ptr&& manager); + + // CxxModule + std::string getName() override; + std::map getConstants() override; + std::vector getMethods() override; + +private: + std::shared_ptr m_manager; +}; + +} } diff --git a/vnext/ReactWindowsCore/Modules/UIManagerModule.cpp b/vnext/ReactWindowsCore/Modules/UIManagerModule.cpp index bba885ea166..35283603582 100644 --- a/vnext/ReactWindowsCore/Modules/UIManagerModule.cpp +++ b/vnext/ReactWindowsCore/Modules/UIManagerModule.cpp @@ -496,203 +496,14 @@ std::vector UIManagerModule::getMeth }; } -BatchingUIManager::BatchingUIManager(std::vector>&& viewManagers, INativeUIManager* nativeManager) - : UIManager(std::move(viewManagers), nativeManager) -{ - m_queue = std::make_unique>>(1024); -} - -void BatchingUIManager::onBatchComplete() -{ - std::function func; - while (m_queue->read(func)) { - func(); - } - - UIManager::onBatchComplete(); -} - -BatchingUIManagerModule::BatchingUIManagerModule(std::shared_ptr&& manager) - : m_manager(std::move(manager)) -{ -} - -std::string BatchingUIManagerModule::getName() -{ - return "UIManager"; -} - -std::map BatchingUIManagerModule::getConstants() -{ - std::map constants {}; - - m_manager->populateViewManagerConstants(constants); - - return constants; -} - -void BatchingUIManager::removeRootView(folly::dynamic&& args) -{ - auto manager = shared_from_this(); - m_queue->write([manager, args]() - { - manager->removeRootView(jsArgAsInt(args, 0)); - }); -} - -void BatchingUIManager::createView(folly::dynamic&& args) -{ - auto manager = shared_from_this(); - m_queue->write([manager, args]() - { - auto arg3 = jsArgAsDynamic(args, 3); - static_cast(manager.get())->createView(jsArgAsInt(args, 0), jsArgAsString(args, 1), jsArgAsInt(args, 2), std::move(arg3)); - }); -} - -void BatchingUIManager::setChildren(folly::dynamic&& args) -{ - auto manager = shared_from_this(); - m_queue->write([manager, args]() - { - auto arg1 = jsArgAsArray(args, 1); - static_cast(manager.get())->setChildren(jsArgAsInt(args, 0), std::move(arg1)); - }); -} - -void BatchingUIManager::updateView(folly::dynamic&& args) -{ - auto manager = shared_from_this(); - m_queue->write([manager, args]() - { - auto arg2 = jsArgAsDynamic(args, 2); - static_cast(manager.get())->updateView(jsArgAsInt(args, 0), jsArgAsString(args, 1), std::move(arg2)); - }); -} - -void BatchingUIManager::removeSubviewsFromContainerWithID(folly::dynamic&& args) -{ - auto manager = shared_from_this(); - m_queue->write([manager, args]() - { - static_cast(manager.get())->removeSubviewsFromContainerWithID(jsArgAsInt(args, 0)); - }); -} - -void BatchingUIManager::manageChildren(folly::dynamic&& args) -{ - auto manager = shared_from_this(); - m_queue->write([manager, args]() - { - auto arg1 = jsArgAsDynamic(args, 1); - auto arg2 = jsArgAsDynamic(args, 2); - auto arg3 = jsArgAsDynamic(args, 3); - auto arg4 = jsArgAsDynamic(args, 4); - auto arg5 = jsArgAsDynamic(args, 5); - static_cast(manager.get())->manageChildren(jsArgAsInt(args, 0), arg1, arg2, arg3, arg4, arg5); - }); -} - -void BatchingUIManager::dispatchViewManagerCommand(folly::dynamic&& args) -{ - auto manager = shared_from_this(); - m_queue->write([manager, args]() - { - auto arg2 = jsArgAsDynamic(args, 2); - static_cast(manager.get())->dispatchViewManagerCommand(jsArgAsInt(args, 0), jsArgAsInt(args, 1), std::move(arg2)); - }); -} - -void BatchingUIManager::replaceExistingNonRootView(folly::dynamic&& args) -{ - auto manager = shared_from_this(); - m_queue->write([manager, args]() - { - static_cast(manager.get())->replaceExistingNonRootView(jsArgAsInt(args, 0), jsArgAsInt(args, 1)); - }); -} - -void BatchingUIManager::measure(folly::dynamic&& args, facebook::xplat::module::CxxModule::Callback cb) -{ - auto manager = shared_from_this(); - m_queue->write([manager, args, cb]() - { - static_cast(manager.get())->measure(jsArgAsInt(args, 0), cb); - }); -} - -std::vector BatchingUIManagerModule::getMethods() -{ - auto manager = std::static_pointer_cast(m_manager); - return - { - Method("getConstantsForViewManager", [manager](dynamic argsJson) -> dynamic - { - auto args = folly::parseJson(argsJson.asString()); - return manager->getConstantsForViewManager(jsArgAsString(args, 0)); - }, SyncTag), - Method("removeRootView", [manager](dynamic args) - { - manager->removeRootView(std::move(args)); - }), - Method("createView", [manager](dynamic args) - { - manager->createView(std::move(args)); - }), - Method("configureNextLayoutAnimation", [manager](dynamic args, Callback cbSuccess, Callback cbError) - { - manager->configureNextLayoutAnimation(std::move(args), cbSuccess, cbError); - }, AsyncTag), - Method("setChildren", [manager](dynamic args) - { - manager->setChildren(std::move(args)); - }), - Method("updateView", [manager](dynamic args) - { - manager->updateView(std::move(args)); - }), - Method("removeSubviewsFromContainerWithID", [manager](dynamic args) - { - manager->removeSubviewsFromContainerWithID(std::move(args)); - }), - Method("manageChildren", [manager](dynamic args) - { - manager->manageChildren(std::move(args)); - }), - Method("replaceExistingNonRootView", [manager](dynamic args) - { - manager->replaceExistingNonRootView(std::move(args)); - }), - Method("dispatchViewManagerCommand", [manager](dynamic args) - { - manager->dispatchViewManagerCommand(std::move(args)); - }), - Method("measure", [manager](dynamic args, facebook::xplat::module::CxxModule::Callback cb) - { - manager->measure(std::move(args), cb); - }), - Method("setJSResponder", [](dynamic args) - { - // TODO: Implement? - //manager->setJSResponder(std::move(args)); - }), - Method("clearJSResponder", []() - { - // TODO: Implement? - //manager->clearJSResponder(); - }), - }; -} - shared_ptr createIUIManager(std::vector>&& viewManagers, INativeUIManager* nativeManager) { - // TODO NOW: Ability to create batching version or not. - return std::make_shared(std::move(viewManagers), nativeManager); + return std::make_shared(std::move(viewManagers), nativeManager); } std::unique_ptr createUIManagerModule(std::shared_ptr uimanager) { - return std::make_unique(std::move(uimanager)); + return std::make_unique(std::move(uimanager)); } } diff --git a/vnext/ReactWindowsCore/Modules/UIManagerModule.h b/vnext/ReactWindowsCore/Modules/UIManagerModule.h index f24958fbf76..d9f50d895fb 100644 --- a/vnext/ReactWindowsCore/Modules/UIManagerModule.h +++ b/vnext/ReactWindowsCore/Modules/UIManagerModule.h @@ -9,8 +9,6 @@ #include #include -#include - namespace facebook { namespace react { struct IReactRootView; @@ -75,43 +73,4 @@ class UIManagerModule : public facebook::xplat::module::CxxModule std::shared_ptr m_manager; }; -class BatchingUIManager - : public UIManager - , public ::std::enable_shared_from_this -{ -public: - BatchingUIManager(std::vector>&& viewManagers, INativeUIManager* nativeManager); - virtual ~BatchingUIManager() noexcept {} - - // TODO NOW: Should these be named differently? Should there be a single function? - void removeRootView(folly::dynamic&& args); - void createView(folly::dynamic&& args); - void setChildren(folly::dynamic&& args); - void updateView(folly::dynamic&& args); - void removeSubviewsFromContainerWithID(folly::dynamic&& args); - void manageChildren(folly::dynamic&& args); - void dispatchViewManagerCommand(folly::dynamic&& args); - void replaceExistingNonRootView(folly::dynamic&& args); - void measure(folly::dynamic&& args, facebook::xplat::module::CxxModule::Callback cb); - void configureNextLayoutAnimation(folly::dynamic&& args, facebook::xplat::module::CxxModule::Callback success, facebook::xplat::module::CxxModule::Callback error); - - void onBatchComplete() override; - - std::shared_ptr>> m_queue; -}; - -class BatchingUIManagerModule : public facebook::xplat::module::CxxModule -{ -public: - BatchingUIManagerModule(std::shared_ptr&& manager); - - // CxxModule - std::string getName() override; - std::map getConstants() override; - std::vector getMethods() override; - -private: - std::shared_ptr m_manager; -}; - } } diff --git a/vnext/ReactWindowsCore/ReactWindowsCore.vcxproj b/vnext/ReactWindowsCore/ReactWindowsCore.vcxproj index bbd89fc612b..4e511b5d1b9 100644 --- a/vnext/ReactWindowsCore/ReactWindowsCore.vcxproj +++ b/vnext/ReactWindowsCore/ReactWindowsCore.vcxproj @@ -113,6 +113,7 @@ + @@ -133,6 +134,7 @@ + diff --git a/vnext/ReactWindowsCore/ReactWindowsCore.vcxproj.filters b/vnext/ReactWindowsCore/ReactWindowsCore.vcxproj.filters index 2c51054fc8f..85df48167eb 100644 --- a/vnext/ReactWindowsCore/ReactWindowsCore.vcxproj.filters +++ b/vnext/ReactWindowsCore/ReactWindowsCore.vcxproj.filters @@ -38,6 +38,9 @@ Modules + + Modules + @@ -125,6 +128,9 @@ + + Modules + From d9d4f151cecd706d91b8592d841673d5daa28413 Mon Sep 17 00:00:00 2001 From: Randy Flynn Date: Wed, 15 May 2019 13:45:09 -0700 Subject: [PATCH 07/10] Put tracking behind ifdefs. Fix whitespace so no change in UIManagerModule.h. --- vnext/ReactUWP/Threading/UIMessageQueueThread.cpp | 3 +++ .../ReactWindowsCore/Modules/BatchingUIManagerModule.cpp | 8 ++++++++ vnext/ReactWindowsCore/Modules/UIManagerModule.h | 4 ++-- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/vnext/ReactUWP/Threading/UIMessageQueueThread.cpp b/vnext/ReactUWP/Threading/UIMessageQueueThread.cpp index 7b00b1ddc3d..630f27d22b6 100644 --- a/vnext/ReactUWP/Threading/UIMessageQueueThread.cpp +++ b/vnext/ReactUWP/Threading/UIMessageQueueThread.cpp @@ -24,10 +24,13 @@ void UIMessageQueueThread::runOnQueue(std::function&& func) winrt::Windows::UI::Core::CoreDispatcherPriority::Normal, [func = std::move(func)]() { +//#define TRACK_UI_CALLS +#ifdef TRACK_UI_CALLS char buffer[1024]; static uint32_t cCalls = 0; _snprintf_s(buffer, _countof(buffer), _TRUNCATE, "UIMessageQueueThread Calls: %u\r\n", ++cCalls); OutputDebugStringA(buffer); +#endif func(); }); diff --git a/vnext/ReactWindowsCore/Modules/BatchingUIManagerModule.cpp b/vnext/ReactWindowsCore/Modules/BatchingUIManagerModule.cpp index 9b5a900720e..2e72fd7ec7b 100644 --- a/vnext/ReactWindowsCore/Modules/BatchingUIManagerModule.cpp +++ b/vnext/ReactWindowsCore/Modules/BatchingUIManagerModule.cpp @@ -22,20 +22,28 @@ BatchingUIManager::BatchingUIManager(std::vector>& void BatchingUIManager::onBatchComplete() { +//#define TRACK_QUEUE +#ifdef TRACK_QUEUE static uint32_t cBatches = 0; static uint32_t cCalls = 0; uint32_t theseCalls = 0; +#endif std::function func; while (m_queue->read(func)) { func(); + +#ifdef TRACK_QUEUE ++theseCalls; +#endif } +#ifdef TRACK_QUEUE cCalls += theseCalls; char buffer[1024]; _snprintf_s(buffer, _countof(buffer), _TRUNCATE, "BatchingUIManager Batches: %u Calls: %u (%u new)\r\n", ++cBatches, cCalls, theseCalls); OutputDebugStringA(buffer); +#endif UIManager::onBatchComplete(); } diff --git a/vnext/ReactWindowsCore/Modules/UIManagerModule.h b/vnext/ReactWindowsCore/Modules/UIManagerModule.h index d9f50d895fb..0db029b0acd 100644 --- a/vnext/ReactWindowsCore/Modules/UIManagerModule.h +++ b/vnext/ReactWindowsCore/Modules/UIManagerModule.h @@ -23,10 +23,10 @@ class UIManager : public IUIManager, INativeUIManagerHost void RegisterRootView(IReactRootView* rootView, int64_t rootViewTag, int64_t width, int64_t height); // IUIManager - folly::dynamic getConstantsForViewManager(const std::string& className) override; + folly::dynamic getConstantsForViewManager(const std::string& className) override; void populateViewManagerConstants(std::map& constants) override; void configureNextLayoutAnimation(folly::dynamic&& config, facebook::xplat::module::CxxModule::Callback success, facebook::xplat::module::CxxModule::Callback error) override; - int64_t AddMeasuredRootView(IReactRootView* rootView) override; + int64_t AddMeasuredRootView(IReactRootView* rootView) override; void removeRootView(int64_t rootViewTag) override; void createView(int64_t tag, std::string&& className, int64_t rootViewTag, folly::dynamic&& props) override; void setChildren(int64_t viewTag, folly::dynamic&& childrenTags) override; From 2d47a7a8a8ac50d95f5e472c1e9d50662c9a51f7 Mon Sep 17 00:00:00 2001 From: Randy Flynn Date: Fri, 24 May 2019 12:07:03 -0700 Subject: [PATCH 08/10] Use smaller queue size and empty it when full. --- .../Modules/BatchingUIManagerModule.cpp | 58 +++++++++++++------ .../Modules/BatchingUIManagerModule.h | 5 ++ 2 files changed, 45 insertions(+), 18 deletions(-) diff --git a/vnext/ReactWindowsCore/Modules/BatchingUIManagerModule.cpp b/vnext/ReactWindowsCore/Modules/BatchingUIManagerModule.cpp index 2e72fd7ec7b..2b048636dc0 100644 --- a/vnext/ReactWindowsCore/Modules/BatchingUIManagerModule.cpp +++ b/vnext/ReactWindowsCore/Modules/BatchingUIManagerModule.cpp @@ -17,16 +17,19 @@ namespace react { BatchingUIManager::BatchingUIManager(std::vector>&& viewManagers, INativeUIManager* nativeManager) : UIManager(std::move(viewManagers), nativeManager) { - m_queue = std::make_unique>>(64000); + m_queue = std::make_unique>>(2048); } -void BatchingUIManager::onBatchComplete() -{ -//#define TRACK_QUEUE +#define TRACK_QUEUE #ifdef TRACK_QUEUE static uint32_t cBatches = 0; static uint32_t cCalls = 0; - uint32_t theseCalls = 0; +#endif + +void BatchingUIManager::processQueue() +{ +#ifdef TRACK_QUEUE + uint32_t cTheseCalls = 0; #endif std::function func; @@ -34,24 +37,43 @@ void BatchingUIManager::onBatchComplete() func(); #ifdef TRACK_QUEUE - ++theseCalls; + ++cTheseCalls; #endif } #ifdef TRACK_QUEUE - cCalls += theseCalls; + cCalls += cTheseCalls; char buffer[1024]; - _snprintf_s(buffer, _countof(buffer), _TRUNCATE, "BatchingUIManager Batches: %u Calls: %u (%u new)\r\n", ++cBatches, cCalls, theseCalls); + _snprintf_s(buffer, _countof(buffer), _TRUNCATE, "BatchingUIManager Batches: %u Calls: %u (%u new)\r\n", ++cBatches, cCalls, cTheseCalls); OutputDebugStringA(buffer); #endif +} + +void BatchingUIManager::dispatchFunction(std::function func) +{ + // If the queue is full then dispatch all items in the queue first + if (this->m_queue->isFull()) + { +#ifdef TRACK_QUEUE + OutputDebugStringA("BatchingUIManager: Processing Full Queue ..."); +#endif + + processQueue(); + } + m_queue->write(func); +} + +void BatchingUIManager::onBatchComplete() +{ + processQueue(); UIManager::onBatchComplete(); } void BatchingUIManager::removeRootView(folly::dynamic&& args) { auto manager = std::static_pointer_cast(shared_from_this()); - m_queue->write([manager, args]() + dispatchFunction([manager, args]() { manager->removeRootView(jsArgAsInt(args, 0)); }); @@ -60,7 +82,7 @@ void BatchingUIManager::removeRootView(folly::dynamic&& args) void BatchingUIManager::configureNextLayoutAnimation(folly::dynamic&& args, facebook::xplat::module::CxxModule::Callback success, facebook::xplat::module::CxxModule::Callback error) { auto manager = shared_from_this(); - m_queue->write([manager, args, success, error]() + dispatchFunction([manager, args, success, error]() { auto config = jsArgAsDynamic(args, 3); manager->configureNextLayoutAnimation(std::move(config), success, error); @@ -70,7 +92,7 @@ void BatchingUIManager::configureNextLayoutAnimation(folly::dynamic&& args, face void BatchingUIManager::createView(folly::dynamic&& args) { auto manager = shared_from_this(); - m_queue->write([manager, args]() + dispatchFunction([manager, args]() { auto arg3 = jsArgAsDynamic(args, 3); static_cast(manager.get())->createView(jsArgAsInt(args, 0), jsArgAsString(args, 1), jsArgAsInt(args, 2), std::move(arg3)); @@ -80,7 +102,7 @@ void BatchingUIManager::createView(folly::dynamic&& args) void BatchingUIManager::setChildren(folly::dynamic&& args) { auto manager = shared_from_this(); - m_queue->write([manager, args]() + dispatchFunction([manager, args]() { auto arg1 = jsArgAsArray(args, 1); static_cast(manager.get())->setChildren(jsArgAsInt(args, 0), std::move(arg1)); @@ -90,7 +112,7 @@ void BatchingUIManager::setChildren(folly::dynamic&& args) void BatchingUIManager::updateView(folly::dynamic&& args) { auto manager = shared_from_this(); - m_queue->write([manager, args]() + dispatchFunction([manager, args]() { auto arg2 = jsArgAsDynamic(args, 2); static_cast(manager.get())->updateView(jsArgAsInt(args, 0), jsArgAsString(args, 1), std::move(arg2)); @@ -100,7 +122,7 @@ void BatchingUIManager::updateView(folly::dynamic&& args) void BatchingUIManager::removeSubviewsFromContainerWithID(folly::dynamic&& args) { auto manager = shared_from_this(); - m_queue->write([manager, args]() + dispatchFunction([manager, args]() { static_cast(manager.get())->removeSubviewsFromContainerWithID(jsArgAsInt(args, 0)); }); @@ -109,7 +131,7 @@ void BatchingUIManager::removeSubviewsFromContainerWithID(folly::dynamic&& args) void BatchingUIManager::manageChildren(folly::dynamic&& args) { auto manager = shared_from_this(); - m_queue->write([manager, args]() + dispatchFunction([manager, args]() { auto arg1 = jsArgAsDynamic(args, 1); auto arg2 = jsArgAsDynamic(args, 2); @@ -123,7 +145,7 @@ void BatchingUIManager::manageChildren(folly::dynamic&& args) void BatchingUIManager::dispatchViewManagerCommand(folly::dynamic&& args) { auto manager = shared_from_this(); - m_queue->write([manager, args]() + dispatchFunction([manager, args]() { auto arg2 = jsArgAsDynamic(args, 2); static_cast(manager.get())->dispatchViewManagerCommand(jsArgAsInt(args, 0), jsArgAsInt(args, 1), std::move(arg2)); @@ -133,7 +155,7 @@ void BatchingUIManager::dispatchViewManagerCommand(folly::dynamic&& args) void BatchingUIManager::replaceExistingNonRootView(folly::dynamic&& args) { auto manager = shared_from_this(); - m_queue->write([manager, args]() + dispatchFunction([manager, args]() { static_cast(manager.get())->replaceExistingNonRootView(jsArgAsInt(args, 0), jsArgAsInt(args, 1)); }); @@ -142,7 +164,7 @@ void BatchingUIManager::replaceExistingNonRootView(folly::dynamic&& args) void BatchingUIManager::measure(folly::dynamic&& args, facebook::xplat::module::CxxModule::Callback cb) { auto manager = shared_from_this(); - m_queue->write([manager, args, cb]() + dispatchFunction([manager, args, cb]() { static_cast(manager.get())->measure(jsArgAsInt(args, 0), cb); }); diff --git a/vnext/ReactWindowsCore/Modules/BatchingUIManagerModule.h b/vnext/ReactWindowsCore/Modules/BatchingUIManagerModule.h index 7a346f12830..1023e0b8d55 100644 --- a/vnext/ReactWindowsCore/Modules/BatchingUIManagerModule.h +++ b/vnext/ReactWindowsCore/Modules/BatchingUIManagerModule.h @@ -40,6 +40,11 @@ class BatchingUIManager void onBatchComplete() override; +private: + void dispatchFunction(std::function func); + void processQueue(); + +private: std::shared_ptr>> m_queue; }; From ef07f638f7e02e7d0bc2ede382609fc296d6c04d Mon Sep 17 00:00:00 2001 From: Randy Flynn Date: Fri, 24 May 2019 13:15:36 -0700 Subject: [PATCH 09/10] Port JSI changes from UIManager to BatchingUIManager. --- .../Modules/BatchingUIManagerModule.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/vnext/ReactWindowsCore/Modules/BatchingUIManagerModule.cpp b/vnext/ReactWindowsCore/Modules/BatchingUIManagerModule.cpp index 2b048636dc0..2d36f0b84b9 100644 --- a/vnext/ReactWindowsCore/Modules/BatchingUIManagerModule.cpp +++ b/vnext/ReactWindowsCore/Modules/BatchingUIManagerModule.cpp @@ -197,9 +197,19 @@ std::vector BatchingUIManagerModule: { Method("getConstantsForViewManager", [manager](dynamic argsJson) -> dynamic { - auto args = folly::parseJson(argsJson.asString()); + dynamic args; + if (argsJson.isString()) + { + args = folly::parseJson(argsJson.asString()); + } + else + { + // In JSI mode this is an array + assert(argsJson.isArray()); + args = argsJson; + } return manager->getConstantsForViewManager(jsArgAsString(args, 0)); - }, SyncTag), + }, SyncTag), Method("removeRootView", [manager](dynamic args) { manager->removeRootView(std::move(args)); From cec0e02c130fb69f250f3b3b984ae8f947417f45 Mon Sep 17 00:00:00 2001 From: Randy Flynn Date: Tue, 28 May 2019 14:00:03 -0700 Subject: [PATCH 10/10] Turn off queue tracking debug output. --- vnext/ReactWindowsCore/Modules/BatchingUIManagerModule.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vnext/ReactWindowsCore/Modules/BatchingUIManagerModule.cpp b/vnext/ReactWindowsCore/Modules/BatchingUIManagerModule.cpp index 2d36f0b84b9..b199ae010a0 100644 --- a/vnext/ReactWindowsCore/Modules/BatchingUIManagerModule.cpp +++ b/vnext/ReactWindowsCore/Modules/BatchingUIManagerModule.cpp @@ -20,7 +20,7 @@ BatchingUIManager::BatchingUIManager(std::vector>& m_queue = std::make_unique>>(2048); } -#define TRACK_QUEUE +//#define TRACK_QUEUE #ifdef TRACK_QUEUE static uint32_t cBatches = 0; static uint32_t cCalls = 0;