From dbf8aa8ad5caa78382d83fd1757788bb2cf55696 Mon Sep 17 00:00:00 2001 From: Jerome Laban Date: Fri, 17 Jul 2020 15:10:21 -0400 Subject: [PATCH] feat: Add support base for Skia on .NET Core BREAKING CHANGE: This PR makes many breaking changes in the WebAssembly target to enable the support for additional backends. --- .vsts-ci.yml | 15 +- build/PackageDiffIgnore.xml | 455 +- build/TestLocalBuild.CMD | 2 +- build/Uno.UI.Build.csproj | 119 +- build/Uno.WinUI.Lottie.nuspec | 17 + build/Uno.WinUI.RemoteControl.nuspec | 56 +- build/Uno.WinUI.Skia.Gtk.nuspec | 28 + build/Uno.WinUI.Skia.Gtk.props | 9 + build/Uno.WinUI.Skia.Gtk.targets | 7 + build/Uno.WinUI.Skia.Wpf.nuspec | 28 + build/Uno.WinUI.Skia.Wpf.props | 9 + build/Uno.WinUI.Skia.Wpf.targets | 7 + build/Uno.WinUI.WebAssembly.nuspec | 30 + build/Uno.WinUI.WebAssembly.props | 9 + build/Uno.WinUI.WebAssembly.targets | 7 + build/Uno.WinUI.nuspec | 102 +- build/ci/.azure-devops-windows.yml | 16 +- build/uno.winui.targets | 26 + .../Uno.UI.Lottie.Skia.csproj | 51 + .../Uno.UI.Lottie.Skia/WasmScripts/lottie.js | 14555 ++++++++++++++++ .../WasmScripts/uno-lottie.d.ts | 36 + .../WasmScripts/uno-lottie.js | 189 + .../Uno.UI.Lottie.Skia/ts/Uno.UI.Lottie.ts | 255 + .../Uno.UI.Lottie.Skia/ts/lottie-web.d.ts | 131 + src/AddIns/Uno.UI.Lottie.Skia/tsconfig.json | 15 + .../Uno.UI.Lottie.Wasm.csproj | 61 + .../Uno.UI.Lottie.Wasm/WasmScripts/lottie.js | 14555 ++++++++++++++++ .../WasmScripts/uno-lottie.d.ts | 36 + .../WasmScripts/uno-lottie.js | 189 + .../Uno.UI.Lottie.Wasm/ts/Uno.UI.Lottie.ts | 255 + .../Uno.UI.Lottie.Wasm/ts/lottie-web.d.ts | 131 + src/AddIns/Uno.UI.Lottie.Wasm/tsconfig.json | 15 + src/AddIns/Uno.UI.Lottie/Uno.UI.Lottie.csproj | 15 +- .../buildTransitive/Uno.UI.Lottie.targets | 16 + .../Uno.UI.MSAL.Skia/LinkerDefinition.xml | 3 + .../Uno.UI.MSAL.Skia/Uno.UI.MSAL.Skia.csproj | 58 + .../WasmScripts/uno-ui-msal.d.ts | 6 + .../WasmScripts/uno-ui-msal.js | 100 + src/AddIns/Uno.UI.MSAL.Skia/ts/MSAL.WebUI.ts | 120 + src/AddIns/Uno.UI.MSAL.Skia/tsconfig.json | 15 + .../Uno.UI.MSAL.Wasm/LinkerDefinition.xml | 3 + .../Uno.UI.MSAL.Wasm/Uno.UI.MSAL.Wasm.csproj | 71 + .../WasmScripts/uno-ui-msal.d.ts | 6 + .../WasmScripts/uno-ui-msal.js | 100 + src/AddIns/Uno.UI.MSAL.Wasm/ts/MSAL.WebUI.ts | 120 + src/AddIns/Uno.UI.MSAL.Wasm/tsconfig.json | 15 + src/AddIns/Uno.UI.MSAL/Uno.UI.MSAL.csproj | 99 +- .../buildTransitive/Uno.UI.MSAL.targets | 16 + src/Directory.Build.props | 8 +- src/Directory.Build.targets | 67 +- src/PlatformItemGroups.props | 42 +- src/SamplesApp/SamplesApp.Shared/App.xaml.cs | 2 + src/SamplesApp/SamplesApp.Skia.Gtk/Program.cs | 27 + .../Properties/launchSettings.json | 8 + .../SamplesApp.Skia.Gtk.csproj | 31 + src/SamplesApp/SamplesApp.Skia.WPF/App.config | 6 + src/SamplesApp/SamplesApp.Skia.WPF/App.xaml | 9 + .../SamplesApp.Skia.WPF/App.xaml.cs | 17 + .../SamplesApp.Skia.WPF/MainWindow.xaml | 10 + .../SamplesApp.Skia.WPF/MainWindow.xaml.cs | 35 + .../Properties/AssemblyInfo.cs | 55 + .../Properties/Resources.Designer.cs | 71 + .../Properties/Resources.resx | 117 + .../Properties/Settings.Designer.cs | 30 + .../Properties/Settings.settings | 7 + .../SamplesApp.Skia.WPF.csproj | 157 + .../SamplesApp.Skia/SamplesApp.Skia.csproj | 42 + .../SampleChooserViewModel.netstd.cs | 2 +- .../SampleChooserViewModel.skia.cs | 43 + .../UITests/Views/Controls/StarStackPanel.cs | 4 +- .../SamplesApp.UnitTests.Shared.projitems | 1 + .../SamplesApp.Wasm/LinkerConfig.xml | 1 - .../SamplesApp.Wasm/SamplesApp.Wasm.csproj | 23 +- .../UITests.Shared/Helpers/UWPViewHelper.cs | 2 +- .../AutoBorderStretchwithbottommargin.xaml.cs | 5 - .../AutoBorderStretchwithleftmargin.xaml.cs | 5 - .../AutoBorderStretchwithrightmargin.xaml.cs | 5 - .../AutoBorderStretchwithtopmargin.xaml.cs | 5 - .../BorderBottomwithmargins.xaml.cs | 5 - .../BorderCenteredwithmargins.xaml.cs | 6 - .../BorderTests/BorderLeftwithmargins.xaml.cs | 5 - .../BorderRightwithmargins.xaml.cs | 6 - .../BorderTests/BorderTopwithmargins.xaml.cs | 6 - .../BorderTests/Border_CornerRadius.xaml.cs | 6 - .../Border_CornerRadius_Alignments.xaml.cs | 5 - .../Border_CornerRadius_Binding.xaml.cs | 6 - .../Border_CornerRadius_with_Opacity.xaml.cs | 6 - .../BorderTests/Border_Simple.xaml.cs | 5 - .../Border_Simple_No_Background.xaml.cs | 5 - ...ith_Content_Border_With_Background.xaml.cs | 5 - ..._Simple_No_Background_With_TextBox.xaml.cs | 6 - .../Border_Simple_with_Opacity.xaml.cs | 5 - ...rder_Simple_with_Uniform_Thickness.xaml.cs | 8 - ..._Simple_with_non_Uniform_Thickness.xaml.cs | 6 - .../BorderTests/Circle.xaml.cs | 6 - .../NonUniformThicknessandRadius.xaml.cs | 8 - .../OnepxThicknessandRadius.xaml.cs | 8 - ...nepxThicknessandRadiusAndTextBlock.xaml.cs | 8 - .../BorderTests/Simple_with_Radius.xaml.cs | 5 - .../SimplewithNonUnifmormRadius.xaml.cs | 8 - ...niformThicknessandNonUniformRadius.xaml.cs | 8 - ...Uniform_Thickness_and_Large_Radius.xaml.cs | 8 - ...Uniform_Thickness_and_Small_Radius.xaml.cs | 8 - .../BorderTests/ZeroThickness.xaml.cs | 8 - .../ZeroThicknessWithRadius.xaml.cs | 8 - .../Button/Button_UseUWPDefaultStyles.xaml.cs | 2 +- .../ImageTests/Models/ImageFilePathModel.cs | 2 +- .../ScrollViewer_Padding.xaml.cs | 2 +- .../TextBlock_FontWeight_Dynamic.xaml.cs | 1 - .../BlankApp.Wasm/BlankApp.Wasm.csproj | 4 +- .../UnoXFQuickStart.Wasm.csproj | 1 - .../Wasm/UnoQuickStart.Wasm.csproj | 4 +- .../BindableTypeProvidersGenerationTask.cs | 4 +- .../RemoteControl/RemoteControlGenerator.cs | 4 +- .../XamlGenerator/XamlCodeGeneration.cs | 17 +- .../XamlFileGenerator.Reflection.cs | 1 + .../XamlGenerator/XamlFileGenerator.cs | 2 +- .../XamlGenerationTests.csproj | 2 +- src/Uno.CrossTargetting.props | 13 +- .../AssemblyInfo.cs | 15 + .../Interop/IJSObject.wasm.cs | 0 .../Interop/IJSObjectMetadata.wasm.cs | 0 .../Interop/JSObject.wasm.cs | 2 - .../Interop/JSObjectHandle.wasm.cs | 0 .../Interop/JSObjectMetadataProvider.wasm.cs | 0 .../Interop}/Runtime.wasm.cs | 3 - .../Interop/TSInteropMarshaller.wasm.cs | 0 .../Interop/TSInteropMessageAttribute.wasm.cs | 0 .../LinkerDefinition.Wasm.xml | 4 + .../Uno.Foundation.Runtime.Wasm.csproj | 53 + src/Uno.Foundation.Skia/AssemblyInfo.skia.cs | 3 + .../Uno.Foundation.Skia.csproj | 30 + .../Uno.Foundation.Wasm.csproj | 33 + src/Uno.Foundation/Eventing/EventActivity.cs | 19 - .../Eventing/EventDescriptor.cs | 43 - src/Uno.Foundation/Eventing/EventOpcode.cs | 21 - .../Eventing/EventProviderExtensions.cs | 228 - src/Uno.Foundation/Eventing/IEventProvider.cs | 41 - .../Eventing/IEventProviderFactory.cs | 17 - .../Eventing/NullEventProvider.cs | 29 - src/Uno.Foundation/Eventing/Tracing.cs | 39 - .../Extensions/RectExtensions.cs | 15 + src/Uno.Foundation/LinkerDefinition.Wasm.xml | 9 - src/Uno.Foundation/NotImplementedAttribute.cs | 12 +- src/Uno.Foundation/Uno.Foundation.csproj | 13 +- src/Uno.ReferenceImplComparer/Program.cs | 124 + .../Properties/launchSettings.json | 8 + .../Uno.ReferenceImplComparer.csproj | 13 + src/Uno.UI-Skia-only.slnf | 43 + src/Uno.UI-Wasm-only.slnf | 12 + .../LinkerDefinition.Wasm.xml | 0 .../Uno.UI.RemoteControl.Skia.csproj | 88 + .../LinkerDefinition.Wasm.xml | 4 + .../Uno.UI.RemoteControl.Wasm.csproj | 92 + .../Uno.UI.RemoteControl.csproj | 17 +- .../Uno.UI.RemoteControl.targets | 16 + .../GTK/GtkCoreWindowExtension.cs | 230 + src/Uno.UI.Runtime.Skia.Gtk/GTK/GtkHost.cs | 89 + .../GTK/UnoDrawingArea.cs | 60 + .../Uno.UI.Runtime.Skia.Gtk.csproj | 49 + .../Uno.UI.Runtime.Skia.Gtk.props | 8 + .../Uno.UI.Runtime.Skia.Gtk.targets | 21 + .../Uno.UI.Runtime.Skia.Wpf.csproj | 49 + src/Uno.UI.Runtime.Skia.Wpf/WPF/WpfHost.cs | 119 + .../Uno.UI.Runtime.Skia.Wpf.props | 7 + .../Uno.UI.Runtime.Skia.Wpf.targets | 20 + src/Uno.UI.Runtime.Wasm/AssemblyInfo.cs | 15 + src/Uno.UI.Runtime.Wasm/HtmlElement.cs | 20 + src/Uno.UI.Runtime.Wasm/LinkerDefinition.xml | 4 + src/Uno.UI.Runtime.Wasm/RuntimeAnchor.cs | 15 + .../Uno.UI.Runtime.Wasm.csproj | 68 + .../WasmHttpHandler.cs | 0 .../buildTransitive/Uno.UI.Runtime.Wasm.props | 7 + .../Uno.UI.Runtime.Wasm.targets | 42 + .../LinkerDefinition.Skia.xml | 3 + .../Uno.UI.RuntimeTests.Skia.csproj | 81 + .../LinkerDefinition.Wasm.xml | 3 + .../Uno.UI.RuntimeTests.Wasm.csproj | 94 + .../Given_HtmlElementAttribute.Wasm.cs | 29 + .../Uno.UI.RuntimeTests.csproj | 28 +- src/Uno.UI.Skia/AssemblyInfo.skia.cs | 4 + src/Uno.UI.Skia/LinkerDefinition.xml | 2 + src/Uno.UI.Skia/Uno.UI.Skia.csproj | 112 + .../Uno.UI.Toolkit.Skia.csproj | 72 + .../Uno.UI.Toolkit.Wasm.csproj | 75 + src/Uno.UI.Toolkit/RectExtensions.cs | 2 +- src/Uno.UI.Toolkit/Uno.UI.Toolkit.csproj | 9 + .../Uno.UI.Wasm.Tests.csproj | 5 +- src/Uno.UI.Wasm/LinkerDefinition.xml | 59 +- src/Uno.UI.Wasm/Uno.UI.Wasm.csproj | 71 +- src/Uno.UI.Wasm/WasmScripts/Uno.UI.js | 11 +- src/Uno.UI.Wasm/ts/HttpClient.ts | 2 +- .../ts/Interop/AsyncInteropHelper.ts | 4 +- src/Uno.UI.Wasm/ts/Interop/ManagedObject.ts | 2 +- src/Uno.UI.sln | 1038 ++ src/Uno.UI/AssemblyInfo.cs | 3 + .../Extensions/ViewExtensions.wasmnet.cs | 2 +- .../{ViewHelper.net.cs => ViewHelper.cs} | 4 +- src/Uno.UI/Extensions/ViewHelper.wasm.cs | 34 - src/Uno.UI/FeatureConfiguration.cs | 20 +- src/Uno.UI/LinkerDefinition.Wasm.xml | 57 - .../NativeRenderTransformAdapter.Skia.cs | 39 + .../Media/NativeRenderTransformAdapter.cs | 2 +- src/Uno.UI/Media/PathStreamGeometryContext.cs | 33 + src/Uno.UI/Media/StreamGeometry.cs | 12 +- src/Uno.UI/MixinGeneration.targets | 195 + src/Uno.UI/Mixins/Wasm/VisualStatesMixins.tt | 2 +- .../Mock/ArbitraryShapeBase.netstdref.cs | 16 + src/Uno.UI/Mock/Border.netstdref.cs | 18 + src/Uno.UI/Mock/Brush.netstdref.cs | 19 + src/Uno.UI/Mock/Color.netstdref.cs | 14 + src/Uno.UI/Mock/ContentControl.netstdref.cs | 14 + src/Uno.UI/Mock/Control.netstdref.cs | 13 + src/Uno.UI/Mock/DispatcherTimer.netstdref.cs | 26 + src/Uno.UI/Mock/Grid.netstdref.cs | 13 + src/Uno.UI/Mock/Image.netstdref.cs | 9 + src/Uno.UI/Mock/ImageSource.netstdref.cs | 22 + src/Uno.UI/Mock/ListView.netstdref.cs | 8 + src/Uno.UI/Mock/ListViewBase.netstdref.cs | 11 + src/Uno.UI/Mock/Panel.netstdref.cs | 34 + src/Uno.UI/Mock/Popup.netstdref.cs | 24 + .../Mock/ScrollContentPresenter.netstdref.cs | 21 + src/Uno.UI/Mock/ScrollViewer.netstdref.cs | 19 + src/Uno.UI/Mock/Shape.netstdref.cs | 15 + src/Uno.UI/Mock/StackPanel.netstdref.cs | 14 + src/Uno.UI/Mock/TextBlock.netstdref.cs | 14 + src/Uno.UI/Mock/UserControl.netstdref.cs | 8 + src/Uno.UI/Mock/ViewExtensions.netstdref.cs | 51 + src/Uno.UI/Mock/ViewExtensions.skia.cs | 42 + .../System/DispatcherQueueTimer.netstdref.cs | 29 + .../System/DispatcherQueueTimer.skia.cs | 29 + src/Uno.UI/UI/Xaml/Application.Skia.cs | 62 + src/Uno.UI/UI/Xaml/Application.netstdref.cs | 16 + .../UI/Xaml/Controls/Border/Border.Skia.cs | 102 + src/Uno.UI/UI/Xaml/Controls/Border/Border.cs | 3 + .../UI/Xaml/Controls/Border/Border.wasm.cs | 2 - .../Border/BorderLayerRenderer.skia.cs | 223 + .../Controls/Button/RadioButton.Android.cs | 8 - .../UI/Xaml/Controls/Button/RadioButton.cs | 16 + .../Controls/Button/RadioButton.iOSmacOS.cs | 8 - .../Xaml/Controls/Button/RadioButton.net.cs | 4 - .../Controls/Button/RadioButton.netstdref.cs | 14 + .../Xaml/Controls/Button/RadioButton.wasm.cs | 8 - .../UI/Xaml/Controls/Canvas/Canvas.Layout.cs | 2 +- .../ContentControl/ContentControl.Skia.cs | 27 + .../ContentPresenter/ContentPresenter.Skia.cs | 70 + .../ContentPresenter/ContentPresenter.cs | 4 +- .../ContentPresenter.netstdref.cs | 53 + .../ContentPresenter/ContentPresenter.wasm.cs | 2 - .../UI/Xaml/Controls/Control/Control.Skia.cs | 45 + .../UI/Xaml/Controls/Control/Control.cs | 2 +- .../Controls/Control/Control.netstdref.cs | 39 + .../UI/Xaml/Controls/Control/Control.wasm.cs | 4 +- ...out.wasm.cs => DatePickerFlyout.netstd.cs} | 0 .../UI/Xaml/Controls/Image/Image.Skia.cs | 27 + src/Uno.UI/UI/Xaml/Controls/Image/Image.cs | 10 +- .../UI/Xaml/Controls/Image/Image.netstdref.cs | 24 + .../UI/Xaml/Controls/Image/Image.wasm.cs | 9 +- .../ItemsControl/ItemsControl.Skia.cs | 26 + .../Controls/ItemsControl/ItemsPresenter.cs | 4 +- .../ItemsStackPanel.NotImplemented.cs | 2 +- .../ItemsStackPanel/ItemsStackPanel.cs | 6 +- .../Controls/ItemsWrapGrid/ItemsWrapGrid.cs | 2 +- .../ItemsWrapGrid/ItemsWrapGridLayout.cs | 2 +- .../UI/Xaml/Controls/Layouter/Layouter.cs | 2 +- .../ListViewBase/ListViewBase.Skia.cs | 53 + .../ListViewBase/ListViewBase.managed.cs | 2 +- .../ListViewBase/ListViewBase.netstdref.cs | 13 + .../ListViewBaseScrollContentPresenter.cs | 2 +- .../ListViewBase/NativeListViewBase.cs | 2 +- .../ListViewBase/VirtualizingPanelLayout.cs | 4 +- .../VirtualizingPanelLayout.managed.cs | 4 +- .../UI/Xaml/Controls/Panel/Panel.Skia.cs | 108 + src/Uno.UI/UI/Xaml/Controls/Panel/Panel.cs | 4 +- .../UI/Xaml/Controls/Panel/Panel.wasm.cs | 2 - .../Xaml/Controls/Primitives/CarouselPanel.cs | 2 +- ...lPanel.wasm.cs => CarouselPanel.netstd.cs} | 0 .../Controls/ProgressRing/ProgressRing.cs | 12 +- .../ProgressRing/ProgressRing.netstdref.cs | 16 + .../ProgressRing/ProgressRing.skia.cs | 16 + .../ScrollContentPresenter.Skia.cs | 128 + .../ScrollContentPresenter.netstd.cs | 85 + .../ScrollContentPresenter.netstdref.cs | 29 + .../ScrollContentPresenter.wasm.cs | 68 +- .../ScrollViewer/ScrollViewer.Skia.cs | 34 + .../Controls/ScrollViewer/ScrollViewer.cs | 2 +- .../Xaml/Controls/TextBlock/TextBlock.Skia.cs | 92 + .../UI/Xaml/Controls/TextBlock/TextBlock.cs | 2 +- .../Controls/TextBlock/TextVisual.Skia.cs | 83 + .../UI/Xaml/Controls/TextBox/TextBox.Skia.cs | 13 + .../UI/Xaml/Controls/TextBox/TextBox.cs | 2 +- .../Controls/TextBox/TextBox.netstdref.cs | 13 + .../Controls/TextBox/TextBoxView.Android.cs | 2 +- .../Controls/TextBox/TextBoxView.macOS.cs | 2 +- .../Xaml/Controls/TextBox/TextBoxView.stub.cs | 4 +- .../Xaml/Controls/TextBox/TextBoxView.wasm.cs | 2 +- .../TextBox/TextBoxViewDelegate.macOS.cs | 2 +- .../UI/Xaml/Controls/TimePicker/TimePicker.cs | 2 +- ...out.wasm.cs => TimePickerFlyout.netstd.cs} | 0 .../UI/Xaml/Controls/ViewBox/Viewbox.skia.cs | 17 + .../UI/Xaml/Controls/WebView/WebView.cs | 4 +- .../Controls/WebView/WebView.netstdref.cs | 23 + .../UI/Xaml/Controls/WebView/WebView.skia.cs | 34 + .../DependencyPropertiesImplementation.cs | 5 +- .../DependencyPropertiesImplementation.tt | 2 +- src/Uno.UI/UI/Xaml/DispatcherTimer.Skia.cs | 46 + .../UI/Xaml/Documents/Hyperlink.wasm.cs | 34 + src/Uno.UI/UI/Xaml/Documents/Inline.cs | 2 +- .../UI/Xaml/Documents/InlineCollection.cs | 54 +- .../Xaml/Documents/InlineCollection.wasm.cs | 4 +- ...mentStub.wasm.cs => ElementStub.netstd.cs} | 0 .../Xaml/FrameworkElement.Interface.Skia.cs | 118 + .../FrameworkElement.Interface.netstdref.cs | 130 + .../Xaml/FrameworkElement.Interface.wasm.cs | 10 +- .../UI/Xaml/FrameworkElement.Layout.Skia.cs | 19 + .../UI/Xaml/FrameworkElement.Layout.netstd.cs | 323 + .../UI/Xaml/FrameworkElement.Layout.wasm.cs | 303 - src/Uno.UI/UI/Xaml/FrameworkElement.Skia.cs | 301 + src/Uno.UI/UI/Xaml/FrameworkElement.cs | 20 +- .../UI/Xaml/FrameworkElement.netstdref.cs | 114 + .../Xaml/Hosting/ElementCompositionPreview.cs | 41 +- ...IFrameworkElementImplementation.Android.cs | 24 +- .../IFrameworkElementImplementation.iOS.tt | 2 +- .../IFrameworkElementImplementation.macOS.tt | 2 +- src/Uno.UI/UI/Xaml/Input/FocusManager.net.cs | 5 - .../UI/Xaml/Input/FocusManager.netstdref.cs | 60 + src/Uno.UI/UI/Xaml/Input/FocusManager.skia.cs | 60 + .../Xaml/Input/PointerRoutedEventArgs.skia.cs | 47 + .../Animators/AnimatorFactory.Skia.cs | 28 + .../Animators/AnimatorFactory.netstdref.cs | 26 + .../ColorAnimationUsingKeyFrames.netstdref.cs | 11 + .../ColorAnimationUsingKeyFrames.skia.cs | 11 + .../Media/Animation/DoubleAnimation.Skia.cs | 10 + ...DoubleAnimationUsingKeyFrames.netstdref.cs | 11 + .../DoubleAnimationUsingKeyFrames.skia.cs | 11 + .../Animation/Timeline.animation.netstdref.cs | 14 + .../Animation/Timeline.animation.skia.cs | 14 + src/Uno.UI/UI/Xaml/Media/Brush.Skia.cs | 59 + src/Uno.UI/UI/Xaml/Media/ImageSource.skia.cs | 32 + .../UI/Xaml/Media/SolidColorBrush.Skia.cs | 11 + .../UI/Xaml/Shapes/ArbitraryShapeBase.Skia.cs | 21 + .../UI/Xaml/Shapes/ArbitraryShapeBase.cs | 4 +- .../Shapes/ArbitraryShapeBase.netstdref.cs | 19 + src/Uno.UI/UI/Xaml/Shapes/Ellipse.Skia.cs | 27 + src/Uno.UI/UI/Xaml/Shapes/Path.Skia.cs | 74 + src/Uno.UI/UI/Xaml/Shapes/Rectangle.Skia.cs | 79 + src/Uno.UI/UI/Xaml/Shapes/Shape.Skia.cs | 174 + ...out.wasm.cs => UIElement.Layout.netstd.cs} | 4 +- src/Uno.UI/UI/Xaml/UIElement.Pointers.Skia.cs | 328 + src/Uno.UI/UI/Xaml/UIElement.RoutedEvents.cs | 2 +- src/Uno.UI/UI/Xaml/UIElement.Skia.cs | 300 + src/Uno.UI/UI/Xaml/UIElement.cs | 10 +- src/Uno.UI/UI/Xaml/UIElement.netstdref.cs | 49 + src/Uno.UI/UI/Xaml/UIElement.wasm.cs | 53 +- .../UI/Xaml/UIElementCollection.Skia.cs | 70 + .../UI/Xaml/UIElementCollection.netstdref.cs | 73 + .../UI/Xaml/UIElementCollection.wasm.cs | 2 +- ...tensions.net.cs => UIElementExtensions.cs} | 3 + .../UI/Xaml/UIElementExtensions.netstdref.cs | 10 + .../UI/Xaml/UIElementExtensions.wasm.cs | 5 - src/Uno.UI/UI/Xaml/Window.Desktop.cs | 2 +- src/Uno.UI/UI/Xaml/Window.Skia.cs | 197 + src/Uno.UI/Uno.UI.csproj | 159 +- src/Uno.UI/XmlnsDefinitionAttribute.cs | 9 +- src/Uno.UWP.Skia/AssemblyInfo.skia.cs | 4 + src/Uno.UWP.Skia/Uno.Skia.csproj | 43 + src/Uno.UWP.Wasm/Uno.Wasm.csproj | 42 + .../Activation/ProtocolActivatedEventArgs.cs | 11 +- .../DataTransfer/Clipboard.netstdref.cs | 18 + .../DataTransfer/Clipboard.skia.cs | 18 + src/Uno.UWP/AssemblyInfo.cs | 1 + .../Devices/Geolocation/Geolocator.wasm.cs | 63 +- .../Devices/Sensors/Accelerometer.Skia.cs | 28 + .../Devices/Sensors/AccelerometerReading.cs | 11 +- .../AccelerometerReadingChangedEvenArgs.cs | 11 +- .../Sensors/AccelerometerShakenEventArgs.cs | 10 +- src/Uno.UWP/Devices/Sensors/Gyrometer.Skia.cs | 23 + .../Devices/Sensors/Magnetometer.Skia.cs | 23 + src/Uno.UWP/Graphics/IGeometrySource2D.cs | 8 + .../ConnectionProfile.netstdref.cs | 17 + .../Connectivity/ConnectionProfile.skia.cs | 17 + .../NetworkInformation.netstdref.cs | 22 + .../Connectivity/NetworkInformation.skia.cs | 22 + .../PasswordVault.Skia.cs | 15 + .../PasswordVault.netstdref.cs | 15 + .../Storage/ApplicationData.netstdref.cs | 23 + src/Uno.UWP/Storage/ApplicationData.skia.cs | 23 + .../Storage/ApplicationDataContainer.skia.cs | 233 + .../System/DispatcherQueueTimer.netstdref.cs | 27 + .../System/DispatcherQueueTimer.skia.cs | 27 + src/Uno.UWP/System/Launcher.Skia.cs | 14 + src/Uno.UWP/System/Profile/AnalyticsInfo.cs | 4 +- .../UI/Composition/CompositionAnimation.cs | 8 +- .../UI/Composition/CompositionBrush.cs | 7 + src/Uno.UWP/UI/Composition/CompositionClip.cs | 15 + .../UI/Composition/CompositionColorBrush.cs | 9 +- .../Composition/CompositionGeometricClip.cs | 17 + .../UI/Composition/CompositionGeometry.cs | 21 + .../UI/Composition/CompositionObject.cs | 17 +- .../UI/Composition/CompositionPath.Skia.cs | 11 + src/Uno.UWP/UI/Composition/CompositionPath.cs | 16 + .../UI/Composition/CompositionPathGeometry.cs | 12 + .../UI/Composition/CompositionScopedBatch.cs | 6 +- .../UI/Composition/CompositionShape.Skia.cs | 13 + .../UI/Composition/CompositionShape.cs | 19 + .../Composition/CompositionShapeCollection.cs | 53 + .../CompositionSpriteShape.Skia.cs | 76 + .../UI/Composition/CompositionSpriteShape.cs | 36 + .../UI/Composition/CompositionViewBox.cs | 15 + src/Uno.UWP/UI/Composition/Compositor.Skia.cs | 95 + src/Uno.UWP/UI/Composition/Compositor.cs | 42 +- .../UI/Composition/ContainerVisual.Skia.cs | 8 + src/Uno.UWP/UI/Composition/ContainerVisual.cs | 8 +- src/Uno.UWP/UI/Composition/InsetClip.cs | 15 + .../UI/Composition/KeyFrameAnimation.cs | 9 +- .../UI/Composition/ScalarKeyFrameAnimation.cs | 4 + .../UI/Composition/ShapeVisual.Skia.cs | 15 + src/Uno.UWP/UI/Composition/ShapeVisual.cs | 15 + .../UI/Composition/SkiaExtensions.Skia.cs | 49 + .../Composition/SkiaGeometrySource2D.Skia.cs | 18 + .../UI/Composition/SpriteVisual.Skia.cs | 44 + src/Uno.UWP/UI/Composition/SpriteVisual.cs | 5 + src/Uno.UWP/UI/Composition/Visual.Android.cs | 4 +- src/Uno.UWP/UI/Composition/Visual.Skia.cs | 22 + src/Uno.UWP/UI/Composition/Visual.cs | 9 +- src/Uno.UWP/UI/Composition/Visual.generic.cs | 11 + src/Uno.UWP/UI/Composition/Visual.iOS.cs | 6 +- src/Uno.UWP/UI/Composition/Visual.macOS.cs | 4 +- src/Uno.UWP/UI/Composition/Visual.net.cs | 4 +- .../UI/Composition/Visual.netstdref.cs | 10 + src/Uno.UWP/UI/Composition/Visual.wasm.cs | 4 +- .../Composition/VisualCollection.Android.cs | 7 - .../UI/Composition/VisualCollection.Skia.cs | 31 + .../UI/Composition/VisualCollection.cs | 14 +- .../UI/Composition/VisualCollection.iOS.cs | 7 - .../UI/Composition/VisualCollection.macOS.cs | 7 - .../UI/Composition/VisualCollection.net.cs | 7 - .../Composition/VisualCollection.netstdref.cs | 31 + .../UI/Composition/VisualCollection.wasm.cs | 7 - src/Uno.UWP/UI/Core/CoreDispatcher.Skia.cs | 34 + .../UI/Core/CoreDispatcher.netstdref.cs | 19 + src/Uno.UWP/UI/Core/CoreWindow.cs | 3 + src/Uno.UWP/UI/Core/CoreWindow.skia.cs | 60 + src/Uno.UWP/UI/Core/PointerEventArgs.cs | 30 + src/Uno.UWP/UI/Input/GestureRecognizer.cs | 2 +- src/Uno.UWP/Uno.csproj | 6 + src/Uno.UWPSyncGenerator/DocGenerator.cs | 2 +- src/Uno.UWPSyncGenerator/Generator.cs | 139 +- src/Uno.UWPSyncGenerator/ImplementedFor.cs | 10 +- .../InheritanceTypeComparer.cs | 4 +- src/crosstargeting_override.props.sample | 2 +- 451 files changed, 43072 insertions(+), 1934 deletions(-) create mode 100644 build/Uno.WinUI.Skia.Gtk.nuspec create mode 100644 build/Uno.WinUI.Skia.Gtk.props create mode 100644 build/Uno.WinUI.Skia.Gtk.targets create mode 100644 build/Uno.WinUI.Skia.Wpf.nuspec create mode 100644 build/Uno.WinUI.Skia.Wpf.props create mode 100644 build/Uno.WinUI.Skia.Wpf.targets create mode 100644 build/Uno.WinUI.WebAssembly.nuspec create mode 100644 build/Uno.WinUI.WebAssembly.props create mode 100644 build/Uno.WinUI.WebAssembly.targets create mode 100644 src/AddIns/Uno.UI.Lottie.Skia/Uno.UI.Lottie.Skia.csproj create mode 100644 src/AddIns/Uno.UI.Lottie.Skia/WasmScripts/lottie.js create mode 100644 src/AddIns/Uno.UI.Lottie.Skia/WasmScripts/uno-lottie.d.ts create mode 100644 src/AddIns/Uno.UI.Lottie.Skia/WasmScripts/uno-lottie.js create mode 100644 src/AddIns/Uno.UI.Lottie.Skia/ts/Uno.UI.Lottie.ts create mode 100644 src/AddIns/Uno.UI.Lottie.Skia/ts/lottie-web.d.ts create mode 100644 src/AddIns/Uno.UI.Lottie.Skia/tsconfig.json create mode 100644 src/AddIns/Uno.UI.Lottie.Wasm/Uno.UI.Lottie.Wasm.csproj create mode 100644 src/AddIns/Uno.UI.Lottie.Wasm/WasmScripts/lottie.js create mode 100644 src/AddIns/Uno.UI.Lottie.Wasm/WasmScripts/uno-lottie.d.ts create mode 100644 src/AddIns/Uno.UI.Lottie.Wasm/WasmScripts/uno-lottie.js create mode 100644 src/AddIns/Uno.UI.Lottie.Wasm/ts/Uno.UI.Lottie.ts create mode 100644 src/AddIns/Uno.UI.Lottie.Wasm/ts/lottie-web.d.ts create mode 100644 src/AddIns/Uno.UI.Lottie.Wasm/tsconfig.json create mode 100644 src/AddIns/Uno.UI.Lottie/buildTransitive/Uno.UI.Lottie.targets create mode 100644 src/AddIns/Uno.UI.MSAL.Skia/LinkerDefinition.xml create mode 100644 src/AddIns/Uno.UI.MSAL.Skia/Uno.UI.MSAL.Skia.csproj create mode 100644 src/AddIns/Uno.UI.MSAL.Skia/WasmScripts/uno-ui-msal.d.ts create mode 100644 src/AddIns/Uno.UI.MSAL.Skia/WasmScripts/uno-ui-msal.js create mode 100644 src/AddIns/Uno.UI.MSAL.Skia/ts/MSAL.WebUI.ts create mode 100644 src/AddIns/Uno.UI.MSAL.Skia/tsconfig.json create mode 100644 src/AddIns/Uno.UI.MSAL.Wasm/LinkerDefinition.xml create mode 100644 src/AddIns/Uno.UI.MSAL.Wasm/Uno.UI.MSAL.Wasm.csproj create mode 100644 src/AddIns/Uno.UI.MSAL.Wasm/WasmScripts/uno-ui-msal.d.ts create mode 100644 src/AddIns/Uno.UI.MSAL.Wasm/WasmScripts/uno-ui-msal.js create mode 100644 src/AddIns/Uno.UI.MSAL.Wasm/ts/MSAL.WebUI.ts create mode 100644 src/AddIns/Uno.UI.MSAL.Wasm/tsconfig.json create mode 100644 src/AddIns/Uno.UI.MSAL/buildTransitive/Uno.UI.MSAL.targets create mode 100644 src/SamplesApp/SamplesApp.Skia.Gtk/Program.cs create mode 100644 src/SamplesApp/SamplesApp.Skia.Gtk/Properties/launchSettings.json create mode 100644 src/SamplesApp/SamplesApp.Skia.Gtk/SamplesApp.Skia.Gtk.csproj create mode 100644 src/SamplesApp/SamplesApp.Skia.WPF/App.config create mode 100644 src/SamplesApp/SamplesApp.Skia.WPF/App.xaml create mode 100644 src/SamplesApp/SamplesApp.Skia.WPF/App.xaml.cs create mode 100644 src/SamplesApp/SamplesApp.Skia.WPF/MainWindow.xaml create mode 100644 src/SamplesApp/SamplesApp.Skia.WPF/MainWindow.xaml.cs create mode 100644 src/SamplesApp/SamplesApp.Skia.WPF/Properties/AssemblyInfo.cs create mode 100644 src/SamplesApp/SamplesApp.Skia.WPF/Properties/Resources.Designer.cs create mode 100644 src/SamplesApp/SamplesApp.Skia.WPF/Properties/Resources.resx create mode 100644 src/SamplesApp/SamplesApp.Skia.WPF/Properties/Settings.Designer.cs create mode 100644 src/SamplesApp/SamplesApp.Skia.WPF/Properties/Settings.settings create mode 100644 src/SamplesApp/SamplesApp.Skia.WPF/SamplesApp.Skia.WPF.csproj create mode 100644 src/SamplesApp/SamplesApp.Skia/SamplesApp.Skia.csproj create mode 100644 src/SamplesApp/SamplesApp.UnitTests.Shared/Controls/UITests/Presentation/SampleChooserViewModel.skia.cs create mode 100644 src/Uno.Foundation.Runtime.Wasm/AssemblyInfo.cs rename src/{Uno.Foundation => Uno.Foundation.Runtime.Wasm}/Interop/IJSObject.wasm.cs (100%) rename src/{Uno.Foundation => Uno.Foundation.Runtime.Wasm}/Interop/IJSObjectMetadata.wasm.cs (100%) rename src/{Uno.Foundation => Uno.Foundation.Runtime.Wasm}/Interop/JSObject.wasm.cs (98%) rename src/{Uno.Foundation => Uno.Foundation.Runtime.Wasm}/Interop/JSObjectHandle.wasm.cs (100%) rename src/{Uno.Foundation => Uno.Foundation.Runtime.Wasm}/Interop/JSObjectMetadataProvider.wasm.cs (100%) rename src/{Uno.Foundation => Uno.Foundation.Runtime.Wasm/Interop}/Runtime.wasm.cs (99%) rename src/{Uno.Foundation => Uno.Foundation.Runtime.Wasm}/Interop/TSInteropMarshaller.wasm.cs (100%) rename src/{Uno.Foundation => Uno.Foundation.Runtime.Wasm}/Interop/TSInteropMessageAttribute.wasm.cs (100%) create mode 100644 src/Uno.Foundation.Runtime.Wasm/LinkerDefinition.Wasm.xml create mode 100644 src/Uno.Foundation.Runtime.Wasm/Uno.Foundation.Runtime.Wasm.csproj create mode 100644 src/Uno.Foundation.Skia/AssemblyInfo.skia.cs create mode 100644 src/Uno.Foundation.Skia/Uno.Foundation.Skia.csproj create mode 100644 src/Uno.Foundation.Wasm/Uno.Foundation.Wasm.csproj delete mode 100644 src/Uno.Foundation/Eventing/EventActivity.cs delete mode 100644 src/Uno.Foundation/Eventing/EventDescriptor.cs delete mode 100644 src/Uno.Foundation/Eventing/EventOpcode.cs delete mode 100644 src/Uno.Foundation/Eventing/EventProviderExtensions.cs delete mode 100644 src/Uno.Foundation/Eventing/IEventProvider.cs delete mode 100644 src/Uno.Foundation/Eventing/IEventProviderFactory.cs delete mode 100644 src/Uno.Foundation/Eventing/NullEventProvider.cs delete mode 100644 src/Uno.Foundation/Eventing/Tracing.cs create mode 100644 src/Uno.Foundation/Extensions/RectExtensions.cs delete mode 100644 src/Uno.Foundation/LinkerDefinition.Wasm.xml create mode 100644 src/Uno.ReferenceImplComparer/Program.cs create mode 100644 src/Uno.ReferenceImplComparer/Properties/launchSettings.json create mode 100644 src/Uno.ReferenceImplComparer/Uno.ReferenceImplComparer.csproj create mode 100644 src/Uno.UI-Skia-only.slnf rename src/{Uno.UI.RemoteControl => Uno.UI.RemoteControl.Skia}/LinkerDefinition.Wasm.xml (100%) create mode 100644 src/Uno.UI.RemoteControl.Skia/Uno.UI.RemoteControl.Skia.csproj create mode 100644 src/Uno.UI.RemoteControl.Wasm/LinkerDefinition.Wasm.xml create mode 100644 src/Uno.UI.RemoteControl.Wasm/Uno.UI.RemoteControl.Wasm.csproj create mode 100644 src/Uno.UI.RemoteControl/buildTransitive/Uno.UI.RemoteControl.targets create mode 100644 src/Uno.UI.Runtime.Skia.Gtk/GTK/GtkCoreWindowExtension.cs create mode 100644 src/Uno.UI.Runtime.Skia.Gtk/GTK/GtkHost.cs create mode 100644 src/Uno.UI.Runtime.Skia.Gtk/GTK/UnoDrawingArea.cs create mode 100644 src/Uno.UI.Runtime.Skia.Gtk/Uno.UI.Runtime.Skia.Gtk.csproj create mode 100644 src/Uno.UI.Runtime.Skia.Gtk/buildTransitive/Uno.UI.Runtime.Skia.Gtk.props create mode 100644 src/Uno.UI.Runtime.Skia.Gtk/buildTransitive/Uno.UI.Runtime.Skia.Gtk.targets create mode 100644 src/Uno.UI.Runtime.Skia.Wpf/Uno.UI.Runtime.Skia.Wpf.csproj create mode 100644 src/Uno.UI.Runtime.Skia.Wpf/WPF/WpfHost.cs create mode 100644 src/Uno.UI.Runtime.Skia.Wpf/buildTransitive/Uno.UI.Runtime.Skia.Wpf.props create mode 100644 src/Uno.UI.Runtime.Skia.Wpf/buildTransitive/Uno.UI.Runtime.Skia.Wpf.targets create mode 100644 src/Uno.UI.Runtime.Wasm/AssemblyInfo.cs create mode 100644 src/Uno.UI.Runtime.Wasm/HtmlElement.cs create mode 100644 src/Uno.UI.Runtime.Wasm/LinkerDefinition.xml create mode 100644 src/Uno.UI.Runtime.Wasm/RuntimeAnchor.cs create mode 100644 src/Uno.UI.Runtime.Wasm/Uno.UI.Runtime.Wasm.csproj rename src/{Uno.UI.Wasm => Uno.UI.Runtime.Wasm}/WasmHttpHandler.cs (100%) create mode 100644 src/Uno.UI.Runtime.Wasm/buildTransitive/Uno.UI.Runtime.Wasm.props create mode 100644 src/Uno.UI.Runtime.Wasm/buildTransitive/Uno.UI.Runtime.Wasm.targets create mode 100644 src/Uno.UI.RuntimeTests.Skia/LinkerDefinition.Skia.xml create mode 100644 src/Uno.UI.RuntimeTests.Skia/Uno.UI.RuntimeTests.Skia.csproj create mode 100644 src/Uno.UI.RuntimeTests.Wasm/LinkerDefinition.Wasm.xml create mode 100644 src/Uno.UI.RuntimeTests.Wasm/Uno.UI.RuntimeTests.Wasm.csproj create mode 100644 src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/HtmlElementAttributeTests/Given_HtmlElementAttribute.Wasm.cs create mode 100644 src/Uno.UI.Skia/AssemblyInfo.skia.cs create mode 100644 src/Uno.UI.Skia/LinkerDefinition.xml create mode 100644 src/Uno.UI.Skia/Uno.UI.Skia.csproj create mode 100644 src/Uno.UI.Toolkit.Skia/Uno.UI.Toolkit.Skia.csproj create mode 100644 src/Uno.UI.Toolkit.Wasm/Uno.UI.Toolkit.Wasm.csproj rename src/Uno.UI/Extensions/{ViewHelper.net.cs => ViewHelper.cs} (94%) delete mode 100644 src/Uno.UI/Extensions/ViewHelper.wasm.cs create mode 100644 src/Uno.UI/Media/NativeRenderTransformAdapter.Skia.cs create mode 100644 src/Uno.UI/MixinGeneration.targets create mode 100644 src/Uno.UI/Mock/ArbitraryShapeBase.netstdref.cs create mode 100644 src/Uno.UI/Mock/Border.netstdref.cs create mode 100644 src/Uno.UI/Mock/Brush.netstdref.cs create mode 100644 src/Uno.UI/Mock/Color.netstdref.cs create mode 100644 src/Uno.UI/Mock/ContentControl.netstdref.cs create mode 100644 src/Uno.UI/Mock/Control.netstdref.cs create mode 100644 src/Uno.UI/Mock/DispatcherTimer.netstdref.cs create mode 100644 src/Uno.UI/Mock/Grid.netstdref.cs create mode 100644 src/Uno.UI/Mock/Image.netstdref.cs create mode 100644 src/Uno.UI/Mock/ImageSource.netstdref.cs create mode 100644 src/Uno.UI/Mock/ListView.netstdref.cs create mode 100644 src/Uno.UI/Mock/ListViewBase.netstdref.cs create mode 100644 src/Uno.UI/Mock/Panel.netstdref.cs create mode 100644 src/Uno.UI/Mock/Popup.netstdref.cs create mode 100644 src/Uno.UI/Mock/ScrollContentPresenter.netstdref.cs create mode 100644 src/Uno.UI/Mock/ScrollViewer.netstdref.cs create mode 100644 src/Uno.UI/Mock/Shape.netstdref.cs create mode 100644 src/Uno.UI/Mock/StackPanel.netstdref.cs create mode 100644 src/Uno.UI/Mock/TextBlock.netstdref.cs create mode 100644 src/Uno.UI/Mock/UserControl.netstdref.cs create mode 100644 src/Uno.UI/Mock/ViewExtensions.netstdref.cs create mode 100644 src/Uno.UI/Mock/ViewExtensions.skia.cs create mode 100644 src/Uno.UI/System/DispatcherQueueTimer.netstdref.cs create mode 100644 src/Uno.UI/System/DispatcherQueueTimer.skia.cs create mode 100644 src/Uno.UI/UI/Xaml/Application.Skia.cs create mode 100644 src/Uno.UI/UI/Xaml/Application.netstdref.cs create mode 100644 src/Uno.UI/UI/Xaml/Controls/Border/Border.Skia.cs create mode 100644 src/Uno.UI/UI/Xaml/Controls/Border/BorderLayerRenderer.skia.cs create mode 100644 src/Uno.UI/UI/Xaml/Controls/Button/RadioButton.netstdref.cs create mode 100644 src/Uno.UI/UI/Xaml/Controls/ContentControl/ContentControl.Skia.cs create mode 100644 src/Uno.UI/UI/Xaml/Controls/ContentPresenter/ContentPresenter.Skia.cs create mode 100644 src/Uno.UI/UI/Xaml/Controls/ContentPresenter/ContentPresenter.netstdref.cs create mode 100644 src/Uno.UI/UI/Xaml/Controls/Control/Control.Skia.cs create mode 100644 src/Uno.UI/UI/Xaml/Controls/Control/Control.netstdref.cs rename src/Uno.UI/UI/Xaml/Controls/DatePicker/{DatePickerFlyout.wasm.cs => DatePickerFlyout.netstd.cs} (100%) create mode 100644 src/Uno.UI/UI/Xaml/Controls/Image/Image.Skia.cs create mode 100644 src/Uno.UI/UI/Xaml/Controls/Image/Image.netstdref.cs create mode 100644 src/Uno.UI/UI/Xaml/Controls/ItemsControl/ItemsControl.Skia.cs create mode 100644 src/Uno.UI/UI/Xaml/Controls/ListViewBase/ListViewBase.Skia.cs create mode 100644 src/Uno.UI/UI/Xaml/Controls/ListViewBase/ListViewBase.netstdref.cs create mode 100644 src/Uno.UI/UI/Xaml/Controls/Panel/Panel.Skia.cs rename src/Uno.UI/UI/Xaml/Controls/Primitives/{CarouselPanel.wasm.cs => CarouselPanel.netstd.cs} (100%) create mode 100644 src/Uno.UI/UI/Xaml/Controls/ProgressRing/ProgressRing.netstdref.cs create mode 100644 src/Uno.UI/UI/Xaml/Controls/ProgressRing/ProgressRing.skia.cs create mode 100644 src/Uno.UI/UI/Xaml/Controls/ScrollContentPresenter/ScrollContentPresenter.Skia.cs create mode 100644 src/Uno.UI/UI/Xaml/Controls/ScrollContentPresenter/ScrollContentPresenter.netstd.cs create mode 100644 src/Uno.UI/UI/Xaml/Controls/ScrollContentPresenter/ScrollContentPresenter.netstdref.cs create mode 100644 src/Uno.UI/UI/Xaml/Controls/ScrollViewer/ScrollViewer.Skia.cs create mode 100644 src/Uno.UI/UI/Xaml/Controls/TextBlock/TextBlock.Skia.cs create mode 100644 src/Uno.UI/UI/Xaml/Controls/TextBlock/TextVisual.Skia.cs create mode 100644 src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.Skia.cs create mode 100644 src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.netstdref.cs rename src/Uno.UI/UI/Xaml/Controls/TimePicker/{TimePickerFlyout.wasm.cs => TimePickerFlyout.netstd.cs} (100%) create mode 100644 src/Uno.UI/UI/Xaml/Controls/ViewBox/Viewbox.skia.cs create mode 100644 src/Uno.UI/UI/Xaml/Controls/WebView/WebView.netstdref.cs create mode 100644 src/Uno.UI/UI/Xaml/Controls/WebView/WebView.skia.cs create mode 100644 src/Uno.UI/UI/Xaml/DispatcherTimer.Skia.cs rename src/Uno.UI/UI/Xaml/{ElementStub.wasm.cs => ElementStub.netstd.cs} (100%) create mode 100644 src/Uno.UI/UI/Xaml/FrameworkElement.Interface.Skia.cs create mode 100644 src/Uno.UI/UI/Xaml/FrameworkElement.Interface.netstdref.cs create mode 100644 src/Uno.UI/UI/Xaml/FrameworkElement.Layout.Skia.cs create mode 100644 src/Uno.UI/UI/Xaml/FrameworkElement.Layout.netstd.cs create mode 100644 src/Uno.UI/UI/Xaml/FrameworkElement.Skia.cs create mode 100644 src/Uno.UI/UI/Xaml/FrameworkElement.netstdref.cs create mode 100644 src/Uno.UI/UI/Xaml/Input/FocusManager.netstdref.cs create mode 100644 src/Uno.UI/UI/Xaml/Input/FocusManager.skia.cs create mode 100644 src/Uno.UI/UI/Xaml/Input/PointerRoutedEventArgs.skia.cs create mode 100644 src/Uno.UI/UI/Xaml/Media/Animation/Animators/AnimatorFactory.Skia.cs create mode 100644 src/Uno.UI/UI/Xaml/Media/Animation/Animators/AnimatorFactory.netstdref.cs create mode 100644 src/Uno.UI/UI/Xaml/Media/Animation/ColorAnimationUsingKeyFrames.netstdref.cs create mode 100644 src/Uno.UI/UI/Xaml/Media/Animation/ColorAnimationUsingKeyFrames.skia.cs create mode 100644 src/Uno.UI/UI/Xaml/Media/Animation/DoubleAnimation.Skia.cs create mode 100644 src/Uno.UI/UI/Xaml/Media/Animation/DoubleAnimationUsingKeyFrames.netstdref.cs create mode 100644 src/Uno.UI/UI/Xaml/Media/Animation/DoubleAnimationUsingKeyFrames.skia.cs create mode 100644 src/Uno.UI/UI/Xaml/Media/Animation/Timeline.animation.netstdref.cs create mode 100644 src/Uno.UI/UI/Xaml/Media/Animation/Timeline.animation.skia.cs create mode 100644 src/Uno.UI/UI/Xaml/Media/Brush.Skia.cs create mode 100644 src/Uno.UI/UI/Xaml/Media/ImageSource.skia.cs create mode 100644 src/Uno.UI/UI/Xaml/Media/SolidColorBrush.Skia.cs create mode 100644 src/Uno.UI/UI/Xaml/Shapes/ArbitraryShapeBase.Skia.cs create mode 100644 src/Uno.UI/UI/Xaml/Shapes/ArbitraryShapeBase.netstdref.cs create mode 100644 src/Uno.UI/UI/Xaml/Shapes/Ellipse.Skia.cs create mode 100644 src/Uno.UI/UI/Xaml/Shapes/Path.Skia.cs create mode 100644 src/Uno.UI/UI/Xaml/Shapes/Rectangle.Skia.cs create mode 100644 src/Uno.UI/UI/Xaml/Shapes/Shape.Skia.cs rename src/Uno.UI/UI/Xaml/{UIElement.Layout.wasm.cs => UIElement.Layout.netstd.cs} (98%) create mode 100644 src/Uno.UI/UI/Xaml/UIElement.Pointers.Skia.cs create mode 100644 src/Uno.UI/UI/Xaml/UIElement.Skia.cs create mode 100644 src/Uno.UI/UI/Xaml/UIElement.netstdref.cs create mode 100644 src/Uno.UI/UI/Xaml/UIElementCollection.Skia.cs create mode 100644 src/Uno.UI/UI/Xaml/UIElementCollection.netstdref.cs rename src/Uno.UI/UI/Xaml/{UIElementExtensions.net.cs => UIElementExtensions.cs} (78%) create mode 100644 src/Uno.UI/UI/Xaml/UIElementExtensions.netstdref.cs create mode 100644 src/Uno.UI/UI/Xaml/Window.Skia.cs create mode 100644 src/Uno.UWP.Skia/AssemblyInfo.skia.cs create mode 100644 src/Uno.UWP.Skia/Uno.Skia.csproj create mode 100644 src/Uno.UWP.Wasm/Uno.Wasm.csproj create mode 100644 src/Uno.UWP/ApplicationModel/DataTransfer/Clipboard.netstdref.cs create mode 100644 src/Uno.UWP/ApplicationModel/DataTransfer/Clipboard.skia.cs create mode 100644 src/Uno.UWP/Devices/Sensors/Accelerometer.Skia.cs create mode 100644 src/Uno.UWP/Devices/Sensors/Gyrometer.Skia.cs create mode 100644 src/Uno.UWP/Devices/Sensors/Magnetometer.Skia.cs create mode 100644 src/Uno.UWP/Graphics/IGeometrySource2D.cs create mode 100644 src/Uno.UWP/Networking/Connectivity/ConnectionProfile.netstdref.cs create mode 100644 src/Uno.UWP/Networking/Connectivity/ConnectionProfile.skia.cs create mode 100644 src/Uno.UWP/Networking/Connectivity/NetworkInformation.netstdref.cs create mode 100644 src/Uno.UWP/Networking/Connectivity/NetworkInformation.skia.cs create mode 100644 src/Uno.UWP/Security.Credentials/PasswordVault.Skia.cs create mode 100644 src/Uno.UWP/Security.Credentials/PasswordVault.netstdref.cs create mode 100644 src/Uno.UWP/Storage/ApplicationData.netstdref.cs create mode 100644 src/Uno.UWP/Storage/ApplicationData.skia.cs create mode 100644 src/Uno.UWP/Storage/ApplicationDataContainer.skia.cs create mode 100644 src/Uno.UWP/System/DispatcherQueueTimer.netstdref.cs create mode 100644 src/Uno.UWP/System/DispatcherQueueTimer.skia.cs create mode 100644 src/Uno.UWP/System/Launcher.Skia.cs create mode 100644 src/Uno.UWP/UI/Composition/CompositionClip.cs create mode 100644 src/Uno.UWP/UI/Composition/CompositionGeometricClip.cs create mode 100644 src/Uno.UWP/UI/Composition/CompositionGeometry.cs create mode 100644 src/Uno.UWP/UI/Composition/CompositionPath.Skia.cs create mode 100644 src/Uno.UWP/UI/Composition/CompositionPath.cs create mode 100644 src/Uno.UWP/UI/Composition/CompositionPathGeometry.cs create mode 100644 src/Uno.UWP/UI/Composition/CompositionShape.Skia.cs create mode 100644 src/Uno.UWP/UI/Composition/CompositionShape.cs create mode 100644 src/Uno.UWP/UI/Composition/CompositionShapeCollection.cs create mode 100644 src/Uno.UWP/UI/Composition/CompositionSpriteShape.Skia.cs create mode 100644 src/Uno.UWP/UI/Composition/CompositionSpriteShape.cs create mode 100644 src/Uno.UWP/UI/Composition/CompositionViewBox.cs create mode 100644 src/Uno.UWP/UI/Composition/Compositor.Skia.cs create mode 100644 src/Uno.UWP/UI/Composition/ContainerVisual.Skia.cs create mode 100644 src/Uno.UWP/UI/Composition/InsetClip.cs create mode 100644 src/Uno.UWP/UI/Composition/ShapeVisual.Skia.cs create mode 100644 src/Uno.UWP/UI/Composition/ShapeVisual.cs create mode 100644 src/Uno.UWP/UI/Composition/SkiaExtensions.Skia.cs create mode 100644 src/Uno.UWP/UI/Composition/SkiaGeometrySource2D.Skia.cs create mode 100644 src/Uno.UWP/UI/Composition/SpriteVisual.Skia.cs create mode 100644 src/Uno.UWP/UI/Composition/Visual.Skia.cs create mode 100644 src/Uno.UWP/UI/Composition/Visual.generic.cs create mode 100644 src/Uno.UWP/UI/Composition/Visual.netstdref.cs create mode 100644 src/Uno.UWP/UI/Composition/VisualCollection.Skia.cs create mode 100644 src/Uno.UWP/UI/Composition/VisualCollection.netstdref.cs create mode 100644 src/Uno.UWP/UI/Core/CoreDispatcher.Skia.cs create mode 100644 src/Uno.UWP/UI/Core/CoreDispatcher.netstdref.cs create mode 100644 src/Uno.UWP/UI/Core/CoreWindow.skia.cs create mode 100644 src/Uno.UWP/UI/Core/PointerEventArgs.cs diff --git a/.vsts-ci.yml b/.vsts-ci.yml index f7f60ef51bd0..d8e52c7c763a 100644 --- a/.vsts-ci.yml +++ b/.vsts-ci.yml @@ -18,7 +18,8 @@ resources: image: unoplatform/wasm-build:2.1.1 variables: - windowsVMImage: 'windows-2019' + windowsHostedVMImage: 'windows-2019' + scaledPool: 'Windows2019-20200608' linuxVMImage: 'ubuntu-16.04' macOSVMImage: 'macOS-10.15' xCodeRoot: '/Applications/Xcode_11.5.app' @@ -27,23 +28,23 @@ variables: jobs: - template: build/ci/.azure-devops-windows.yml parameters: - vmImage: '$(windowsVMImage)' + poolName: '$(scaledPool)' - template: build/ci/.azure-devops-project-template-tests.yml parameters: - vmImage: '$(windowsVMImage)' + vmImage: '$(windowsHostedVMImage)' - template: build/ci/.azure-devops-uap.yml parameters: - vmImage: '$(windowsVMImage)' + vmImage: '$(windowsHostedVMImage)' - template: build/ci/.azure-devops-unit-tests.yml parameters: - vmImage: '$(windowsVMImage)' + vmImage: '$(windowsHostedVMImage)' - template: build/ci/.azure-devops-docs.yml parameters: - vmImage: '$(windowsVMImage)' + vmImage: '$(windowsHostedVMImage)' - template: build/ci/.azure-devops-wasm-uitests.yml parameters: @@ -69,4 +70,4 @@ jobs: - template: build/ci/.azure-devops-screenshot-compare.yml parameters: - vmImage: '$(windowsVMImage)' + vmImage: '$(windowsHostedVMImage)' diff --git a/build/PackageDiffIgnore.xml b/build/PackageDiffIgnore.xml index 0ec76bf807c0..fe488cf9b380 100644 --- a/build/PackageDiffIgnore.xml +++ b/build/PackageDiffIgnore.xml @@ -717,26 +717,26 @@ - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1665,6 +1845,39 @@ fullName="Windows.UI.Xaml.FrameworkElement Windows.UI.Xaml.Controls.PopupBase::Child()" reason="Property type corrected from FrameworkElement to UIElement as part of native views clean-up"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2766,6 +2979,26 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/build/TestLocalBuild.CMD b/build/TestLocalBuild.CMD index df4a3f04eca1..1db2a448c7e8 100644 --- a/build/TestLocalBuild.CMD +++ b/build/TestLocalBuild.CMD @@ -1,2 +1,2 @@ -msbuild uno.ui.proj "/p:CombinedConfiguration=Release|AnyCPU;BUILD_BUILDNUMBER=test_test_8888" /m:16 /clp:PerformanceSummary;Summary /bl +msbuild uno.ui.build.csproj "/p:CombinedConfiguration=Release|AnyCPU;BUILD_BUILDNUMBER=test_test_8888;GitVersion_FullSemVer=1.0.0.0;GITVERSION_MajorMinorPatch=1.0.0;GITVERSION_CommitsSinceVersionSource=1" /m:16 /clp:PerformanceSummary;Summary /bl pause diff --git a/build/Uno.UI.Build.csproj b/build/Uno.UI.Build.csproj index 3385c591b2f2..a0b05f16398c 100644 --- a/build/Uno.UI.Build.csproj +++ b/build/Uno.UI.Build.csproj @@ -47,7 +47,7 @@ - + @@ -96,6 +96,15 @@ + + + @@ -163,7 +172,7 @@ DestinationFiles="$(OutputDir)\vslatest\UnoPlatform-$(GITVERSION_FullSemVer).vsix" /> - + http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd @@ -171,28 +180,103 @@ Uno.UI - - - + + <_NuspecFiles Include=".\Uno.WinUI.nuspec" /> + <_NuspecFiles Include=".\Uno.WinUI.Lottie.nuspec" /> + <_NuspecFiles Include=".\Uno.WinUI.RemoteControl.nuspec" /> + <_NuspecFiles Include=".\Uno.WinUI.Skia.Gtk.nuspec" /> + <_NuspecFiles Include=".\Uno.WinUI.Skia.Wpf.nuspec" /> + <_NuspecFiles Include=".\Uno.WinUI.WebAssembly.nuspec" /> + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -201,8 +285,17 @@ Uno.UI - - + + + + + + + Uno.WinUI + Uno.UI + + + diff --git a/build/Uno.WinUI.Lottie.nuspec b/build/Uno.WinUI.Lottie.nuspec index ed4276d3227f..d27b964bdd8d 100644 --- a/build/Uno.WinUI.Lottie.nuspec +++ b/build/Uno.WinUI.Lottie.nuspec @@ -37,6 +37,10 @@ + + + + @@ -54,6 +58,9 @@ + + + @@ -63,5 +70,15 @@ + + + + + + + + + + diff --git a/build/Uno.WinUI.RemoteControl.nuspec b/build/Uno.WinUI.RemoteControl.nuspec index 46106499cb7f..4ef17142893a 100644 --- a/build/Uno.WinUI.RemoteControl.nuspec +++ b/build/Uno.WinUI.RemoteControl.nuspec @@ -16,14 +16,21 @@ - - - + + + - - + + + + + + - + + + + @@ -57,26 +64,34 @@ - + - - - - - - + + + + + + + + + + + - - - + + + + + + @@ -84,6 +99,15 @@ + + + + + + + + + diff --git a/build/Uno.WinUI.Skia.Gtk.nuspec b/build/Uno.WinUI.Skia.Gtk.nuspec new file mode 100644 index 000000000000..7ff6087ff7e9 --- /dev/null +++ b/build/Uno.WinUI.Skia.Gtk.nuspec @@ -0,0 +1,28 @@ + + + + Uno.WinUI.Skia.Gtk + 1.0.0.0 + Uno.UI + nventive + nventive + false + https://platform.uno/ + Apache-2.0 + https://nv-assets.azurewebsites.net/logos/uno.png + Build Mobile, Desktop and WebAssembly apps with C# and XAML. Today. Open source and professionally supported. + Copyright (C) 2015-2020 nventive inc. - all rights reserved + + + + + + + + + + + + + + diff --git a/build/Uno.WinUI.Skia.Gtk.props b/build/Uno.WinUI.Skia.Gtk.props new file mode 100644 index 000000000000..6a00269d85d2 --- /dev/null +++ b/build/Uno.WinUI.Skia.Gtk.props @@ -0,0 +1,9 @@ + + + + + true + Skia + + + diff --git a/build/Uno.WinUI.Skia.Gtk.targets b/build/Uno.WinUI.Skia.Gtk.targets new file mode 100644 index 000000000000..9abbed6843d5 --- /dev/null +++ b/build/Uno.WinUI.Skia.Gtk.targets @@ -0,0 +1,7 @@ + + + + + + + diff --git a/build/Uno.WinUI.Skia.Wpf.nuspec b/build/Uno.WinUI.Skia.Wpf.nuspec new file mode 100644 index 000000000000..540bdb5f7b2d --- /dev/null +++ b/build/Uno.WinUI.Skia.Wpf.nuspec @@ -0,0 +1,28 @@ + + + + Uno.WinUI.Skia.Wpf + 1.0.0.0 + Uno.UI + nventive + nventive + false + https://platform.uno/ + Apache-2.0 + https://nv-assets.azurewebsites.net/logos/uno.png + Build Mobile, Desktop and WebAssembly apps with C# and XAML. Today. Open source and professionally supported. + Copyright (C) 2015-2020 nventive inc. - all rights reserved + + + + + + + + + + + + + + diff --git a/build/Uno.WinUI.Skia.Wpf.props b/build/Uno.WinUI.Skia.Wpf.props new file mode 100644 index 000000000000..6a00269d85d2 --- /dev/null +++ b/build/Uno.WinUI.Skia.Wpf.props @@ -0,0 +1,9 @@ + + + + + true + Skia + + + diff --git a/build/Uno.WinUI.Skia.Wpf.targets b/build/Uno.WinUI.Skia.Wpf.targets new file mode 100644 index 000000000000..9abbed6843d5 --- /dev/null +++ b/build/Uno.WinUI.Skia.Wpf.targets @@ -0,0 +1,7 @@ + + + + + + + diff --git a/build/Uno.WinUI.WebAssembly.nuspec b/build/Uno.WinUI.WebAssembly.nuspec new file mode 100644 index 000000000000..05cc963b2365 --- /dev/null +++ b/build/Uno.WinUI.WebAssembly.nuspec @@ -0,0 +1,30 @@ + + + + Uno.UI.WebAssembly + 1.0.0.0 + Uno.UI + nventive + nventive + false + https://platform.uno/ + Apache-2.0 + https://nv-assets.azurewebsites.net/logos/uno.png + Build Mobile, Desktop and WebAssembly apps with C# and XAML. Today. Open source and professionally supported. + Copyright (C) 2015-2020 nventive inc. - all rights reserved + + + + + + + + + + + + + + + + diff --git a/build/Uno.WinUI.WebAssembly.props b/build/Uno.WinUI.WebAssembly.props new file mode 100644 index 000000000000..6284bac5fc33 --- /dev/null +++ b/build/Uno.WinUI.WebAssembly.props @@ -0,0 +1,9 @@ + + + + + true + WebAssembly + + + diff --git a/build/Uno.WinUI.WebAssembly.targets b/build/Uno.WinUI.WebAssembly.targets new file mode 100644 index 000000000000..9abbed6843d5 --- /dev/null +++ b/build/Uno.WinUI.WebAssembly.targets @@ -0,0 +1,7 @@ + + + + + + + diff --git a/build/Uno.WinUI.nuspec b/build/Uno.WinUI.nuspec index d0734746da96..9f9812b0b35d 100644 --- a/build/Uno.WinUI.nuspec +++ b/build/Uno.WinUI.nuspec @@ -22,9 +22,10 @@ - + + @@ -32,34 +33,38 @@ - + + - + + - + - + - + + - + - + + @@ -77,14 +82,13 @@ - + - @@ -96,7 +100,7 @@ - + @@ -124,21 +128,11 @@ - + - - - - - - - - - - @@ -152,6 +146,8 @@ + + @@ -165,6 +161,8 @@ + + @@ -176,6 +174,8 @@ + + @@ -187,20 +187,36 @@ + + - + - - - - - - - + + + + + + + + + + + + + + + + + + + + + @@ -215,22 +231,22 @@ - - + + - - - - - - - - + + + + + + + + - - + + - + diff --git a/build/ci/.azure-devops-windows.yml b/build/ci/.azure-devops-windows.yml index 005437d0dec3..e9c486b9c819 100644 --- a/build/ci/.azure-devops-windows.yml +++ b/build/ci/.azure-devops-windows.yml @@ -1,12 +1,11 @@ parameters: - vmImage: '' + poolName: '' jobs: - job: VS_Latest timeoutInMinutes: 90 - pool: - vmImage: ${{ parameters.vmImage }} + pool: ${{ parameters.poolName }} strategy: matrix: @@ -56,7 +55,7 @@ jobs: msbuildLocationMethod: version msbuildVersion: latest msbuildArchitecture: x86 - msbuildArguments: /r /m "/p:CombinedConfiguration=$(CombinedConfiguration)" /detailedsummary # /bl:$(build.artifactstagingdirectory)\build-$(GitVersion.FullSemVer).binlog + msbuildArguments: /r /m "/p:CombinedConfiguration=$(CombinedConfiguration)" /detailedsummary /bl:$(build.artifactstagingdirectory)\build-$(GitVersion.FullSemVer).binlog clean: false restoreNugetPackages: false logProjectEvents: false @@ -85,13 +84,20 @@ jobs: condition: and(succeeded(), not(eq(variables['build.reason'], 'PullRequest')), not(eq(variables['SignClientSecret'], '')), not(eq(variables['SignClientUser'], ''))) - task: PublishBuildArtifacts@1 - # https://developercommunity.visualstudio.com/content/problem/284991/public-vsts-previouw-cant-set-build-number-of-pr-b.html condition: always() inputs: PathtoPublish: $(build.artifactstagingdirectory) ArtifactName: NugetPackages ArtifactType: Container + - task: PublishBuildArtifacts@1 + displayName: Publish Skia Artifacts + condition: always() + inputs: + PathtoPublish: $(build.sourcesdirectory)\src\SamplesApp\SamplesApp.Skia.Gtk\bin\Release\netcoreapp3.1 + ArtifactName: uno-skia-artifacts + ArtifactType: Container + # Publish PR packages to local feed to enable canary testing from PR artifacts - task: NuGetCommand@2 condition: and(eq(variables['System.PullRequest.IsFork'], 'False'), eq(variables['Build.Reason'], 'PullRequest')) diff --git a/build/uno.winui.targets b/build/uno.winui.targets index d56f7973692f..b405416821ab 100644 --- a/build/uno.winui.targets +++ b/build/uno.winui.targets @@ -4,6 +4,8 @@ ..\ + + <_IsUnoPlatform>true @@ -26,6 +28,10 @@ $(UnoDefineConstants);UNO_HAS_NO_IDEPENDENCYOBJECT + + $(UnoDefineConstants);UNO_REFERENCE_API + + @@ -51,6 +57,26 @@ + + + + <_ItemsFromUnoToRemove Include="@(RuntimeCopyLocalItems)" Condition="'%(RuntimeCopyLocalItems.NuGetPackageId)'=='Uno.UI' or '%(RuntimeCopyLocalItems.NuGetPackageId)'=='Uno.WinUI'" /> + + + + + + + + + + + + diff --git a/src/AddIns/Uno.UI.Lottie.Skia/Uno.UI.Lottie.Skia.csproj b/src/AddIns/Uno.UI.Lottie.Skia/Uno.UI.Lottie.Skia.csproj new file mode 100644 index 000000000000..6dd6afde0529 --- /dev/null +++ b/src/AddIns/Uno.UI.Lottie.Skia/Uno.UI.Lottie.Skia.csproj @@ -0,0 +1,51 @@ + + + + netstandard2.0 + $(NoWarn);NU1701 + true + true + + Uno.UI.Lottie + Uno.UI.Lottie + + Skia + ..\Uno.UI.Lottie\ + + + + + + + + + + + + + + + + ..\..\SourceGenerators\Uno.UI.SourceGenerators\bin\$(Configuration) + + + + + + + + <_OverrideTargetFramework>$(TargetFramework) + <_TargetNugetFolder>$(USERPROFILE)\.nuget\packages\Uno.UI.Lottie\$(UnoNugetOverrideVersion)\uno-runtime\$(UnoRuntimeIdentifier.ToLowerInvariant()) + + + <_OutputFiles Include="$(TargetDir)**" /> + + + + + + + + + + diff --git a/src/AddIns/Uno.UI.Lottie.Skia/WasmScripts/lottie.js b/src/AddIns/Uno.UI.Lottie.Skia/WasmScripts/lottie.js new file mode 100644 index 000000000000..f113b07927e3 --- /dev/null +++ b/src/AddIns/Uno.UI.Lottie.Skia/WasmScripts/lottie.js @@ -0,0 +1,14555 @@ +(typeof navigator !== "undefined") && (function (root, factory) { + if (typeof define === "function" && define.amd) { + define(function () { + return factory(root); + }); + } else if (typeof module === "object" && module.exports) { + module.exports = factory(root); + } else { + root.lottie = factory(root); + root.bodymovin = root.lottie; + } +}((window || {}), function (window) { + "use strict"; + var svgNS = "http://www.w3.org/2000/svg"; + + var locationHref = ''; + + var initialDefaultFrame = -999999; + + var subframeEnabled = true; + var expressionsPlugin; + var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); + var cachedColors = {}; + var bm_rounder = Math.round; + var bm_rnd; + var bm_pow = Math.pow; + var bm_sqrt = Math.sqrt; + var bm_abs = Math.abs; + var bm_floor = Math.floor; + var bm_max = Math.max; + var bm_min = Math.min; + var blitter = 10; + + var BMMath = {}; + (function () { + var propertyNames = ["abs", "acos", "acosh", "asin", "asinh", "atan", "atanh", "atan2", "ceil", "cbrt", "expm1", "clz32", "cos", "cosh", "exp", "floor", "fround", "hypot", "imul", "log", "log1p", "log2", "log10", "max", "min", "pow", "random", "round", "sign", "sin", "sinh", "sqrt", "tan", "tanh", "trunc", "E", "LN10", "LN2", "LOG10E", "LOG2E", "PI", "SQRT1_2", "SQRT2"]; + var i, len = propertyNames.length; + for (i = 0; i < len; i += 1) { + BMMath[propertyNames[i]] = Math[propertyNames[i]]; + } + }()); + + function ProjectInterface() { return {}; } + + BMMath.random = Math.random; + BMMath.abs = function (val) { + var tOfVal = typeof val; + if (tOfVal === 'object' && val.length) { + var absArr = createSizedArray(val.length); + var i, len = val.length; + for (i = 0; i < len; i += 1) { + absArr[i] = Math.abs(val[i]); + } + return absArr; + } + return Math.abs(val); + + }; + var defaultCurveSegments = 150; + var degToRads = Math.PI / 180; + var roundCorner = 0.5519; + + function roundValues(flag) { + if (flag) { + bm_rnd = Math.round; + } else { + bm_rnd = function (val) { + return val; + }; + } + } + roundValues(false); + + function styleDiv(element) { + element.style.position = 'absolute'; + element.style.top = 0; + element.style.left = 0; + element.style.display = 'block'; + element.style.transformOrigin = element.style.webkitTransformOrigin = '0 0'; + element.style.backfaceVisibility = element.style.webkitBackfaceVisibility = 'visible'; + element.style.transformStyle = element.style.webkitTransformStyle = element.style.mozTransformStyle = "preserve-3d"; + } + + function BMEnterFrameEvent(type, currentTime, totalTime, frameMultiplier) { + this.type = type; + this.currentTime = currentTime; + this.totalTime = totalTime; + this.direction = frameMultiplier < 0 ? -1 : 1; + } + + function BMCompleteEvent(type, frameMultiplier) { + this.type = type; + this.direction = frameMultiplier < 0 ? -1 : 1; + } + + function BMCompleteLoopEvent(type, totalLoops, currentLoop, frameMultiplier) { + this.type = type; + this.currentLoop = currentLoop; + this.totalLoops = totalLoops; + this.direction = frameMultiplier < 0 ? -1 : 1; + } + + function BMSegmentStartEvent(type, firstFrame, totalFrames) { + this.type = type; + this.firstFrame = firstFrame; + this.totalFrames = totalFrames; + } + + function BMDestroyEvent(type, target) { + this.type = type; + this.target = target; + } + + function BMRenderFrameErrorEvent(nativeError, currentTime) { + this.type = 'renderFrameError'; + this.nativeError = nativeError; + this.currentTime = currentTime; + } + + function BMConfigErrorEvent(nativeError) { + this.type = 'configError'; + this.nativeError = nativeError; + } + + function BMAnimationConfigErrorEvent(type, nativeError) { + this.type = type; + this.nativeError = nativeError; + this.currentTime = currentTime; + } + + var createElementID = (function () { + var _count = 0; + return function createID() { + return '__lottie_element_' + ++_count + } + }()) + + function HSVtoRGB(h, s, v) { + var r, g, b, i, f, p, q, t; + i = Math.floor(h * 6); + f = h * 6 - i; + p = v * (1 - s); + q = v * (1 - f * s); + t = v * (1 - (1 - f) * s); + switch (i % 6) { + case 0: r = v; g = t; b = p; break; + case 1: r = q; g = v; b = p; break; + case 2: r = p; g = v; b = t; break; + case 3: r = p; g = q; b = v; break; + case 4: r = t; g = p; b = v; break; + case 5: r = v; g = p; b = q; break; + } + return [r, + g, + b]; + } + + function RGBtoHSV(r, g, b) { + var max = Math.max(r, g, b), min = Math.min(r, g, b), + d = max - min, + h, + s = (max === 0 ? 0 : d / max), + v = max / 255; + + switch (max) { + case min: h = 0; break; + case r: h = (g - b) + d * (g < b ? 6 : 0); h /= 6 * d; break; + case g: h = (b - r) + d * 2; h /= 6 * d; break; + case b: h = (r - g) + d * 4; h /= 6 * d; break; + } + + return [ + h, + s, + v + ]; + } + + function addSaturationToRGB(color, offset) { + var hsv = RGBtoHSV(color[0] * 255, color[1] * 255, color[2] * 255); + hsv[1] += offset; + if (hsv[1] > 1) { + hsv[1] = 1; + } + else if (hsv[1] <= 0) { + hsv[1] = 0; + } + return HSVtoRGB(hsv[0], hsv[1], hsv[2]); + } + + function addBrightnessToRGB(color, offset) { + var hsv = RGBtoHSV(color[0] * 255, color[1] * 255, color[2] * 255); + hsv[2] += offset; + if (hsv[2] > 1) { + hsv[2] = 1; + } + else if (hsv[2] < 0) { + hsv[2] = 0; + } + return HSVtoRGB(hsv[0], hsv[1], hsv[2]); + } + + function addHueToRGB(color, offset) { + var hsv = RGBtoHSV(color[0] * 255, color[1] * 255, color[2] * 255); + hsv[0] += offset / 360; + if (hsv[0] > 1) { + hsv[0] -= 1; + } + else if (hsv[0] < 0) { + hsv[0] += 1; + } + return HSVtoRGB(hsv[0], hsv[1], hsv[2]); + } + + var rgbToHex = (function () { + var colorMap = []; + var i; + var hex; + for (i = 0; i < 256; i += 1) { + hex = i.toString(16); + colorMap[i] = hex.length == 1 ? '0' + hex : hex; + } + + return function (r, g, b) { + if (r < 0) { + r = 0; + } + if (g < 0) { + g = 0; + } + if (b < 0) { + b = 0; + } + return '#' + colorMap[r] + colorMap[g] + colorMap[b]; + }; + }()); + function BaseEvent() { } + BaseEvent.prototype = { + triggerEvent: function (eventName, args) { + if (this._cbs[eventName]) { + var len = this._cbs[eventName].length; + for (var i = 0; i < len; i++) { + this._cbs[eventName][i](args); + } + } + }, + addEventListener: function (eventName, callback) { + if (!this._cbs[eventName]) { + this._cbs[eventName] = []; + } + this._cbs[eventName].push(callback); + + return function () { + this.removeEventListener(eventName, callback); + }.bind(this); + }, + removeEventListener: function (eventName, callback) { + if (!callback) { + this._cbs[eventName] = null; + } else if (this._cbs[eventName]) { + var i = 0, len = this._cbs[eventName].length; + while (i < len) { + if (this._cbs[eventName][i] === callback) { + this._cbs[eventName].splice(i, 1); + i -= 1; + len -= 1; + } + i += 1; + } + if (!this._cbs[eventName].length) { + this._cbs[eventName] = null; + } + } + } + }; + var createTypedArray = (function () { + function createRegularArray(type, len) { + var i = 0, arr = [], value; + switch (type) { + case 'int16': + case 'uint8c': + value = 1; + break; + default: + value = 1.1; + break; + } + for (i = 0; i < len; i += 1) { + arr.push(value); + } + return arr; + } + function createTypedArray(type, len) { + if (type === 'float32') { + return new Float32Array(len); + } else if (type === 'int16') { + return new Int16Array(len); + } else if (type === 'uint8c') { + return new Uint8ClampedArray(len); + } + } + if (typeof Uint8ClampedArray === 'function' && typeof Float32Array === 'function') { + return createTypedArray; + } else { + return createRegularArray; + } + }()); + + function createSizedArray(len) { + return Array.apply(null, { length: len }); + } + function createNS(type) { + //return {appendChild:function(){},setAttribute:function(){},style:{}} + return document.createElementNS(svgNS, type); + } + function createTag(type) { + //return {appendChild:function(){},setAttribute:function(){},style:{}} + return document.createElement(type); + } + function DynamicPropertyContainer() { }; + DynamicPropertyContainer.prototype = { + addDynamicProperty: function (prop) { + if (this.dynamicProperties.indexOf(prop) === -1) { + this.dynamicProperties.push(prop); + this.container.addDynamicProperty(this); + this._isAnimated = true; + } + }, + iterateDynamicProperties: function () { + this._mdf = false; + var i, len = this.dynamicProperties.length; + for (i = 0; i < len; i += 1) { + this.dynamicProperties[i].getValue(); + if (this.dynamicProperties[i]._mdf) { + this._mdf = true; + } + } + }, + initDynamicPropertyContainer: function (container) { + this.container = container; + this.dynamicProperties = []; + this._mdf = false; + this._isAnimated = false; + } + } + var getBlendMode = (function () { + + var blendModeEnums = { + 0: 'source-over', + 1: 'multiply', + 2: 'screen', + 3: 'overlay', + 4: 'darken', + 5: 'lighten', + 6: 'color-dodge', + 7: 'color-burn', + 8: 'hard-light', + 9: 'soft-light', + 10: 'difference', + 11: 'exclusion', + 12: 'hue', + 13: 'saturation', + 14: 'color', + 15: 'luminosity' + } + + return function (mode) { + return blendModeEnums[mode] || ''; + } + }()) + /*! + Transformation Matrix v2.0 + (c) Epistemex 2014-2015 + www.epistemex.com + By Ken Fyrstenberg + Contributions by leeoniya. + License: MIT, header required. + */ + + /** + * 2D transformation matrix object initialized with identity matrix. + * + * The matrix can synchronize a canvas context by supplying the context + * as an argument, or later apply current absolute transform to an + * existing context. + * + * All values are handled as floating point values. + * + * @param {CanvasRenderingContext2D} [context] - Optional context to sync with Matrix + * @prop {number} a - scale x + * @prop {number} b - shear y + * @prop {number} c - shear x + * @prop {number} d - scale y + * @prop {number} e - translate x + * @prop {number} f - translate y + * @prop {CanvasRenderingContext2D|null} [context=null] - set or get current canvas context + * @constructor + */ + + var Matrix = (function () { + + var _cos = Math.cos; + var _sin = Math.sin; + var _tan = Math.tan; + var _rnd = Math.round; + + function reset() { + this.props[0] = 1; + this.props[1] = 0; + this.props[2] = 0; + this.props[3] = 0; + this.props[4] = 0; + this.props[5] = 1; + this.props[6] = 0; + this.props[7] = 0; + this.props[8] = 0; + this.props[9] = 0; + this.props[10] = 1; + this.props[11] = 0; + this.props[12] = 0; + this.props[13] = 0; + this.props[14] = 0; + this.props[15] = 1; + return this; + } + + function rotate(angle) { + if (angle === 0) { + return this; + } + var mCos = _cos(angle); + var mSin = _sin(angle); + return this._t(mCos, -mSin, 0, 0, mSin, mCos, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); + } + + function rotateX(angle) { + if (angle === 0) { + return this; + } + var mCos = _cos(angle); + var mSin = _sin(angle); + return this._t(1, 0, 0, 0, 0, mCos, -mSin, 0, 0, mSin, mCos, 0, 0, 0, 0, 1); + } + + function rotateY(angle) { + if (angle === 0) { + return this; + } + var mCos = _cos(angle); + var mSin = _sin(angle); + return this._t(mCos, 0, mSin, 0, 0, 1, 0, 0, -mSin, 0, mCos, 0, 0, 0, 0, 1); + } + + function rotateZ(angle) { + if (angle === 0) { + return this; + } + var mCos = _cos(angle); + var mSin = _sin(angle); + return this._t(mCos, -mSin, 0, 0, mSin, mCos, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); + } + + function shear(sx, sy) { + return this._t(1, sy, sx, 1, 0, 0); + } + + function skew(ax, ay) { + return this.shear(_tan(ax), _tan(ay)); + } + + function skewFromAxis(ax, angle) { + var mCos = _cos(angle); + var mSin = _sin(angle); + return this._t(mCos, mSin, 0, 0, -mSin, mCos, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1) + ._t(1, 0, 0, 0, _tan(ax), 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1) + ._t(mCos, -mSin, 0, 0, mSin, mCos, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); + //return this._t(mCos, mSin, -mSin, mCos, 0, 0)._t(1, 0, _tan(ax), 1, 0, 0)._t(mCos, -mSin, mSin, mCos, 0, 0); + } + + function scale(sx, sy, sz) { + if (!sz && sz !== 0) { + sz = 1; + } + if (sx === 1 && sy === 1 && sz === 1) { + return this; + } + return this._t(sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, sz, 0, 0, 0, 0, 1); + } + + function setTransform(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) { + this.props[0] = a; + this.props[1] = b; + this.props[2] = c; + this.props[3] = d; + this.props[4] = e; + this.props[5] = f; + this.props[6] = g; + this.props[7] = h; + this.props[8] = i; + this.props[9] = j; + this.props[10] = k; + this.props[11] = l; + this.props[12] = m; + this.props[13] = n; + this.props[14] = o; + this.props[15] = p; + return this; + } + + function translate(tx, ty, tz) { + tz = tz || 0; + if (tx !== 0 || ty !== 0 || tz !== 0) { + return this._t(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, tx, ty, tz, 1); + } + return this; + } + + function transform(a2, b2, c2, d2, e2, f2, g2, h2, i2, j2, k2, l2, m2, n2, o2, p2) { + + var _p = this.props; + + if (a2 === 1 && b2 === 0 && c2 === 0 && d2 === 0 && e2 === 0 && f2 === 1 && g2 === 0 && h2 === 0 && i2 === 0 && j2 === 0 && k2 === 1 && l2 === 0) { + //NOTE: commenting this condition because TurboFan deoptimizes code when present + //if(m2 !== 0 || n2 !== 0 || o2 !== 0){ + _p[12] = _p[12] * a2 + _p[15] * m2; + _p[13] = _p[13] * f2 + _p[15] * n2; + _p[14] = _p[14] * k2 + _p[15] * o2; + _p[15] = _p[15] * p2; + //} + this._identityCalculated = false; + return this; + } + + var a1 = _p[0]; + var b1 = _p[1]; + var c1 = _p[2]; + var d1 = _p[3]; + var e1 = _p[4]; + var f1 = _p[5]; + var g1 = _p[6]; + var h1 = _p[7]; + var i1 = _p[8]; + var j1 = _p[9]; + var k1 = _p[10]; + var l1 = _p[11]; + var m1 = _p[12]; + var n1 = _p[13]; + var o1 = _p[14]; + var p1 = _p[15]; + + /* matrix order (canvas compatible): + * ace + * bdf + * 001 + */ + _p[0] = a1 * a2 + b1 * e2 + c1 * i2 + d1 * m2; + _p[1] = a1 * b2 + b1 * f2 + c1 * j2 + d1 * n2; + _p[2] = a1 * c2 + b1 * g2 + c1 * k2 + d1 * o2; + _p[3] = a1 * d2 + b1 * h2 + c1 * l2 + d1 * p2; + + _p[4] = e1 * a2 + f1 * e2 + g1 * i2 + h1 * m2; + _p[5] = e1 * b2 + f1 * f2 + g1 * j2 + h1 * n2; + _p[6] = e1 * c2 + f1 * g2 + g1 * k2 + h1 * o2; + _p[7] = e1 * d2 + f1 * h2 + g1 * l2 + h1 * p2; + + _p[8] = i1 * a2 + j1 * e2 + k1 * i2 + l1 * m2; + _p[9] = i1 * b2 + j1 * f2 + k1 * j2 + l1 * n2; + _p[10] = i1 * c2 + j1 * g2 + k1 * k2 + l1 * o2; + _p[11] = i1 * d2 + j1 * h2 + k1 * l2 + l1 * p2; + + _p[12] = m1 * a2 + n1 * e2 + o1 * i2 + p1 * m2; + _p[13] = m1 * b2 + n1 * f2 + o1 * j2 + p1 * n2; + _p[14] = m1 * c2 + n1 * g2 + o1 * k2 + p1 * o2; + _p[15] = m1 * d2 + n1 * h2 + o1 * l2 + p1 * p2; + + this._identityCalculated = false; + return this; + } + + function isIdentity() { + if (!this._identityCalculated) { + this._identity = !(this.props[0] !== 1 || this.props[1] !== 0 || this.props[2] !== 0 || this.props[3] !== 0 || this.props[4] !== 0 || this.props[5] !== 1 || this.props[6] !== 0 || this.props[7] !== 0 || this.props[8] !== 0 || this.props[9] !== 0 || this.props[10] !== 1 || this.props[11] !== 0 || this.props[12] !== 0 || this.props[13] !== 0 || this.props[14] !== 0 || this.props[15] !== 1); + this._identityCalculated = true; + } + return this._identity; + } + + function equals(matr) { + var i = 0; + while (i < 16) { + if (matr.props[i] !== this.props[i]) { + return false; + } + i += 1; + } + return true; + } + + function clone(matr) { + var i; + for (i = 0; i < 16; i += 1) { + matr.props[i] = this.props[i]; + } + } + + function cloneFromProps(props) { + var i; + for (i = 0; i < 16; i += 1) { + this.props[i] = props[i]; + } + } + + function applyToPoint(x, y, z) { + + return { + x: x * this.props[0] + y * this.props[4] + z * this.props[8] + this.props[12], + y: x * this.props[1] + y * this.props[5] + z * this.props[9] + this.props[13], + z: x * this.props[2] + y * this.props[6] + z * this.props[10] + this.props[14] + }; + /*return { + x: x * me.a + y * me.c + me.e, + y: x * me.b + y * me.d + me.f + };*/ + } + function applyToX(x, y, z) { + return x * this.props[0] + y * this.props[4] + z * this.props[8] + this.props[12]; + } + function applyToY(x, y, z) { + return x * this.props[1] + y * this.props[5] + z * this.props[9] + this.props[13]; + } + function applyToZ(x, y, z) { + return x * this.props[2] + y * this.props[6] + z * this.props[10] + this.props[14]; + } + + function getInverseMatrix() { + var determinant = this.props[0] * this.props[5] - this.props[1] * this.props[4]; + var a = this.props[5] / determinant; + var b = - this.props[1] / determinant; + var c = - this.props[4] / determinant; + var d = this.props[0] / determinant; + var e = (this.props[4] * this.props[13] - this.props[5] * this.props[12]) / determinant; + var f = - (this.props[0] * this.props[13] - this.props[1] * this.props[12]) / determinant; + var inverseMatrix = new Matrix(); + inverseMatrix.props[0] = a; + inverseMatrix.props[1] = b; + inverseMatrix.props[4] = c; + inverseMatrix.props[5] = d; + inverseMatrix.props[12] = e; + inverseMatrix.props[13] = f; + return inverseMatrix; + } + + function inversePoint(pt) { + var inverseMatrix = this.getInverseMatrix(); + return inverseMatrix.applyToPointArray(pt[0], pt[1], pt[2] || 0) + } + + function inversePoints(pts) { + var i, len = pts.length, retPts = []; + for (i = 0; i < len; i += 1) { + retPts[i] = inversePoint(pts[i]); + } + return retPts; + } + + function applyToTriplePoints(pt1, pt2, pt3) { + var arr = createTypedArray('float32', 6); + if (this.isIdentity()) { + arr[0] = pt1[0]; + arr[1] = pt1[1]; + arr[2] = pt2[0]; + arr[3] = pt2[1]; + arr[4] = pt3[0]; + arr[5] = pt3[1]; + } else { + var p0 = this.props[0], p1 = this.props[1], p4 = this.props[4], p5 = this.props[5], p12 = this.props[12], p13 = this.props[13]; + arr[0] = pt1[0] * p0 + pt1[1] * p4 + p12; + arr[1] = pt1[0] * p1 + pt1[1] * p5 + p13; + arr[2] = pt2[0] * p0 + pt2[1] * p4 + p12; + arr[3] = pt2[0] * p1 + pt2[1] * p5 + p13; + arr[4] = pt3[0] * p0 + pt3[1] * p4 + p12; + arr[5] = pt3[0] * p1 + pt3[1] * p5 + p13; + } + return arr; + } + + function applyToPointArray(x, y, z) { + var arr; + if (this.isIdentity()) { + arr = [x, y, z]; + } else { + arr = [x * this.props[0] + y * this.props[4] + z * this.props[8] + this.props[12], x * this.props[1] + y * this.props[5] + z * this.props[9] + this.props[13], x * this.props[2] + y * this.props[6] + z * this.props[10] + this.props[14]]; + } + return arr; + } + + function applyToPointStringified(x, y) { + if (this.isIdentity()) { + return x + ',' + y; + } + var _p = this.props; + return Math.round((x * _p[0] + y * _p[4] + _p[12]) * 100) / 100 + ',' + Math.round((x * _p[1] + y * _p[5] + _p[13]) * 100) / 100; + } + + function toCSS() { + //Doesn't make much sense to add this optimization. If it is an identity matrix, it's very likely this will get called only once since it won't be keyframed. + /*if(this.isIdentity()) { + return ''; + }*/ + var i = 0; + var props = this.props; + var cssValue = 'matrix3d('; + var v = 10000; + while (i < 16) { + cssValue += _rnd(props[i] * v) / v; + cssValue += i === 15 ? ')' : ','; + i += 1; + } + return cssValue; + } + + function roundMatrixProperty(val) { + var v = 10000; + if ((val < 0.000001 && val > 0) || (val > -0.000001 && val < 0)) { + return _rnd(val * v) / v; + } + return val; + } + + function to2dCSS() { + //Doesn't make much sense to add this optimization. If it is an identity matrix, it's very likely this will get called only once since it won't be keyframed. + /*if(this.isIdentity()) { + return ''; + }*/ + var props = this.props; + var _a = roundMatrixProperty(props[0]); + var _b = roundMatrixProperty(props[1]); + var _c = roundMatrixProperty(props[4]); + var _d = roundMatrixProperty(props[5]); + var _e = roundMatrixProperty(props[12]); + var _f = roundMatrixProperty(props[13]); + return "matrix(" + _a + ',' + _b + ',' + _c + ',' + _d + ',' + _e + ',' + _f + ")"; + } + + return function () { + this.reset = reset; + this.rotate = rotate; + this.rotateX = rotateX; + this.rotateY = rotateY; + this.rotateZ = rotateZ; + this.skew = skew; + this.skewFromAxis = skewFromAxis; + this.shear = shear; + this.scale = scale; + this.setTransform = setTransform; + this.translate = translate; + this.transform = transform; + this.applyToPoint = applyToPoint; + this.applyToX = applyToX; + this.applyToY = applyToY; + this.applyToZ = applyToZ; + this.applyToPointArray = applyToPointArray; + this.applyToTriplePoints = applyToTriplePoints; + this.applyToPointStringified = applyToPointStringified; + this.toCSS = toCSS; + this.to2dCSS = to2dCSS; + this.clone = clone; + this.cloneFromProps = cloneFromProps; + this.equals = equals; + this.inversePoints = inversePoints; + this.inversePoint = inversePoint; + this.getInverseMatrix = getInverseMatrix; + this._t = this.transform; + this.isIdentity = isIdentity; + this._identity = true; + this._identityCalculated = false; + + this.props = createTypedArray('float32', 16); + this.reset(); + }; + }()); + + /* + Copyright 2014 David Bau. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + */ + + (function (pool, math) { + // + // The following constants are related to IEEE 754 limits. + // + var global = this, + width = 256, // each RC4 output is 0 <= x < 256 + chunks = 6, // at least six RC4 outputs for each double + digits = 52, // there are 52 significant digits in a double + rngname = 'random', // rngname: name for Math.random and Math.seedrandom + startdenom = math.pow(width, chunks), + significance = math.pow(2, digits), + overflow = significance * 2, + mask = width - 1, + nodecrypto; // node.js crypto module, initialized at the bottom. + + // + // seedrandom() + // This is the seedrandom function described above. + // + function seedrandom(seed, options, callback) { + var key = []; + options = (options === true) ? { entropy: true } : (options || {}); + + // Flatten the seed string or build one from local entropy if needed. + var shortseed = mixkey(flatten( + options.entropy ? [seed, tostring(pool)] : + (seed === null) ? autoseed() : seed, 3), key); + + // Use the seed to initialize an ARC4 generator. + var arc4 = new ARC4(key); + + // This function returns a random double in [0, 1) that contains + // randomness in every bit of the mantissa of the IEEE 754 value. + var prng = function () { + var n = arc4.g(chunks), // Start with a numerator n < 2 ^ 48 + d = startdenom, // and denominator d = 2 ^ 48. + x = 0; // and no 'extra last byte'. + while (n < significance) { // Fill up all significant digits by + n = (n + x) * width; // shifting numerator and + d *= width; // denominator and generating a + x = arc4.g(1); // new least-significant-byte. + } + while (n >= overflow) { // To avoid rounding up, before adding + n /= 2; // last byte, shift everything + d /= 2; // right using integer math until + x >>>= 1; // we have exactly the desired bits. + } + return (n + x) / d; // Form the number within [0, 1). + }; + + prng.int32 = function () { return arc4.g(4) | 0; }; + prng.quick = function () { return arc4.g(4) / 0x100000000; }; + prng.double = prng; + + // Mix the randomness into accumulated entropy. + mixkey(tostring(arc4.S), pool); + + // Calling convention: what to return as a function of prng, seed, is_math. + return (options.pass || callback || + function (prng, seed, is_math_call, state) { + if (state) { + // Load the arc4 state from the given state if it has an S array. + if (state.S) { copy(state, arc4); } + // Only provide the .state method if requested via options.state. + prng.state = function () { return copy(arc4, {}); }; + } + + // If called as a method of Math (Math.seedrandom()), mutate + // Math.random because that is how seedrandom.js has worked since v1.0. + if (is_math_call) { math[rngname] = prng; return seed; } + + // Otherwise, it is a newer calling convention, so return the + // prng directly. + else return prng; + })( + prng, + shortseed, + 'global' in options ? options.global : (this == math), + options.state); + } + math['seed' + rngname] = seedrandom; + + // + // ARC4 + // + // An ARC4 implementation. The constructor takes a key in the form of + // an array of at most (width) integers that should be 0 <= x < (width). + // + // The g(count) method returns a pseudorandom integer that concatenates + // the next (count) outputs from ARC4. Its return value is a number x + // that is in the range 0 <= x < (width ^ count). + // + function ARC4(key) { + var t, keylen = key.length, + me = this, i = 0, j = me.i = me.j = 0, s = me.S = []; + + // The empty key [] is treated as [0]. + if (!keylen) { key = [keylen++]; } + + // Set up S using the standard key scheduling algorithm. + while (i < width) { + s[i] = i++; + } + for (i = 0; i < width; i++) { + s[i] = s[j = mask & (j + key[i % keylen] + (t = s[i]))]; + s[j] = t; + } + + // The "g" method returns the next (count) outputs as one number. + me.g = function (count) { + // Using instance members instead of closure state nearly doubles speed. + var t, r = 0, + i = me.i, j = me.j, s = me.S; + while (count--) { + t = s[i = mask & (i + 1)]; + r = r * width + s[mask & ((s[i] = s[j = mask & (j + t)]) + (s[j] = t))]; + } + me.i = i; me.j = j; + return r; + // For robust unpredictability, the function call below automatically + // discards an initial batch of values. This is called RC4-drop[256]. + // See http://google.com/search?q=rsa+fluhrer+response&btnI + }; + } + + // + // copy() + // Copies internal state of ARC4 to or from a plain object. + // + function copy(f, t) { + t.i = f.i; + t.j = f.j; + t.S = f.S.slice(); + return t; + } + + // + // flatten() + // Converts an object tree to nested arrays of strings. + // + function flatten(obj, depth) { + var result = [], typ = (typeof obj), prop; + if (depth && typ == 'object') { + for (prop in obj) { + try { result.push(flatten(obj[prop], depth - 1)); } catch (e) { } + } + } + return (result.length ? result : typ == 'string' ? obj : obj + '\0'); + } + + // + // mixkey() + // Mixes a string seed into a key that is an array of integers, and + // returns a shortened string seed that is equivalent to the result key. + // + function mixkey(seed, key) { + var stringseed = seed + '', smear, j = 0; + while (j < stringseed.length) { + key[mask & j] = + mask & ((smear ^= key[mask & j] * 19) + stringseed.charCodeAt(j++)); + } + return tostring(key); + } + + // + // autoseed() + // Returns an object for autoseeding, using window.crypto and Node crypto + // module if available. + // + function autoseed() { + try { + if (nodecrypto) { return tostring(nodecrypto.randomBytes(width)); } + var out = new Uint8Array(width); + (global.crypto || global.msCrypto).getRandomValues(out); + return tostring(out); + } catch (e) { + var browser = global.navigator, + plugins = browser && browser.plugins; + return [+new Date(), global, plugins, global.screen, tostring(pool)]; + } + } + + // + // tostring() + // Converts an array of charcodes to a string + // + function tostring(a) { + return String.fromCharCode.apply(0, a); + } + + // + // When seedrandom.js is loaded, we immediately mix a few bits + // from the built-in RNG into the entropy pool. Because we do + // not want to interfere with deterministic PRNG state later, + // seedrandom will not call math.random on its own again after + // initialization. + // + mixkey(math.random(), pool); + + // + // Nodejs and AMD support: export the implementation as a module using + // either convention. + // + + // End anonymous scope, and pass initial values. + })( + [], // pool: entropy pool starts empty + BMMath // math: package containing random, pow, and seedrandom + ); + var BezierFactory = (function () { + /** + * BezierEasing - use bezier curve for transition easing function + * by Gaëtan Renaudeau 2014 - 2015 – MIT License + * + * Credits: is based on Firefox's nsSMILKeySpline.cpp + * Usage: + * var spline = BezierEasing([ 0.25, 0.1, 0.25, 1.0 ]) + * spline.get(x) => returns the easing value | x must be in [0, 1] range + * + */ + + var ob = {}; + ob.getBezierEasing = getBezierEasing; + var beziers = {}; + + function getBezierEasing(a, b, c, d, nm) { + var str = nm || ('bez_' + a + '_' + b + '_' + c + '_' + d).replace(/\./g, 'p'); + if (beziers[str]) { + return beziers[str]; + } + var bezEasing = new BezierEasing([a, b, c, d]); + beziers[str] = bezEasing; + return bezEasing; + } + + // These values are established by empiricism with tests (tradeoff: performance VS precision) + var NEWTON_ITERATIONS = 4; + var NEWTON_MIN_SLOPE = 0.001; + var SUBDIVISION_PRECISION = 0.0000001; + var SUBDIVISION_MAX_ITERATIONS = 10; + + var kSplineTableSize = 11; + var kSampleStepSize = 1.0 / (kSplineTableSize - 1.0); + + var float32ArraySupported = typeof Float32Array === "function"; + + function A(aA1, aA2) { return 1.0 - 3.0 * aA2 + 3.0 * aA1; } + function B(aA1, aA2) { return 3.0 * aA2 - 6.0 * aA1; } + function C(aA1) { return 3.0 * aA1; } + + // Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2. + function calcBezier(aT, aA1, aA2) { + return ((A(aA1, aA2) * aT + B(aA1, aA2)) * aT + C(aA1)) * aT; + } + + // Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2. + function getSlope(aT, aA1, aA2) { + return 3.0 * A(aA1, aA2) * aT * aT + 2.0 * B(aA1, aA2) * aT + C(aA1); + } + + function binarySubdivide(aX, aA, aB, mX1, mX2) { + var currentX, currentT, i = 0; + do { + currentT = aA + (aB - aA) / 2.0; + currentX = calcBezier(currentT, mX1, mX2) - aX; + if (currentX > 0.0) { + aB = currentT; + } else { + aA = currentT; + } + } while (Math.abs(currentX) > SUBDIVISION_PRECISION && ++i < SUBDIVISION_MAX_ITERATIONS); + return currentT; + } + + function newtonRaphsonIterate(aX, aGuessT, mX1, mX2) { + for (var i = 0; i < NEWTON_ITERATIONS; ++i) { + var currentSlope = getSlope(aGuessT, mX1, mX2); + if (currentSlope === 0.0) return aGuessT; + var currentX = calcBezier(aGuessT, mX1, mX2) - aX; + aGuessT -= currentX / currentSlope; + } + return aGuessT; + } + + /** + * points is an array of [ mX1, mY1, mX2, mY2 ] + */ + function BezierEasing(points) { + this._p = points; + this._mSampleValues = float32ArraySupported ? new Float32Array(kSplineTableSize) : new Array(kSplineTableSize); + this._precomputed = false; + + this.get = this.get.bind(this); + } + + BezierEasing.prototype = { + + get: function (x) { + var mX1 = this._p[0], + mY1 = this._p[1], + mX2 = this._p[2], + mY2 = this._p[3]; + if (!this._precomputed) this._precompute(); + if (mX1 === mY1 && mX2 === mY2) return x; // linear + // Because JavaScript number are imprecise, we should guarantee the extremes are right. + if (x === 0) return 0; + if (x === 1) return 1; + return calcBezier(this._getTForX(x), mY1, mY2); + }, + + // Private part + + _precompute: function () { + var mX1 = this._p[0], + mY1 = this._p[1], + mX2 = this._p[2], + mY2 = this._p[3]; + this._precomputed = true; + if (mX1 !== mY1 || mX2 !== mY2) + this._calcSampleValues(); + }, + + _calcSampleValues: function () { + var mX1 = this._p[0], + mX2 = this._p[2]; + for (var i = 0; i < kSplineTableSize; ++i) { + this._mSampleValues[i] = calcBezier(i * kSampleStepSize, mX1, mX2); + } + }, + + /** + * getTForX chose the fastest heuristic to determine the percentage value precisely from a given X projection. + */ + _getTForX: function (aX) { + var mX1 = this._p[0], + mX2 = this._p[2], + mSampleValues = this._mSampleValues; + + var intervalStart = 0.0; + var currentSample = 1; + var lastSample = kSplineTableSize - 1; + + for (; currentSample !== lastSample && mSampleValues[currentSample] <= aX; ++currentSample) { + intervalStart += kSampleStepSize; + } + --currentSample; + + // Interpolate to provide an initial guess for t + var dist = (aX - mSampleValues[currentSample]) / (mSampleValues[currentSample + 1] - mSampleValues[currentSample]); + var guessForT = intervalStart + dist * kSampleStepSize; + + var initialSlope = getSlope(guessForT, mX1, mX2); + if (initialSlope >= NEWTON_MIN_SLOPE) { + return newtonRaphsonIterate(aX, guessForT, mX1, mX2); + } else if (initialSlope === 0.0) { + return guessForT; + } else { + return binarySubdivide(aX, intervalStart, intervalStart + kSampleStepSize, mX1, mX2); + } + } + }; + + return ob; + + }()); + (function () { + var lastTime = 0; + var vendors = ['ms', 'moz', 'webkit', 'o']; + for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { + window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame']; + window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || window[vendors[x] + 'CancelRequestAnimationFrame']; + } + if (!window.requestAnimationFrame) + window.requestAnimationFrame = function (callback, element) { + var currTime = new Date().getTime(); + var timeToCall = Math.max(0, 16 - (currTime - lastTime)); + var id = setTimeout(function () { + callback(currTime + timeToCall); + }, + timeToCall); + lastTime = currTime + timeToCall; + return id; + }; + if (!window.cancelAnimationFrame) + window.cancelAnimationFrame = function (id) { + clearTimeout(id); + }; + }()); + + function extendPrototype(sources, destination) { + var i, len = sources.length, sourcePrototype; + for (i = 0; i < len; i += 1) { + sourcePrototype = sources[i].prototype; + for (var attr in sourcePrototype) { + if (sourcePrototype.hasOwnProperty(attr)) destination.prototype[attr] = sourcePrototype[attr]; + } + } + } + + function getDescriptor(object, prop) { + return Object.getOwnPropertyDescriptor(object, prop); + } + + function createProxyFunction(prototype) { + function ProxyFunction() { } + ProxyFunction.prototype = prototype; + return ProxyFunction; + } + function bezFunction() { + + var easingFunctions = []; + var math = Math; + + function pointOnLine2D(x1, y1, x2, y2, x3, y3) { + var det1 = (x1 * y2) + (y1 * x3) + (x2 * y3) - (x3 * y2) - (y3 * x1) - (x2 * y1); + return det1 > -0.001 && det1 < 0.001; + } + + function pointOnLine3D(x1, y1, z1, x2, y2, z2, x3, y3, z3) { + if (z1 === 0 && z2 === 0 && z3 === 0) { + return pointOnLine2D(x1, y1, x2, y2, x3, y3); + } + var dist1 = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2) + Math.pow(z2 - z1, 2)); + var dist2 = Math.sqrt(Math.pow(x3 - x1, 2) + Math.pow(y3 - y1, 2) + Math.pow(z3 - z1, 2)); + var dist3 = Math.sqrt(Math.pow(x3 - x2, 2) + Math.pow(y3 - y2, 2) + Math.pow(z3 - z2, 2)); + var diffDist; + if (dist1 > dist2) { + if (dist1 > dist3) { + diffDist = dist1 - dist2 - dist3; + } else { + diffDist = dist3 - dist2 - dist1; + } + } else if (dist3 > dist2) { + diffDist = dist3 - dist2 - dist1; + } else { + diffDist = dist2 - dist1 - dist3; + } + return diffDist > -0.0001 && diffDist < 0.0001; + } + + var getBezierLength = (function () { + + return function (pt1, pt2, pt3, pt4) { + var curveSegments = defaultCurveSegments; + var k; + var i, len; + var ptCoord, perc, addedLength = 0; + var ptDistance; + var point = [], lastPoint = []; + var lengthData = bezier_length_pool.newElement(); + len = pt3.length; + for (k = 0; k < curveSegments; k += 1) { + perc = k / (curveSegments - 1); + ptDistance = 0; + for (i = 0; i < len; i += 1) { + ptCoord = bm_pow(1 - perc, 3) * pt1[i] + 3 * bm_pow(1 - perc, 2) * perc * pt3[i] + 3 * (1 - perc) * bm_pow(perc, 2) * pt4[i] + bm_pow(perc, 3) * pt2[i]; + point[i] = ptCoord; + if (lastPoint[i] !== null) { + ptDistance += bm_pow(point[i] - lastPoint[i], 2); + } + lastPoint[i] = point[i]; + } + if (ptDistance) { + ptDistance = bm_sqrt(ptDistance); + addedLength += ptDistance; + } + lengthData.percents[k] = perc; + lengthData.lengths[k] = addedLength; + } + lengthData.addedLength = addedLength; + return lengthData; + }; + }()); + + function getSegmentsLength(shapeData) { + var segmentsLength = segments_length_pool.newElement(); + var closed = shapeData.c; + var pathV = shapeData.v; + var pathO = shapeData.o; + var pathI = shapeData.i; + var i, len = shapeData._length; + var lengths = segmentsLength.lengths; + var totalLength = 0; + for (i = 0; i < len - 1; i += 1) { + lengths[i] = getBezierLength(pathV[i], pathV[i + 1], pathO[i], pathI[i + 1]); + totalLength += lengths[i].addedLength; + } + if (closed && len) { + lengths[i] = getBezierLength(pathV[i], pathV[0], pathO[i], pathI[0]); + totalLength += lengths[i].addedLength; + } + segmentsLength.totalLength = totalLength; + return segmentsLength; + } + + function BezierData(length) { + this.segmentLength = 0; + this.points = new Array(length); + } + + function PointData(partial, point) { + this.partialLength = partial; + this.point = point; + } + + var buildBezierData = (function () { + + var storedData = {}; + + return function (pt1, pt2, pt3, pt4) { + var bezierName = (pt1[0] + '_' + pt1[1] + '_' + pt2[0] + '_' + pt2[1] + '_' + pt3[0] + '_' + pt3[1] + '_' + pt4[0] + '_' + pt4[1]).replace(/\./g, 'p'); + if (!storedData[bezierName]) { + var curveSegments = defaultCurveSegments; + var k, i, len; + var ptCoord, perc, addedLength = 0; + var ptDistance; + var point, lastPoint = null; + if (pt1.length === 2 && (pt1[0] != pt2[0] || pt1[1] != pt2[1]) && pointOnLine2D(pt1[0], pt1[1], pt2[0], pt2[1], pt1[0] + pt3[0], pt1[1] + pt3[1]) && pointOnLine2D(pt1[0], pt1[1], pt2[0], pt2[1], pt2[0] + pt4[0], pt2[1] + pt4[1])) { + curveSegments = 2; + } + var bezierData = new BezierData(curveSegments); + len = pt3.length; + for (k = 0; k < curveSegments; k += 1) { + point = createSizedArray(len); + perc = k / (curveSegments - 1); + ptDistance = 0; + for (i = 0; i < len; i += 1) { + ptCoord = bm_pow(1 - perc, 3) * pt1[i] + 3 * bm_pow(1 - perc, 2) * perc * (pt1[i] + pt3[i]) + 3 * (1 - perc) * bm_pow(perc, 2) * (pt2[i] + pt4[i]) + bm_pow(perc, 3) * pt2[i]; + point[i] = ptCoord; + if (lastPoint !== null) { + ptDistance += bm_pow(point[i] - lastPoint[i], 2); + } + } + ptDistance = bm_sqrt(ptDistance); + addedLength += ptDistance; + bezierData.points[k] = new PointData(ptDistance, point); + lastPoint = point; + } + bezierData.segmentLength = addedLength; + storedData[bezierName] = bezierData; + } + return storedData[bezierName]; + }; + }()); + + function getDistancePerc(perc, bezierData) { + var percents = bezierData.percents; + var lengths = bezierData.lengths; + var len = percents.length; + var initPos = bm_floor((len - 1) * perc); + var lengthPos = perc * bezierData.addedLength; + var lPerc = 0; + if (initPos === len - 1 || initPos === 0 || lengthPos === lengths[initPos]) { + return percents[initPos]; + } else { + var dir = lengths[initPos] > lengthPos ? -1 : 1; + var flag = true; + while (flag) { + if (lengths[initPos] <= lengthPos && lengths[initPos + 1] > lengthPos) { + lPerc = (lengthPos - lengths[initPos]) / (lengths[initPos + 1] - lengths[initPos]); + flag = false; + } else { + initPos += dir; + } + if (initPos < 0 || initPos >= len - 1) { + //FIX for TypedArrays that don't store floating point values with enough accuracy + if (initPos === len - 1) { + return percents[initPos]; + } + flag = false; + } + } + return percents[initPos] + (percents[initPos + 1] - percents[initPos]) * lPerc; + } + } + + function getPointInSegment(pt1, pt2, pt3, pt4, percent, bezierData) { + var t1 = getDistancePerc(percent, bezierData); + var u0 = 1; + var u1 = 1 - t1; + var ptX = Math.round((u1 * u1 * u1 * pt1[0] + (t1 * u1 * u1 + u1 * t1 * u1 + u1 * u1 * t1) * pt3[0] + (t1 * t1 * u1 + u1 * t1 * t1 + t1 * u1 * t1) * pt4[0] + t1 * t1 * t1 * pt2[0]) * 1000) / 1000; + var ptY = Math.round((u1 * u1 * u1 * pt1[1] + (t1 * u1 * u1 + u1 * t1 * u1 + u1 * u1 * t1) * pt3[1] + (t1 * t1 * u1 + u1 * t1 * t1 + t1 * u1 * t1) * pt4[1] + t1 * t1 * t1 * pt2[1]) * 1000) / 1000; + return [ptX, ptY]; + } + + function getSegmentArray() { + + } + + var bezier_segment_points = createTypedArray('float32', 8); + + function getNewSegment(pt1, pt2, pt3, pt4, startPerc, endPerc, bezierData) { + + startPerc = startPerc < 0 ? 0 : startPerc > 1 ? 1 : startPerc; + var t0 = getDistancePerc(startPerc, bezierData); + endPerc = endPerc > 1 ? 1 : endPerc; + var t1 = getDistancePerc(endPerc, bezierData); + var i, len = pt1.length; + var u0 = 1 - t0; + var u1 = 1 - t1; + var u0u0u0 = u0 * u0 * u0; + var t0u0u0_3 = t0 * u0 * u0 * 3; + var t0t0u0_3 = t0 * t0 * u0 * 3; + var t0t0t0 = t0 * t0 * t0; + // + var u0u0u1 = u0 * u0 * u1; + var t0u0u1_3 = t0 * u0 * u1 + u0 * t0 * u1 + u0 * u0 * t1; + var t0t0u1_3 = t0 * t0 * u1 + u0 * t0 * t1 + t0 * u0 * t1; + var t0t0t1 = t0 * t0 * t1; + // + var u0u1u1 = u0 * u1 * u1; + var t0u1u1_3 = t0 * u1 * u1 + u0 * t1 * u1 + u0 * u1 * t1; + var t0t1u1_3 = t0 * t1 * u1 + u0 * t1 * t1 + t0 * u1 * t1; + var t0t1t1 = t0 * t1 * t1; + // + var u1u1u1 = u1 * u1 * u1; + var t1u1u1_3 = t1 * u1 * u1 + u1 * t1 * u1 + u1 * u1 * t1; + var t1t1u1_3 = t1 * t1 * u1 + u1 * t1 * t1 + t1 * u1 * t1; + var t1t1t1 = t1 * t1 * t1; + for (i = 0; i < len; i += 1) { + bezier_segment_points[i * 4] = Math.round((u0u0u0 * pt1[i] + t0u0u0_3 * pt3[i] + t0t0u0_3 * pt4[i] + t0t0t0 * pt2[i]) * 1000) / 1000; + bezier_segment_points[i * 4 + 1] = Math.round((u0u0u1 * pt1[i] + t0u0u1_3 * pt3[i] + t0t0u1_3 * pt4[i] + t0t0t1 * pt2[i]) * 1000) / 1000; + bezier_segment_points[i * 4 + 2] = Math.round((u0u1u1 * pt1[i] + t0u1u1_3 * pt3[i] + t0t1u1_3 * pt4[i] + t0t1t1 * pt2[i]) * 1000) / 1000; + bezier_segment_points[i * 4 + 3] = Math.round((u1u1u1 * pt1[i] + t1u1u1_3 * pt3[i] + t1t1u1_3 * pt4[i] + t1t1t1 * pt2[i]) * 1000) / 1000; + } + + return bezier_segment_points; + } + + return { + getSegmentsLength: getSegmentsLength, + getNewSegment: getNewSegment, + getPointInSegment: getPointInSegment, + buildBezierData: buildBezierData, + pointOnLine2D: pointOnLine2D, + pointOnLine3D: pointOnLine3D + }; + } + + var bez = bezFunction(); + function dataFunctionManager() { + + //var tCanvasHelper = createTag('canvas').getContext('2d'); + + function completeLayers(layers, comps, fontManager) { + var layerData; + var animArray, lastFrame; + var i, len = layers.length; + var j, jLen, k, kLen; + for (i = 0; i < len; i += 1) { + layerData = layers[i]; + if (!('ks' in layerData) || layerData.completed) { + continue; + } + layerData.completed = true; + if (layerData.tt) { + layers[i - 1].td = layerData.tt; + } + animArray = []; + lastFrame = -1; + if (layerData.hasMask) { + var maskProps = layerData.masksProperties; + jLen = maskProps.length; + for (j = 0; j < jLen; j += 1) { + if (maskProps[j].pt.k.i) { + convertPathsToAbsoluteValues(maskProps[j].pt.k); + } else { + kLen = maskProps[j].pt.k.length; + for (k = 0; k < kLen; k += 1) { + if (maskProps[j].pt.k[k].s) { + convertPathsToAbsoluteValues(maskProps[j].pt.k[k].s[0]); + } + if (maskProps[j].pt.k[k].e) { + convertPathsToAbsoluteValues(maskProps[j].pt.k[k].e[0]); + } + } + } + } + } + if (layerData.ty === 0) { + layerData.layers = findCompLayers(layerData.refId, comps); + completeLayers(layerData.layers, comps, fontManager); + } else if (layerData.ty === 4) { + completeShapes(layerData.shapes); + } else if (layerData.ty == 5) { + completeText(layerData, fontManager); + } + } + } + + function findCompLayers(id, comps) { + var i = 0, len = comps.length; + while (i < len) { + if (comps[i].id === id) { + if (!comps[i].layers.__used) { + comps[i].layers.__used = true; + return comps[i].layers; + } + return JSON.parse(JSON.stringify(comps[i].layers)); + } + i += 1; + } + } + + function completeShapes(arr) { + var i, len = arr.length; + var j, jLen; + var hasPaths = false; + for (i = len - 1; i >= 0; i -= 1) { + if (arr[i].ty == 'sh') { + if (arr[i].ks.k.i) { + convertPathsToAbsoluteValues(arr[i].ks.k); + } else { + jLen = arr[i].ks.k.length; + for (j = 0; j < jLen; j += 1) { + if (arr[i].ks.k[j].s) { + convertPathsToAbsoluteValues(arr[i].ks.k[j].s[0]); + } + if (arr[i].ks.k[j].e) { + convertPathsToAbsoluteValues(arr[i].ks.k[j].e[0]); + } + } + } + hasPaths = true; + } else if (arr[i].ty == 'gr') { + completeShapes(arr[i].it); + } + } + /*if(hasPaths){ + //mx: distance + //ss: sensitivity + //dc: decay + arr.splice(arr.length-1,0,{ + "ty": "ms", + "mx":20, + "ss":10, + "dc":0.001, + "maxDist":200 + }); + }*/ + } + + function convertPathsToAbsoluteValues(path) { + var i, len = path.i.length; + for (i = 0; i < len; i += 1) { + path.i[i][0] += path.v[i][0]; + path.i[i][1] += path.v[i][1]; + path.o[i][0] += path.v[i][0]; + path.o[i][1] += path.v[i][1]; + } + } + + function checkVersion(minimum, animVersionString) { + var animVersion = animVersionString ? animVersionString.split('.') : [100, 100, 100]; + if (minimum[0] > animVersion[0]) { + return true; + } else if (animVersion[0] > minimum[0]) { + return false; + } + if (minimum[1] > animVersion[1]) { + return true; + } else if (animVersion[1] > minimum[1]) { + return false; + } + if (minimum[2] > animVersion[2]) { + return true; + } else if (animVersion[2] > minimum[2]) { + return false; + } + } + + var checkText = (function () { + var minimumVersion = [4, 4, 14]; + + function updateTextLayer(textLayer) { + var documentData = textLayer.t.d; + textLayer.t.d = { + k: [ + { + s: documentData, + t: 0 + } + ] + }; + } + + function iterateLayers(layers) { + var i, len = layers.length; + for (i = 0; i < len; i += 1) { + if (layers[i].ty === 5) { + updateTextLayer(layers[i]); + } + } + } + + return function (animationData) { + if (checkVersion(minimumVersion, animationData.v)) { + iterateLayers(animationData.layers); + if (animationData.assets) { + var i, len = animationData.assets.length; + for (i = 0; i < len; i += 1) { + if (animationData.assets[i].layers) { + iterateLayers(animationData.assets[i].layers); + + } + } + } + } + }; + }()); + + var checkChars = (function () { + var minimumVersion = [4, 7, 99]; + return function (animationData) { + if (animationData.chars && !checkVersion(minimumVersion, animationData.v)) { + var i, len = animationData.chars.length, j, jLen, k, kLen; + var pathData, paths; + for (i = 0; i < len; i += 1) { + if (animationData.chars[i].data && animationData.chars[i].data.shapes) { + paths = animationData.chars[i].data.shapes[0].it; + jLen = paths.length; + + for (j = 0; j < jLen; j += 1) { + pathData = paths[j].ks.k; + if (!pathData.__converted) { + convertPathsToAbsoluteValues(paths[j].ks.k); + pathData.__converted = true; + } + } + } + } + } + }; + }()); + + var checkColors = (function () { + var minimumVersion = [4, 1, 9]; + + function iterateShapes(shapes) { + var i, len = shapes.length; + var j, jLen; + for (i = 0; i < len; i += 1) { + if (shapes[i].ty === 'gr') { + iterateShapes(shapes[i].it); + } else if (shapes[i].ty === 'fl' || shapes[i].ty === 'st') { + if (shapes[i].c.k && shapes[i].c.k[0].i) { + jLen = shapes[i].c.k.length; + for (j = 0; j < jLen; j += 1) { + if (shapes[i].c.k[j].s) { + shapes[i].c.k[j].s[0] /= 255; + shapes[i].c.k[j].s[1] /= 255; + shapes[i].c.k[j].s[2] /= 255; + shapes[i].c.k[j].s[3] /= 255; + } + if (shapes[i].c.k[j].e) { + shapes[i].c.k[j].e[0] /= 255; + shapes[i].c.k[j].e[1] /= 255; + shapes[i].c.k[j].e[2] /= 255; + shapes[i].c.k[j].e[3] /= 255; + } + } + } else { + shapes[i].c.k[0] /= 255; + shapes[i].c.k[1] /= 255; + shapes[i].c.k[2] /= 255; + shapes[i].c.k[3] /= 255; + } + } + } + } + + function iterateLayers(layers) { + var i, len = layers.length; + for (i = 0; i < len; i += 1) { + if (layers[i].ty === 4) { + iterateShapes(layers[i].shapes); + } + } + } + + return function (animationData) { + if (checkVersion(minimumVersion, animationData.v)) { + iterateLayers(animationData.layers); + if (animationData.assets) { + var i, len = animationData.assets.length; + for (i = 0; i < len; i += 1) { + if (animationData.assets[i].layers) { + iterateLayers(animationData.assets[i].layers); + + } + } + } + } + }; + }()); + + var checkShapes = (function () { + var minimumVersion = [4, 4, 18]; + + + + function completeShapes(arr) { + var i, len = arr.length; + var j, jLen; + var hasPaths = false; + for (i = len - 1; i >= 0; i -= 1) { + if (arr[i].ty == 'sh') { + if (arr[i].ks.k.i) { + arr[i].ks.k.c = arr[i].closed; + } else { + jLen = arr[i].ks.k.length; + for (j = 0; j < jLen; j += 1) { + if (arr[i].ks.k[j].s) { + arr[i].ks.k[j].s[0].c = arr[i].closed; + } + if (arr[i].ks.k[j].e) { + arr[i].ks.k[j].e[0].c = arr[i].closed; + } + } + } + hasPaths = true; + } else if (arr[i].ty == 'gr') { + completeShapes(arr[i].it); + } + } + } + + function iterateLayers(layers) { + var layerData; + var i, len = layers.length; + var j, jLen, k, kLen; + for (i = 0; i < len; i += 1) { + layerData = layers[i]; + if (layerData.hasMask) { + var maskProps = layerData.masksProperties; + jLen = maskProps.length; + for (j = 0; j < jLen; j += 1) { + if (maskProps[j].pt.k.i) { + maskProps[j].pt.k.c = maskProps[j].cl; + } else { + kLen = maskProps[j].pt.k.length; + for (k = 0; k < kLen; k += 1) { + if (maskProps[j].pt.k[k].s) { + maskProps[j].pt.k[k].s[0].c = maskProps[j].cl; + } + if (maskProps[j].pt.k[k].e) { + maskProps[j].pt.k[k].e[0].c = maskProps[j].cl; + } + } + } + } + } + if (layerData.ty === 4) { + completeShapes(layerData.shapes); + } + } + } + + return function (animationData) { + if (checkVersion(minimumVersion, animationData.v)) { + iterateLayers(animationData.layers); + if (animationData.assets) { + var i, len = animationData.assets.length; + for (i = 0; i < len; i += 1) { + if (animationData.assets[i].layers) { + iterateLayers(animationData.assets[i].layers); + + } + } + } + } + }; + }()); + + function completeData(animationData, fontManager) { + if (animationData.__complete) { + return; + } + checkColors(animationData); + checkText(animationData); + checkChars(animationData); + checkShapes(animationData); + completeLayers(animationData.layers, animationData.assets, fontManager); + animationData.__complete = true; + //blitAnimation(animationData, animationData.assets, fontManager); + } + + function completeText(data, fontManager) { + if (data.t.a.length === 0 && !('m' in data.t.p)) { + data.singleShape = true; + } + } + + var moduleOb = {}; + moduleOb.completeData = completeData; + moduleOb.checkColors = checkColors; + moduleOb.checkChars = checkChars; + moduleOb.checkShapes = checkShapes; + moduleOb.completeLayers = completeLayers; + + return moduleOb; + } + + var dataManager = dataFunctionManager(); + + var FontManager = (function () { + + var maxWaitingTime = 5000; + var emptyChar = { + w: 0, + size: 0, + shapes: [] + }; + var combinedCharacters = []; + //Hindi characters + combinedCharacters = combinedCharacters.concat([2304, 2305, 2306, 2307, 2362, 2363, 2364, 2364, 2366 + , 2367, 2368, 2369, 2370, 2371, 2372, 2373, 2374, 2375, 2376, 2377, 2378, 2379 + , 2380, 2381, 2382, 2383, 2387, 2388, 2389, 2390, 2391, 2402, 2403]); + + function setUpNode(font, family) { + var parentNode = createTag('span'); + parentNode.style.fontFamily = family; + var node = createTag('span'); + // Characters that vary significantly among different fonts + node.innerHTML = 'giItT1WQy@!-/#'; + // Visible - so we can measure it - but not on the screen + parentNode.style.position = 'absolute'; + parentNode.style.left = '-10000px'; + parentNode.style.top = '-10000px'; + // Large font size makes even subtle changes obvious + parentNode.style.fontSize = '300px'; + // Reset any font properties + parentNode.style.fontVariant = 'normal'; + parentNode.style.fontStyle = 'normal'; + parentNode.style.fontWeight = 'normal'; + parentNode.style.letterSpacing = '0'; + parentNode.appendChild(node); + document.body.appendChild(parentNode); + + // Remember width with no applied web font + var width = node.offsetWidth; + node.style.fontFamily = font + ', ' + family; + return { node: node, w: width, parent: parentNode }; + } + + function checkLoadedFonts() { + var i, len = this.fonts.length; + var node, w; + var loadedCount = len; + for (i = 0; i < len; i += 1) { + if (this.fonts[i].loaded) { + loadedCount -= 1; + continue; + } + if (this.fonts[i].fOrigin === 'n' || this.fonts[i].origin === 0) { + this.fonts[i].loaded = true; + } else { + node = this.fonts[i].monoCase.node; + w = this.fonts[i].monoCase.w; + if (node.offsetWidth !== w) { + loadedCount -= 1; + this.fonts[i].loaded = true; + } else { + node = this.fonts[i].sansCase.node; + w = this.fonts[i].sansCase.w; + if (node.offsetWidth !== w) { + loadedCount -= 1; + this.fonts[i].loaded = true; + } + } + if (this.fonts[i].loaded) { + this.fonts[i].sansCase.parent.parentNode.removeChild(this.fonts[i].sansCase.parent); + this.fonts[i].monoCase.parent.parentNode.removeChild(this.fonts[i].monoCase.parent); + } + } + } + + if (loadedCount !== 0 && Date.now() - this.initTime < maxWaitingTime) { + setTimeout(this.checkLoadedFonts.bind(this), 20); + } else { + setTimeout(function () { this.isLoaded = true; }.bind(this), 0); + + } + } + + function createHelper(def, fontData) { + var tHelper = createNS('text'); + tHelper.style.fontSize = '100px'; + //tHelper.style.fontFamily = fontData.fFamily; + tHelper.setAttribute('font-family', fontData.fFamily); + tHelper.setAttribute('font-style', fontData.fStyle); + tHelper.setAttribute('font-weight', fontData.fWeight); + tHelper.textContent = '1'; + if (fontData.fClass) { + tHelper.style.fontFamily = 'inherit'; + tHelper.setAttribute('class', fontData.fClass); + } else { + tHelper.style.fontFamily = fontData.fFamily; + } + def.appendChild(tHelper); + var tCanvasHelper = createTag('canvas').getContext('2d'); + tCanvasHelper.font = fontData.fWeight + ' ' + fontData.fStyle + ' 100px ' + fontData.fFamily; + //tCanvasHelper.font = ' 100px '+ fontData.fFamily; + return tHelper; + } + + function addFonts(fontData, defs) { + if (!fontData) { + this.isLoaded = true; + return; + } + if (this.chars) { + this.isLoaded = true; + this.fonts = fontData.list; + return; + } + + + var fontArr = fontData.list; + var i, len = fontArr.length; + var _pendingFonts = len; + for (i = 0; i < len; i += 1) { + var shouldLoadFont = true; + var loadedSelector; + var j; + fontArr[i].loaded = false; + fontArr[i].monoCase = setUpNode(fontArr[i].fFamily, 'monospace'); + fontArr[i].sansCase = setUpNode(fontArr[i].fFamily, 'sans-serif'); + if (!fontArr[i].fPath) { + fontArr[i].loaded = true; + _pendingFonts -= 1; + } else if (fontArr[i].fOrigin === 'p' || fontArr[i].origin === 3) { + loadedSelector = document.querySelectorAll('style[f-forigin="p"][f-family="' + fontArr[i].fFamily + '"], style[f-origin="3"][f-family="' + fontArr[i].fFamily + '"]'); + + if (loadedSelector.length > 0) { + shouldLoadFont = false; + } + + if (shouldLoadFont) { + var s = createTag('style'); + s.setAttribute('f-forigin', fontArr[i].fOrigin); + s.setAttribute('f-origin', fontArr[i].origin); + s.setAttribute('f-family', fontArr[i].fFamily); + s.type = "text/css"; + s.innerHTML = "@font-face {" + "font-family: " + fontArr[i].fFamily + "; font-style: normal; src: url('" + fontArr[i].fPath + "');}"; + defs.appendChild(s); + } + } else if (fontArr[i].fOrigin === 'g' || fontArr[i].origin === 1) { + loadedSelector = document.querySelectorAll('link[f-forigin="g"], link[f-origin="1"]'); + + for (j = 0; j < loadedSelector.length; j++) { + if (loadedSelector[j].href.indexOf(fontArr[i].fPath) !== -1) { + // Font is already loaded + shouldLoadFont = false; + } + } + + if (shouldLoadFont) { + var l = createTag('link'); + l.setAttribute('f-forigin', fontArr[i].fOrigin); + l.setAttribute('f-origin', fontArr[i].origin); + l.type = "text/css"; + l.rel = "stylesheet"; + l.href = fontArr[i].fPath; + document.body.appendChild(l); + } + } else if (fontArr[i].fOrigin === 't' || fontArr[i].origin === 2) { + loadedSelector = document.querySelectorAll('script[f-forigin="t"], script[f-origin="2"]'); + + for (j = 0; j < loadedSelector.length; j++) { + if (fontArr[i].fPath === loadedSelector[j].src) { + // Font is already loaded + shouldLoadFont = false; + } + } + + if (shouldLoadFont) { + var sc = createTag('link'); + sc.setAttribute('f-forigin', fontArr[i].fOrigin); + sc.setAttribute('f-origin', fontArr[i].origin); + sc.setAttribute('rel', 'stylesheet'); + sc.setAttribute('href', fontArr[i].fPath); + defs.appendChild(sc); + } + } + fontArr[i].helper = createHelper(defs, fontArr[i]); + fontArr[i].cache = {}; + this.fonts.push(fontArr[i]); + } + if (_pendingFonts === 0) { + this.isLoaded = true; + } else { + //On some cases even if the font is loaded, it won't load correctly when measuring text on canvas. + //Adding this timeout seems to fix it + setTimeout(this.checkLoadedFonts.bind(this), 100); + } + } + + function addChars(chars) { + if (!chars) { + return; + } + if (!this.chars) { + this.chars = []; + } + var i, len = chars.length; + var j, jLen = this.chars.length, found; + for (i = 0; i < len; i += 1) { + j = 0; + found = false; + while (j < jLen) { + if (this.chars[j].style === chars[i].style && this.chars[j].fFamily === chars[i].fFamily && this.chars[j].ch === chars[i].ch) { + found = true; + } + j += 1; + } + if (!found) { + this.chars.push(chars[i]); + jLen += 1; + } + } + } + + function getCharData(char, style, font) { + var i = 0, len = this.chars.length; + while (i < len) { + if (this.chars[i].ch === char && this.chars[i].style === style && this.chars[i].fFamily === font) { + + return this.chars[i]; + } + i += 1; + } + if ((typeof char === 'string' && char.charCodeAt(0) !== 13 || !char) && console && console.warn) { + console.warn('Missing character from exported characters list: ', char, style, font); + } + return emptyChar; + } + + function measureText(char, fontName, size) { + var fontData = this.getFontByName(fontName); + var index = char.charCodeAt(0); + if (!fontData.cache[index + 1]) { + var tHelper = fontData.helper; + //Canvas version + //fontData.cache[index] = tHelper.measureText(char).width / 100; + //SVG version + //console.log(tHelper.getBBox().width) + if (char === ' ') { + tHelper.textContent = '|' + char + '|'; + var doubleSize = tHelper.getComputedTextLength(); + tHelper.textContent = '||'; + var singleSize = tHelper.getComputedTextLength(); + fontData.cache[index + 1] = (doubleSize - singleSize) / 100; + } else { + tHelper.textContent = char; + fontData.cache[index + 1] = (tHelper.getComputedTextLength()) / 100; + } + } + return fontData.cache[index + 1] * size; + } + + function getFontByName(name) { + var i = 0, len = this.fonts.length; + while (i < len) { + if (this.fonts[i].fName === name) { + return this.fonts[i]; + } + i += 1; + } + return this.fonts[0]; + } + + function getCombinedCharacterCodes() { + return combinedCharacters; + } + + function loaded() { + return this.isLoaded; + } + + var Font = function () { + this.fonts = []; + this.chars = null; + this.typekitLoaded = 0; + this.isLoaded = false; + this.initTime = Date.now(); + }; + //TODO: for now I'm adding these methods to the Class and not the prototype. Think of a better way to implement it. + Font.getCombinedCharacterCodes = getCombinedCharacterCodes; + + Font.prototype.addChars = addChars; + Font.prototype.addFonts = addFonts; + Font.prototype.getCharData = getCharData; + Font.prototype.getFontByName = getFontByName; + Font.prototype.measureText = measureText; + Font.prototype.checkLoadedFonts = checkLoadedFonts; + Font.prototype.loaded = loaded; + + return Font; + + }()); + var PropertyFactory = (function () { + + var initFrame = initialDefaultFrame; + var math_abs = Math.abs; + + function interpolateValue(frameNum, caching) { + var offsetTime = this.offsetTime; + var newValue; + if (this.propType === 'multidimensional') { + newValue = createTypedArray('float32', this.pv.length); + } + var iterationIndex = caching.lastIndex; + var i = iterationIndex; + var len = this.keyframes.length - 1, flag = true; + var keyData, nextKeyData; + + while (flag) { + keyData = this.keyframes[i]; + nextKeyData = this.keyframes[i + 1]; + if (i === len - 1 && frameNum >= nextKeyData.t - offsetTime) { + if (keyData.h) { + keyData = nextKeyData; + } + iterationIndex = 0; + break; + } + if ((nextKeyData.t - offsetTime) > frameNum) { + iterationIndex = i; + break; + } + if (i < len - 1) { + i += 1; + } else { + iterationIndex = 0; + flag = false; + } + } + + var k, kLen, perc, jLen, j, fnc; + var nextKeyTime = nextKeyData.t - offsetTime; + var keyTime = keyData.t - offsetTime; + var endValue; + if (keyData.to) { + if (!keyData.bezierData) { + keyData.bezierData = bez.buildBezierData(keyData.s, nextKeyData.s || keyData.e, keyData.to, keyData.ti); + } + var bezierData = keyData.bezierData; + if (frameNum >= nextKeyTime || frameNum < keyTime) { + var ind = frameNum >= nextKeyTime ? bezierData.points.length - 1 : 0; + kLen = bezierData.points[ind].point.length; + for (k = 0; k < kLen; k += 1) { + newValue[k] = bezierData.points[ind].point[k]; + } + // caching._lastKeyframeIndex = -1; + } else { + if (keyData.__fnct) { + fnc = keyData.__fnct; + } else { + fnc = BezierFactory.getBezierEasing(keyData.o.x, keyData.o.y, keyData.i.x, keyData.i.y, keyData.n).get; + keyData.__fnct = fnc; + } + perc = fnc((frameNum - keyTime) / (nextKeyTime - keyTime)); + var distanceInLine = bezierData.segmentLength * perc; + + var segmentPerc; + var addedLength = (caching.lastFrame < frameNum && caching._lastKeyframeIndex === i) ? caching._lastAddedLength : 0; + j = (caching.lastFrame < frameNum && caching._lastKeyframeIndex === i) ? caching._lastPoint : 0; + flag = true; + jLen = bezierData.points.length; + while (flag) { + addedLength += bezierData.points[j].partialLength; + if (distanceInLine === 0 || perc === 0 || j === bezierData.points.length - 1) { + kLen = bezierData.points[j].point.length; + for (k = 0; k < kLen; k += 1) { + newValue[k] = bezierData.points[j].point[k]; + } + break; + } else if (distanceInLine >= addedLength && distanceInLine < addedLength + bezierData.points[j + 1].partialLength) { + segmentPerc = (distanceInLine - addedLength) / bezierData.points[j + 1].partialLength; + kLen = bezierData.points[j].point.length; + for (k = 0; k < kLen; k += 1) { + newValue[k] = bezierData.points[j].point[k] + (bezierData.points[j + 1].point[k] - bezierData.points[j].point[k]) * segmentPerc; + } + break; + } + if (j < jLen - 1) { + j += 1; + } else { + flag = false; + } + } + caching._lastPoint = j; + caching._lastAddedLength = addedLength - bezierData.points[j].partialLength; + caching._lastKeyframeIndex = i; + } + } else { + var outX, outY, inX, inY, keyValue; + len = keyData.s.length; + endValue = nextKeyData.s || keyData.e; + if (this.sh && keyData.h !== 1) { + if (frameNum >= nextKeyTime) { + newValue[0] = endValue[0]; + newValue[1] = endValue[1]; + newValue[2] = endValue[2]; + } else if (frameNum <= keyTime) { + newValue[0] = keyData.s[0]; + newValue[1] = keyData.s[1]; + newValue[2] = keyData.s[2]; + } else { + var quatStart = createQuaternion(keyData.s); + var quatEnd = createQuaternion(endValue); + var time = (frameNum - keyTime) / (nextKeyTime - keyTime); + quaternionToEuler(newValue, slerp(quatStart, quatEnd, time)); + } + + } else { + for (i = 0; i < len; i += 1) { + if (keyData.h !== 1) { + if (frameNum >= nextKeyTime) { + perc = 1; + } else if (frameNum < keyTime) { + perc = 0; + } else { + if (keyData.o.x.constructor === Array) { + if (!keyData.__fnct) { + keyData.__fnct = []; + } + if (!keyData.__fnct[i]) { + outX = (typeof keyData.o.x[i] === 'undefined') ? keyData.o.x[0] : keyData.o.x[i]; + outY = (typeof keyData.o.y[i] === 'undefined') ? keyData.o.y[0] : keyData.o.y[i]; + inX = (typeof keyData.i.x[i] === 'undefined') ? keyData.i.x[0] : keyData.i.x[i]; + inY = (typeof keyData.i.y[i] === 'undefined') ? keyData.i.y[0] : keyData.i.y[i]; + fnc = BezierFactory.getBezierEasing(outX, outY, inX, inY).get; + keyData.__fnct[i] = fnc; + } else { + fnc = keyData.__fnct[i]; + } + } else { + if (!keyData.__fnct) { + outX = keyData.o.x; + outY = keyData.o.y; + inX = keyData.i.x; + inY = keyData.i.y; + fnc = BezierFactory.getBezierEasing(outX, outY, inX, inY).get; + keyData.__fnct = fnc; + } else { + fnc = keyData.__fnct; + } + } + perc = fnc((frameNum - keyTime) / (nextKeyTime - keyTime)); + } + } + + endValue = nextKeyData.s || keyData.e; + keyValue = keyData.h === 1 ? keyData.s[i] : keyData.s[i] + (endValue[i] - keyData.s[i]) * perc; + + if (this.propType === 'multidimensional') { + newValue[i] = keyValue; + } else { + newValue = keyValue; + } + } + } + } + caching.lastIndex = iterationIndex; + return newValue; + } + + //based on @Toji's https://github.com/toji/gl-matrix/ + function slerp(a, b, t) { + var out = []; + var ax = a[0], ay = a[1], az = a[2], aw = a[3], + bx = b[0], by = b[1], bz = b[2], bw = b[3] + + var omega, cosom, sinom, scale0, scale1; + + cosom = ax * bx + ay * by + az * bz + aw * bw; + if (cosom < 0.0) { + cosom = -cosom; + bx = -bx; + by = -by; + bz = -bz; + bw = -bw; + } + if ((1.0 - cosom) > 0.000001) { + omega = Math.acos(cosom); + sinom = Math.sin(omega); + scale0 = Math.sin((1.0 - t) * omega) / sinom; + scale1 = Math.sin(t * omega) / sinom; + } else { + scale0 = 1.0 - t; + scale1 = t; + } + out[0] = scale0 * ax + scale1 * bx; + out[1] = scale0 * ay + scale1 * by; + out[2] = scale0 * az + scale1 * bz; + out[3] = scale0 * aw + scale1 * bw; + + return out; + } + + function quaternionToEuler(out, quat) { + var qx = quat[0]; + var qy = quat[1]; + var qz = quat[2]; + var qw = quat[3]; + var heading = Math.atan2(2 * qy * qw - 2 * qx * qz, 1 - 2 * qy * qy - 2 * qz * qz) + var attitude = Math.asin(2 * qx * qy + 2 * qz * qw) + var bank = Math.atan2(2 * qx * qw - 2 * qy * qz, 1 - 2 * qx * qx - 2 * qz * qz); + out[0] = heading / degToRads; + out[1] = attitude / degToRads; + out[2] = bank / degToRads; + } + + function createQuaternion(values) { + var heading = values[0] * degToRads; + var attitude = values[1] * degToRads; + var bank = values[2] * degToRads; + var c1 = Math.cos(heading / 2); + var c2 = Math.cos(attitude / 2); + var c3 = Math.cos(bank / 2); + var s1 = Math.sin(heading / 2); + var s2 = Math.sin(attitude / 2); + var s3 = Math.sin(bank / 2); + var w = c1 * c2 * c3 - s1 * s2 * s3; + var x = s1 * s2 * c3 + c1 * c2 * s3; + var y = s1 * c2 * c3 + c1 * s2 * s3; + var z = c1 * s2 * c3 - s1 * c2 * s3; + + return [x, y, z, w]; + } + + function getValueAtCurrentTime() { + var frameNum = this.comp.renderedFrame - this.offsetTime; + var initTime = this.keyframes[0].t - this.offsetTime; + var endTime = this.keyframes[this.keyframes.length - 1].t - this.offsetTime; + if (!(frameNum === this._caching.lastFrame || (this._caching.lastFrame !== initFrame && ((this._caching.lastFrame >= endTime && frameNum >= endTime) || (this._caching.lastFrame < initTime && frameNum < initTime))))) { + if (this._caching.lastFrame >= frameNum) { + this._caching._lastKeyframeIndex = -1; + this._caching.lastIndex = 0; + } + + var renderResult = this.interpolateValue(frameNum, this._caching); + this.pv = renderResult; + } + this._caching.lastFrame = frameNum; + return this.pv; + } + + function setVValue(val) { + var multipliedValue; + if (this.propType === 'unidimensional') { + multipliedValue = val * this.mult; + if (math_abs(this.v - multipliedValue) > 0.00001) { + this.v = multipliedValue; + this._mdf = true; + } + } else { + var i = 0, len = this.v.length; + while (i < len) { + multipliedValue = val[i] * this.mult; + if (math_abs(this.v[i] - multipliedValue) > 0.00001) { + this.v[i] = multipliedValue; + this._mdf = true; + } + i += 1; + } + } + } + + function processEffectsSequence() { + if (this.elem.globalData.frameId === this.frameId || !this.effectsSequence.length) { + return; + } + if (this.lock) { + this.setVValue(this.pv); + return; + } + this.lock = true; + this._mdf = this._isFirstFrame; + var multipliedValue; + var i, len = this.effectsSequence.length; + var finalValue = this.kf ? this.pv : this.data.k; + for (i = 0; i < len; i += 1) { + finalValue = this.effectsSequence[i](finalValue); + } + this.setVValue(finalValue); + this._isFirstFrame = false; + this.lock = false; + this.frameId = this.elem.globalData.frameId; + } + + function addEffect(effectFunction) { + this.effectsSequence.push(effectFunction); + this.container.addDynamicProperty(this); + } + + function ValueProperty(elem, data, mult, container) { + this.propType = 'unidimensional'; + this.mult = mult || 1; + this.data = data; + this.v = mult ? data.k * mult : data.k; + this.pv = data.k; + this._mdf = false; + this.elem = elem; + this.container = container; + this.comp = elem.comp; + this.k = false; + this.kf = false; + this.vel = 0; + this.effectsSequence = []; + this._isFirstFrame = true; + this.getValue = processEffectsSequence; + this.setVValue = setVValue; + this.addEffect = addEffect; + } + + function MultiDimensionalProperty(elem, data, mult, container) { + this.propType = 'multidimensional'; + this.mult = mult || 1; + this.data = data; + this._mdf = false; + this.elem = elem; + this.container = container; + this.comp = elem.comp; + this.k = false; + this.kf = false; + this.frameId = -1; + var i, len = data.k.length; + this.v = createTypedArray('float32', len); + this.pv = createTypedArray('float32', len); + var arr = createTypedArray('float32', len); + this.vel = createTypedArray('float32', len); + for (i = 0; i < len; i += 1) { + this.v[i] = data.k[i] * this.mult; + this.pv[i] = data.k[i]; + } + this._isFirstFrame = true; + this.effectsSequence = []; + this.getValue = processEffectsSequence; + this.setVValue = setVValue; + this.addEffect = addEffect; + } + + function KeyframedValueProperty(elem, data, mult, container) { + this.propType = 'unidimensional'; + this.keyframes = data.k; + this.offsetTime = elem.data.st; + this.frameId = -1; + this._caching = { lastFrame: initFrame, lastIndex: 0, value: 0, _lastKeyframeIndex: -1 }; + this.k = true; + this.kf = true; + this.data = data; + this.mult = mult || 1; + this.elem = elem; + this.container = container; + this.comp = elem.comp; + this.v = initFrame; + this.pv = initFrame; + this._isFirstFrame = true; + this.getValue = processEffectsSequence; + this.setVValue = setVValue; + this.interpolateValue = interpolateValue; + this.effectsSequence = [getValueAtCurrentTime.bind(this)]; + this.addEffect = addEffect; + } + + function KeyframedMultidimensionalProperty(elem, data, mult, container) { + this.propType = 'multidimensional'; + var i, len = data.k.length; + var s, e, to, ti; + for (i = 0; i < len - 1; i += 1) { + if (data.k[i].to && data.k[i].s && data.k[i + 1] && data.k[i + 1].s) { + s = data.k[i].s; + e = data.k[i + 1].s; + to = data.k[i].to; + ti = data.k[i].ti; + if ((s.length === 2 && !(s[0] === e[0] && s[1] === e[1]) && bez.pointOnLine2D(s[0], s[1], e[0], e[1], s[0] + to[0], s[1] + to[1]) && bez.pointOnLine2D(s[0], s[1], e[0], e[1], e[0] + ti[0], e[1] + ti[1])) || (s.length === 3 && !(s[0] === e[0] && s[1] === e[1] && s[2] === e[2]) && bez.pointOnLine3D(s[0], s[1], s[2], e[0], e[1], e[2], s[0] + to[0], s[1] + to[1], s[2] + to[2]) && bez.pointOnLine3D(s[0], s[1], s[2], e[0], e[1], e[2], e[0] + ti[0], e[1] + ti[1], e[2] + ti[2]))) { + data.k[i].to = null; + data.k[i].ti = null; + } + if (s[0] === e[0] && s[1] === e[1] && to[0] === 0 && to[1] === 0 && ti[0] === 0 && ti[1] === 0) { + if (s.length === 2 || (s[2] === e[2] && to[2] === 0 && ti[2] === 0)) { + data.k[i].to = null; + data.k[i].ti = null; + } + } + } + } + this.effectsSequence = [getValueAtCurrentTime.bind(this)]; + this.keyframes = data.k; + this.offsetTime = elem.data.st; + this.k = true; + this.kf = true; + this._isFirstFrame = true; + this.mult = mult || 1; + this.elem = elem; + this.container = container; + this.comp = elem.comp; + this.getValue = processEffectsSequence; + this.setVValue = setVValue; + this.interpolateValue = interpolateValue; + this.frameId = -1; + var arrLen = data.k[0].s.length; + this.v = createTypedArray('float32', arrLen); + this.pv = createTypedArray('float32', arrLen); + for (i = 0; i < arrLen; i += 1) { + this.v[i] = initFrame; + this.pv[i] = initFrame; + } + this._caching = { lastFrame: initFrame, lastIndex: 0, value: createTypedArray('float32', arrLen) }; + this.addEffect = addEffect; + } + + function getProp(elem, data, type, mult, container) { + var p; + if (!data.k.length) { + p = new ValueProperty(elem, data, mult, container); + } else if (typeof (data.k[0]) === 'number') { + p = new MultiDimensionalProperty(elem, data, mult, container); + } else { + switch (type) { + case 0: + p = new KeyframedValueProperty(elem, data, mult, container); + break; + case 1: + p = new KeyframedMultidimensionalProperty(elem, data, mult, container); + break; + } + } + if (p.effectsSequence.length) { + container.addDynamicProperty(p); + } + return p; + } + + var ob = { + getProp: getProp + }; + return ob; + }()); + var TransformPropertyFactory = (function () { + + var defaultVector = [0, 0] + + function applyToMatrix(mat) { + var _mdf = this._mdf; + this.iterateDynamicProperties(); + this._mdf = this._mdf || _mdf; + if (this.a) { + mat.translate(-this.a.v[0], -this.a.v[1], this.a.v[2]); + } + if (this.s) { + mat.scale(this.s.v[0], this.s.v[1], this.s.v[2]); + } + if (this.sk) { + mat.skewFromAxis(-this.sk.v, this.sa.v); + } + if (this.r) { + mat.rotate(-this.r.v); + } else { + mat.rotateZ(-this.rz.v).rotateY(this.ry.v).rotateX(this.rx.v).rotateZ(-this.or.v[2]).rotateY(this.or.v[1]).rotateX(this.or.v[0]); + } + if (this.data.p.s) { + if (this.data.p.z) { + mat.translate(this.px.v, this.py.v, -this.pz.v); + } else { + mat.translate(this.px.v, this.py.v, 0); + } + } else { + mat.translate(this.p.v[0], this.p.v[1], -this.p.v[2]); + } + } + function processKeys(forceRender) { + if (this.elem.globalData.frameId === this.frameId) { + return; + } + if (this._isDirty) { + this.precalculateMatrix(); + this._isDirty = false; + } + + this.iterateDynamicProperties(); + + if (this._mdf || forceRender) { + this.v.cloneFromProps(this.pre.props); + if (this.appliedTransformations < 1) { + this.v.translate(-this.a.v[0], -this.a.v[1], this.a.v[2]); + } + if (this.appliedTransformations < 2) { + this.v.scale(this.s.v[0], this.s.v[1], this.s.v[2]); + } + if (this.sk && this.appliedTransformations < 3) { + this.v.skewFromAxis(-this.sk.v, this.sa.v); + } + if (this.r && this.appliedTransformations < 4) { + this.v.rotate(-this.r.v); + } else if (!this.r && this.appliedTransformations < 4) { + this.v.rotateZ(-this.rz.v).rotateY(this.ry.v).rotateX(this.rx.v).rotateZ(-this.or.v[2]).rotateY(this.or.v[1]).rotateX(this.or.v[0]); + } + if (this.autoOriented) { + var v1, v2, frameRate = this.elem.globalData.frameRate; + if (this.p && this.p.keyframes && this.p.getValueAtTime) { + if (this.p._caching.lastFrame + this.p.offsetTime <= this.p.keyframes[0].t) { + v1 = this.p.getValueAtTime((this.p.keyframes[0].t + 0.01) / frameRate, 0); + v2 = this.p.getValueAtTime(this.p.keyframes[0].t / frameRate, 0); + } else if (this.p._caching.lastFrame + this.p.offsetTime >= this.p.keyframes[this.p.keyframes.length - 1].t) { + v1 = this.p.getValueAtTime((this.p.keyframes[this.p.keyframes.length - 1].t / frameRate), 0); + v2 = this.p.getValueAtTime((this.p.keyframes[this.p.keyframes.length - 1].t - 0.05) / frameRate, 0); + } else { + v1 = this.p.pv; + v2 = this.p.getValueAtTime((this.p._caching.lastFrame + this.p.offsetTime - 0.01) / frameRate, this.p.offsetTime); + } + } else if (this.px && this.px.keyframes && this.py.keyframes && this.px.getValueAtTime && this.py.getValueAtTime) { + v1 = []; + v2 = []; + var px = this.px, py = this.py, frameRate; + if (px._caching.lastFrame + px.offsetTime <= px.keyframes[0].t) { + v1[0] = px.getValueAtTime((px.keyframes[0].t + 0.01) / frameRate, 0); + v1[1] = py.getValueAtTime((py.keyframes[0].t + 0.01) / frameRate, 0); + v2[0] = px.getValueAtTime((px.keyframes[0].t) / frameRate, 0); + v2[1] = py.getValueAtTime((py.keyframes[0].t) / frameRate, 0); + } else if (px._caching.lastFrame + px.offsetTime >= px.keyframes[px.keyframes.length - 1].t) { + v1[0] = px.getValueAtTime((px.keyframes[px.keyframes.length - 1].t / frameRate), 0); + v1[1] = py.getValueAtTime((py.keyframes[py.keyframes.length - 1].t / frameRate), 0); + v2[0] = px.getValueAtTime((px.keyframes[px.keyframes.length - 1].t - 0.01) / frameRate, 0); + v2[1] = py.getValueAtTime((py.keyframes[py.keyframes.length - 1].t - 0.01) / frameRate, 0); + } else { + v1 = [px.pv, py.pv]; + v2[0] = px.getValueAtTime((px._caching.lastFrame + px.offsetTime - 0.01) / frameRate, px.offsetTime); + v2[1] = py.getValueAtTime((py._caching.lastFrame + py.offsetTime - 0.01) / frameRate, py.offsetTime); + } + } else { + v1 = v2 = defaultVector + } + this.v.rotate(-Math.atan2(v1[1] - v2[1], v1[0] - v2[0])); + } + if (this.data.p && this.data.p.s) { + if (this.data.p.z) { + this.v.translate(this.px.v, this.py.v, -this.pz.v); + } else { + this.v.translate(this.px.v, this.py.v, 0); + } + } else { + this.v.translate(this.p.v[0], this.p.v[1], -this.p.v[2]); + } + } + this.frameId = this.elem.globalData.frameId; + } + + function precalculateMatrix() { + if (!this.a.k) { + this.pre.translate(-this.a.v[0], -this.a.v[1], this.a.v[2]); + this.appliedTransformations = 1; + } else { + return; + } + if (!this.s.effectsSequence.length) { + this.pre.scale(this.s.v[0], this.s.v[1], this.s.v[2]); + this.appliedTransformations = 2; + } else { + return; + } + if (this.sk) { + if (!this.sk.effectsSequence.length && !this.sa.effectsSequence.length) { + this.pre.skewFromAxis(-this.sk.v, this.sa.v); + this.appliedTransformations = 3; + } else { + return; + } + } + if (this.r) { + if (!this.r.effectsSequence.length) { + this.pre.rotate(-this.r.v); + this.appliedTransformations = 4; + } else { + return; + } + } else if (!this.rz.effectsSequence.length && !this.ry.effectsSequence.length && !this.rx.effectsSequence.length && !this.or.effectsSequence.length) { + this.pre.rotateZ(-this.rz.v).rotateY(this.ry.v).rotateX(this.rx.v).rotateZ(-this.or.v[2]).rotateY(this.or.v[1]).rotateX(this.or.v[0]); + this.appliedTransformations = 4; + } + } + + function autoOrient() { + // + //var prevP = this.getValueAtTime(); + } + + function addDynamicProperty(prop) { + this._addDynamicProperty(prop); + this.elem.addDynamicProperty(prop); + this._isDirty = true; + } + + function TransformProperty(elem, data, container) { + this.elem = elem; + this.frameId = -1; + this.propType = 'transform'; + this.data = data; + this.v = new Matrix(); + //Precalculated matrix with non animated properties + this.pre = new Matrix(); + this.appliedTransformations = 0; + this.initDynamicPropertyContainer(container || elem); + if (data.p && data.p.s) { + this.px = PropertyFactory.getProp(elem, data.p.x, 0, 0, this); + this.py = PropertyFactory.getProp(elem, data.p.y, 0, 0, this); + if (data.p.z) { + this.pz = PropertyFactory.getProp(elem, data.p.z, 0, 0, this); + } + } else { + this.p = PropertyFactory.getProp(elem, data.p || { k: [0, 0, 0] }, 1, 0, this); + } + if (data.rx) { + this.rx = PropertyFactory.getProp(elem, data.rx, 0, degToRads, this); + this.ry = PropertyFactory.getProp(elem, data.ry, 0, degToRads, this); + this.rz = PropertyFactory.getProp(elem, data.rz, 0, degToRads, this); + if (data.or.k[0].ti) { + var i, len = data.or.k.length; + for (i = 0; i < len; i += 1) { + data.or.k[i].to = data.or.k[i].ti = null; + } + } + this.or = PropertyFactory.getProp(elem, data.or, 1, degToRads, this); + //sh Indicates it needs to be capped between -180 and 180 + this.or.sh = true; + } else { + this.r = PropertyFactory.getProp(elem, data.r || { k: 0 }, 0, degToRads, this); + } + if (data.sk) { + this.sk = PropertyFactory.getProp(elem, data.sk, 0, degToRads, this); + this.sa = PropertyFactory.getProp(elem, data.sa, 0, degToRads, this); + } + this.a = PropertyFactory.getProp(elem, data.a || { k: [0, 0, 0] }, 1, 0, this); + this.s = PropertyFactory.getProp(elem, data.s || { k: [100, 100, 100] }, 1, 0.01, this); + // Opacity is not part of the transform properties, that's why it won't use this.dynamicProperties. That way transforms won't get updated if opacity changes. + if (data.o) { + this.o = PropertyFactory.getProp(elem, data.o, 0, 0.01, elem); + } else { + this.o = { _mdf: false, v: 1 }; + } + this._isDirty = true; + if (!this.dynamicProperties.length) { + this.getValue(true); + } + } + + TransformProperty.prototype = { + applyToMatrix: applyToMatrix, + getValue: processKeys, + precalculateMatrix: precalculateMatrix, + autoOrient: autoOrient + } + + extendPrototype([DynamicPropertyContainer], TransformProperty); + TransformProperty.prototype.addDynamicProperty = addDynamicProperty; + TransformProperty.prototype._addDynamicProperty = DynamicPropertyContainer.prototype.addDynamicProperty; + + function getTransformProperty(elem, data, container) { + return new TransformProperty(elem, data, container); + } + + return { + getTransformProperty: getTransformProperty + }; + + }()); + function ShapePath() { + this.c = false; + this._length = 0; + this._maxLength = 8; + this.v = createSizedArray(this._maxLength); + this.o = createSizedArray(this._maxLength); + this.i = createSizedArray(this._maxLength); + } + + ShapePath.prototype.setPathData = function (closed, len) { + this.c = closed; + this.setLength(len); + var i = 0; + while (i < len) { + this.v[i] = point_pool.newElement(); + this.o[i] = point_pool.newElement(); + this.i[i] = point_pool.newElement(); + i += 1; + } + }; + + ShapePath.prototype.setLength = function (len) { + while (this._maxLength < len) { + this.doubleArrayLength(); + } + this._length = len; + }; + + ShapePath.prototype.doubleArrayLength = function () { + this.v = this.v.concat(createSizedArray(this._maxLength)); + this.i = this.i.concat(createSizedArray(this._maxLength)); + this.o = this.o.concat(createSizedArray(this._maxLength)); + this._maxLength *= 2; + }; + + ShapePath.prototype.setXYAt = function (x, y, type, pos, replace) { + var arr; + this._length = Math.max(this._length, pos + 1); + if (this._length >= this._maxLength) { + this.doubleArrayLength(); + } + switch (type) { + case 'v': + arr = this.v; + break; + case 'i': + arr = this.i; + break; + case 'o': + arr = this.o; + break; + } + if (!arr[pos] || (arr[pos] && !replace)) { + arr[pos] = point_pool.newElement(); + } + arr[pos][0] = x; + arr[pos][1] = y; + }; + + ShapePath.prototype.setTripleAt = function (vX, vY, oX, oY, iX, iY, pos, replace) { + this.setXYAt(vX, vY, 'v', pos, replace); + this.setXYAt(oX, oY, 'o', pos, replace); + this.setXYAt(iX, iY, 'i', pos, replace); + }; + + ShapePath.prototype.reverse = function () { + var newPath = new ShapePath(); + newPath.setPathData(this.c, this._length); + var vertices = this.v, outPoints = this.o, inPoints = this.i; + var init = 0; + if (this.c) { + newPath.setTripleAt(vertices[0][0], vertices[0][1], inPoints[0][0], inPoints[0][1], outPoints[0][0], outPoints[0][1], 0, false); + init = 1; + } + var cnt = this._length - 1; + var len = this._length; + + var i; + for (i = init; i < len; i += 1) { + newPath.setTripleAt(vertices[cnt][0], vertices[cnt][1], inPoints[cnt][0], inPoints[cnt][1], outPoints[cnt][0], outPoints[cnt][1], i, false); + cnt -= 1; + } + return newPath; + }; + var ShapePropertyFactory = (function () { + + var initFrame = -999999; + + function interpolateShape(frameNum, previousValue, caching) { + var iterationIndex = caching.lastIndex; + var keyPropS, keyPropE, isHold, j, k, jLen, kLen, perc, vertexValue; + var kf = this.keyframes; + if (frameNum < kf[0].t - this.offsetTime) { + keyPropS = kf[0].s[0]; + isHold = true; + iterationIndex = 0; + } else if (frameNum >= kf[kf.length - 1].t - this.offsetTime) { + keyPropS = kf[kf.length - 1].s ? kf[kf.length - 1].s[0] : kf[kf.length - 2].e[0]; + /*if(kf[kf.length - 1].s){ + keyPropS = kf[kf.length - 1].s[0]; + }else{ + keyPropS = kf[kf.length - 2].e[0]; + }*/ + isHold = true; + } else { + var i = iterationIndex; + var len = kf.length - 1, flag = true, keyData, nextKeyData; + while (flag) { + keyData = kf[i]; + nextKeyData = kf[i + 1]; + if ((nextKeyData.t - this.offsetTime) > frameNum) { + break; + } + if (i < len - 1) { + i += 1; + } else { + flag = false; + } + } + isHold = keyData.h === 1; + iterationIndex = i; + if (!isHold) { + if (frameNum >= nextKeyData.t - this.offsetTime) { + perc = 1; + } else if (frameNum < keyData.t - this.offsetTime) { + perc = 0; + } else { + var fnc; + if (keyData.__fnct) { + fnc = keyData.__fnct; + } else { + fnc = BezierFactory.getBezierEasing(keyData.o.x, keyData.o.y, keyData.i.x, keyData.i.y).get; + keyData.__fnct = fnc; + } + perc = fnc((frameNum - (keyData.t - this.offsetTime)) / ((nextKeyData.t - this.offsetTime) - (keyData.t - this.offsetTime))); + } + keyPropE = nextKeyData.s ? nextKeyData.s[0] : keyData.e[0]; + } + keyPropS = keyData.s[0]; + } + jLen = previousValue._length; + kLen = keyPropS.i[0].length; + caching.lastIndex = iterationIndex; + + for (j = 0; j < jLen; j += 1) { + for (k = 0; k < kLen; k += 1) { + vertexValue = isHold ? keyPropS.i[j][k] : keyPropS.i[j][k] + (keyPropE.i[j][k] - keyPropS.i[j][k]) * perc; + previousValue.i[j][k] = vertexValue; + vertexValue = isHold ? keyPropS.o[j][k] : keyPropS.o[j][k] + (keyPropE.o[j][k] - keyPropS.o[j][k]) * perc; + previousValue.o[j][k] = vertexValue; + vertexValue = isHold ? keyPropS.v[j][k] : keyPropS.v[j][k] + (keyPropE.v[j][k] - keyPropS.v[j][k]) * perc; + previousValue.v[j][k] = vertexValue; + } + } + } + + function interpolateShapeCurrentTime() { + var frameNum = this.comp.renderedFrame - this.offsetTime; + var initTime = this.keyframes[0].t - this.offsetTime; + var endTime = this.keyframes[this.keyframes.length - 1].t - this.offsetTime; + var lastFrame = this._caching.lastFrame; + if (!(lastFrame !== initFrame && ((lastFrame < initTime && frameNum < initTime) || (lastFrame > endTime && frameNum > endTime)))) { + //// + this._caching.lastIndex = lastFrame < frameNum ? this._caching.lastIndex : 0; + this.interpolateShape(frameNum, this.pv, this._caching); + //// + } + this._caching.lastFrame = frameNum; + return this.pv; + } + + function resetShape() { + this.paths = this.localShapeCollection; + } + + function shapesEqual(shape1, shape2) { + if (shape1._length !== shape2._length || shape1.c !== shape2.c) { + return false; + } + var i, len = shape1._length; + for (i = 0; i < len; i += 1) { + if (shape1.v[i][0] !== shape2.v[i][0] + || shape1.v[i][1] !== shape2.v[i][1] + || shape1.o[i][0] !== shape2.o[i][0] + || shape1.o[i][1] !== shape2.o[i][1] + || shape1.i[i][0] !== shape2.i[i][0] + || shape1.i[i][1] !== shape2.i[i][1]) { + return false; + } + } + return true; + } + + function setVValue(newPath) { + if (!shapesEqual(this.v, newPath)) { + this.v = shape_pool.clone(newPath); + this.localShapeCollection.releaseShapes(); + this.localShapeCollection.addShape(this.v); + this._mdf = true; + this.paths = this.localShapeCollection; + } + } + + function processEffectsSequence() { + if (this.elem.globalData.frameId === this.frameId) { + return; + } else if (!this.effectsSequence.length) { + this._mdf = false; + return; + } + if (this.lock) { + this.setVValue(this.pv); + return; + } + this.lock = true; + this._mdf = false; + var finalValue = this.kf ? this.pv : this.data.ks ? this.data.ks.k : this.data.pt.k; + var i, len = this.effectsSequence.length; + for (i = 0; i < len; i += 1) { + finalValue = this.effectsSequence[i](finalValue); + } + this.setVValue(finalValue); + this.lock = false; + this.frameId = this.elem.globalData.frameId; + }; + + function ShapeProperty(elem, data, type) { + this.propType = 'shape'; + this.comp = elem.comp; + this.container = elem; + this.elem = elem; + this.data = data; + this.k = false; + this.kf = false; + this._mdf = false; + var pathData = type === 3 ? data.pt.k : data.ks.k; + this.v = shape_pool.clone(pathData); + this.pv = shape_pool.clone(this.v); + this.localShapeCollection = shapeCollection_pool.newShapeCollection(); + this.paths = this.localShapeCollection; + this.paths.addShape(this.v); + this.reset = resetShape; + this.effectsSequence = []; + } + + function addEffect(effectFunction) { + this.effectsSequence.push(effectFunction); + this.container.addDynamicProperty(this); + } + + ShapeProperty.prototype.interpolateShape = interpolateShape; + ShapeProperty.prototype.getValue = processEffectsSequence; + ShapeProperty.prototype.setVValue = setVValue; + ShapeProperty.prototype.addEffect = addEffect; + + function KeyframedShapeProperty(elem, data, type) { + this.propType = 'shape'; + this.comp = elem.comp; + this.elem = elem; + this.container = elem; + this.offsetTime = elem.data.st; + this.keyframes = type === 3 ? data.pt.k : data.ks.k; + this.k = true; + this.kf = true; + var i, len = this.keyframes[0].s[0].i.length; + var jLen = this.keyframes[0].s[0].i[0].length; + this.v = shape_pool.newElement(); + this.v.setPathData(this.keyframes[0].s[0].c, len); + this.pv = shape_pool.clone(this.v); + this.localShapeCollection = shapeCollection_pool.newShapeCollection(); + this.paths = this.localShapeCollection; + this.paths.addShape(this.v); + this.lastFrame = initFrame; + this.reset = resetShape; + this._caching = { lastFrame: initFrame, lastIndex: 0 }; + this.effectsSequence = [interpolateShapeCurrentTime.bind(this)]; + } + KeyframedShapeProperty.prototype.getValue = processEffectsSequence; + KeyframedShapeProperty.prototype.interpolateShape = interpolateShape; + KeyframedShapeProperty.prototype.setVValue = setVValue; + KeyframedShapeProperty.prototype.addEffect = addEffect; + + var EllShapeProperty = (function () { + + var cPoint = roundCorner; + + function EllShapeProperty(elem, data) { + /*this.v = { + v: createSizedArray(4), + i: createSizedArray(4), + o: createSizedArray(4), + c: true + };*/ + this.v = shape_pool.newElement(); + this.v.setPathData(true, 4); + this.localShapeCollection = shapeCollection_pool.newShapeCollection(); + this.paths = this.localShapeCollection; + this.localShapeCollection.addShape(this.v); + this.d = data.d; + this.elem = elem; + this.comp = elem.comp; + this.frameId = -1; + this.initDynamicPropertyContainer(elem); + this.p = PropertyFactory.getProp(elem, data.p, 1, 0, this); + this.s = PropertyFactory.getProp(elem, data.s, 1, 0, this); + if (this.dynamicProperties.length) { + this.k = true; + } else { + this.k = false; + this.convertEllToPath(); + } + }; + + EllShapeProperty.prototype = { + reset: resetShape, + getValue: function () { + if (this.elem.globalData.frameId === this.frameId) { + return; + } + this.frameId = this.elem.globalData.frameId; + this.iterateDynamicProperties(); + + if (this._mdf) { + this.convertEllToPath(); + } + }, + convertEllToPath: function () { + var p0 = this.p.v[0], p1 = this.p.v[1], s0 = this.s.v[0] / 2, s1 = this.s.v[1] / 2; + var _cw = this.d !== 3; + var _v = this.v; + _v.v[0][0] = p0; + _v.v[0][1] = p1 - s1; + _v.v[1][0] = _cw ? p0 + s0 : p0 - s0; + _v.v[1][1] = p1; + _v.v[2][0] = p0; + _v.v[2][1] = p1 + s1; + _v.v[3][0] = _cw ? p0 - s0 : p0 + s0; + _v.v[3][1] = p1; + _v.i[0][0] = _cw ? p0 - s0 * cPoint : p0 + s0 * cPoint; + _v.i[0][1] = p1 - s1; + _v.i[1][0] = _cw ? p0 + s0 : p0 - s0; + _v.i[1][1] = p1 - s1 * cPoint; + _v.i[2][0] = _cw ? p0 + s0 * cPoint : p0 - s0 * cPoint; + _v.i[2][1] = p1 + s1; + _v.i[3][0] = _cw ? p0 - s0 : p0 + s0; + _v.i[3][1] = p1 + s1 * cPoint; + _v.o[0][0] = _cw ? p0 + s0 * cPoint : p0 - s0 * cPoint; + _v.o[0][1] = p1 - s1; + _v.o[1][0] = _cw ? p0 + s0 : p0 - s0; + _v.o[1][1] = p1 + s1 * cPoint; + _v.o[2][0] = _cw ? p0 - s0 * cPoint : p0 + s0 * cPoint; + _v.o[2][1] = p1 + s1; + _v.o[3][0] = _cw ? p0 - s0 : p0 + s0; + _v.o[3][1] = p1 - s1 * cPoint; + } + } + + extendPrototype([DynamicPropertyContainer], EllShapeProperty); + + return EllShapeProperty; + }()); + + var StarShapeProperty = (function () { + + function StarShapeProperty(elem, data) { + this.v = shape_pool.newElement(); + this.v.setPathData(true, 0); + this.elem = elem; + this.comp = elem.comp; + this.data = data; + this.frameId = -1; + this.d = data.d; + this.initDynamicPropertyContainer(elem); + if (data.sy === 1) { + this.ir = PropertyFactory.getProp(elem, data.ir, 0, 0, this); + this.is = PropertyFactory.getProp(elem, data.is, 0, 0.01, this); + this.convertToPath = this.convertStarToPath; + } else { + this.convertToPath = this.convertPolygonToPath; + } + this.pt = PropertyFactory.getProp(elem, data.pt, 0, 0, this); + this.p = PropertyFactory.getProp(elem, data.p, 1, 0, this); + this.r = PropertyFactory.getProp(elem, data.r, 0, degToRads, this); + this.or = PropertyFactory.getProp(elem, data.or, 0, 0, this); + this.os = PropertyFactory.getProp(elem, data.os, 0, 0.01, this); + this.localShapeCollection = shapeCollection_pool.newShapeCollection(); + this.localShapeCollection.addShape(this.v); + this.paths = this.localShapeCollection; + if (this.dynamicProperties.length) { + this.k = true; + } else { + this.k = false; + this.convertToPath(); + } + }; + + StarShapeProperty.prototype = { + reset: resetShape, + getValue: function () { + if (this.elem.globalData.frameId === this.frameId) { + return; + } + this.frameId = this.elem.globalData.frameId; + this.iterateDynamicProperties(); + if (this._mdf) { + this.convertToPath(); + } + }, + convertStarToPath: function () { + var numPts = Math.floor(this.pt.v) * 2; + var angle = Math.PI * 2 / numPts; + /*this.v.v.length = numPts; + this.v.i.length = numPts; + this.v.o.length = numPts;*/ + var longFlag = true; + var longRad = this.or.v; + var shortRad = this.ir.v; + var longRound = this.os.v; + var shortRound = this.is.v; + var longPerimSegment = 2 * Math.PI * longRad / (numPts * 2); + var shortPerimSegment = 2 * Math.PI * shortRad / (numPts * 2); + var i, rad, roundness, perimSegment, currentAng = -Math.PI / 2; + currentAng += this.r.v; + var dir = this.data.d === 3 ? -1 : 1; + this.v._length = 0; + for (i = 0; i < numPts; i += 1) { + rad = longFlag ? longRad : shortRad; + roundness = longFlag ? longRound : shortRound; + perimSegment = longFlag ? longPerimSegment : shortPerimSegment; + var x = rad * Math.cos(currentAng); + var y = rad * Math.sin(currentAng); + var ox = x === 0 && y === 0 ? 0 : y / Math.sqrt(x * x + y * y); + var oy = x === 0 && y === 0 ? 0 : -x / Math.sqrt(x * x + y * y); + x += + this.p.v[0]; + y += + this.p.v[1]; + this.v.setTripleAt(x, y, x - ox * perimSegment * roundness * dir, y - oy * perimSegment * roundness * dir, x + ox * perimSegment * roundness * dir, y + oy * perimSegment * roundness * dir, i, true); + + /*this.v.v[i] = [x,y]; + this.v.i[i] = [x+ox*perimSegment*roundness*dir,y+oy*perimSegment*roundness*dir]; + this.v.o[i] = [x-ox*perimSegment*roundness*dir,y-oy*perimSegment*roundness*dir]; + this.v._length = numPts;*/ + longFlag = !longFlag; + currentAng += angle * dir; + } + }, + convertPolygonToPath: function () { + var numPts = Math.floor(this.pt.v); + var angle = Math.PI * 2 / numPts; + var rad = this.or.v; + var roundness = this.os.v; + var perimSegment = 2 * Math.PI * rad / (numPts * 4); + var i, currentAng = -Math.PI / 2; + var dir = this.data.d === 3 ? -1 : 1; + currentAng += this.r.v; + this.v._length = 0; + for (i = 0; i < numPts; i += 1) { + var x = rad * Math.cos(currentAng); + var y = rad * Math.sin(currentAng); + var ox = x === 0 && y === 0 ? 0 : y / Math.sqrt(x * x + y * y); + var oy = x === 0 && y === 0 ? 0 : -x / Math.sqrt(x * x + y * y); + x += + this.p.v[0]; + y += + this.p.v[1]; + this.v.setTripleAt(x, y, x - ox * perimSegment * roundness * dir, y - oy * perimSegment * roundness * dir, x + ox * perimSegment * roundness * dir, y + oy * perimSegment * roundness * dir, i, true); + currentAng += angle * dir; + } + this.paths.length = 0; + this.paths[0] = this.v; + } + + } + extendPrototype([DynamicPropertyContainer], StarShapeProperty); + + return StarShapeProperty; + }()); + + var RectShapeProperty = (function () { + + function RectShapeProperty(elem, data) { + this.v = shape_pool.newElement(); + this.v.c = true; + this.localShapeCollection = shapeCollection_pool.newShapeCollection(); + this.localShapeCollection.addShape(this.v); + this.paths = this.localShapeCollection; + this.elem = elem; + this.comp = elem.comp; + this.frameId = -1; + this.d = data.d; + this.initDynamicPropertyContainer(elem); + this.p = PropertyFactory.getProp(elem, data.p, 1, 0, this); + this.s = PropertyFactory.getProp(elem, data.s, 1, 0, this); + this.r = PropertyFactory.getProp(elem, data.r, 0, 0, this); + if (this.dynamicProperties.length) { + this.k = true; + } else { + this.k = false; + this.convertRectToPath(); + } + }; + + RectShapeProperty.prototype = { + convertRectToPath: function () { + var p0 = this.p.v[0], p1 = this.p.v[1], v0 = this.s.v[0] / 2, v1 = this.s.v[1] / 2; + var round = bm_min(v0, v1, this.r.v); + var cPoint = round * (1 - roundCorner); + this.v._length = 0; + + if (this.d === 2 || this.d === 1) { + this.v.setTripleAt(p0 + v0, p1 - v1 + round, p0 + v0, p1 - v1 + round, p0 + v0, p1 - v1 + cPoint, 0, true); + this.v.setTripleAt(p0 + v0, p1 + v1 - round, p0 + v0, p1 + v1 - cPoint, p0 + v0, p1 + v1 - round, 1, true); + if (round !== 0) { + this.v.setTripleAt(p0 + v0 - round, p1 + v1, p0 + v0 - round, p1 + v1, p0 + v0 - cPoint, p1 + v1, 2, true); + this.v.setTripleAt(p0 - v0 + round, p1 + v1, p0 - v0 + cPoint, p1 + v1, p0 - v0 + round, p1 + v1, 3, true); + this.v.setTripleAt(p0 - v0, p1 + v1 - round, p0 - v0, p1 + v1 - round, p0 - v0, p1 + v1 - cPoint, 4, true); + this.v.setTripleAt(p0 - v0, p1 - v1 + round, p0 - v0, p1 - v1 + cPoint, p0 - v0, p1 - v1 + round, 5, true); + this.v.setTripleAt(p0 - v0 + round, p1 - v1, p0 - v0 + round, p1 - v1, p0 - v0 + cPoint, p1 - v1, 6, true); + this.v.setTripleAt(p0 + v0 - round, p1 - v1, p0 + v0 - cPoint, p1 - v1, p0 + v0 - round, p1 - v1, 7, true); + } else { + this.v.setTripleAt(p0 - v0, p1 + v1, p0 - v0 + cPoint, p1 + v1, p0 - v0, p1 + v1, 2); + this.v.setTripleAt(p0 - v0, p1 - v1, p0 - v0, p1 - v1 + cPoint, p0 - v0, p1 - v1, 3); + } + } else { + this.v.setTripleAt(p0 + v0, p1 - v1 + round, p0 + v0, p1 - v1 + cPoint, p0 + v0, p1 - v1 + round, 0, true); + if (round !== 0) { + this.v.setTripleAt(p0 + v0 - round, p1 - v1, p0 + v0 - round, p1 - v1, p0 + v0 - cPoint, p1 - v1, 1, true); + this.v.setTripleAt(p0 - v0 + round, p1 - v1, p0 - v0 + cPoint, p1 - v1, p0 - v0 + round, p1 - v1, 2, true); + this.v.setTripleAt(p0 - v0, p1 - v1 + round, p0 - v0, p1 - v1 + round, p0 - v0, p1 - v1 + cPoint, 3, true); + this.v.setTripleAt(p0 - v0, p1 + v1 - round, p0 - v0, p1 + v1 - cPoint, p0 - v0, p1 + v1 - round, 4, true); + this.v.setTripleAt(p0 - v0 + round, p1 + v1, p0 - v0 + round, p1 + v1, p0 - v0 + cPoint, p1 + v1, 5, true); + this.v.setTripleAt(p0 + v0 - round, p1 + v1, p0 + v0 - cPoint, p1 + v1, p0 + v0 - round, p1 + v1, 6, true); + this.v.setTripleAt(p0 + v0, p1 + v1 - round, p0 + v0, p1 + v1 - round, p0 + v0, p1 + v1 - cPoint, 7, true); + } else { + this.v.setTripleAt(p0 - v0, p1 - v1, p0 - v0 + cPoint, p1 - v1, p0 - v0, p1 - v1, 1, true); + this.v.setTripleAt(p0 - v0, p1 + v1, p0 - v0, p1 + v1 - cPoint, p0 - v0, p1 + v1, 2, true); + this.v.setTripleAt(p0 + v0, p1 + v1, p0 + v0 - cPoint, p1 + v1, p0 + v0, p1 + v1, 3, true); + + } + } + }, + getValue: function (frameNum) { + if (this.elem.globalData.frameId === this.frameId) { + return; + } + this.frameId = this.elem.globalData.frameId; + this.iterateDynamicProperties(); + if (this._mdf) { + this.convertRectToPath(); + } + + }, + reset: resetShape + } + extendPrototype([DynamicPropertyContainer], RectShapeProperty); + + return RectShapeProperty; + }()); + + function getShapeProp(elem, data, type) { + var prop; + if (type === 3 || type === 4) { + var dataProp = type === 3 ? data.pt : data.ks; + var keys = dataProp.k; + if (keys.length) { + prop = new KeyframedShapeProperty(elem, data, type); + } else { + prop = new ShapeProperty(elem, data, type); + } + } else if (type === 5) { + prop = new RectShapeProperty(elem, data); + } else if (type === 6) { + prop = new EllShapeProperty(elem, data); + } else if (type === 7) { + prop = new StarShapeProperty(elem, data); + } + if (prop.k) { + elem.addDynamicProperty(prop); + } + return prop; + } + + function getConstructorFunction() { + return ShapeProperty; + } + + function getKeyframedConstructorFunction() { + return KeyframedShapeProperty; + } + + var ob = {}; + ob.getShapeProp = getShapeProp; + ob.getConstructorFunction = getConstructorFunction; + ob.getKeyframedConstructorFunction = getKeyframedConstructorFunction; + return ob; + }()); + var ShapeModifiers = (function () { + var ob = {}; + var modifiers = {}; + ob.registerModifier = registerModifier; + ob.getModifier = getModifier; + + function registerModifier(nm, factory) { + if (!modifiers[nm]) { + modifiers[nm] = factory; + } + } + + function getModifier(nm, elem, data) { + return new modifiers[nm](elem, data); + } + + return ob; + }()); + + function ShapeModifier() { } + ShapeModifier.prototype.initModifierProperties = function () { }; + ShapeModifier.prototype.addShapeToModifier = function () { }; + ShapeModifier.prototype.addShape = function (data) { + if (!this.closed) { + // Adding shape to dynamic properties. It covers the case where a shape has no effects applied, to reset it's _mdf state on every tick. + data.sh.container.addDynamicProperty(data.sh); + var shapeData = { shape: data.sh, data: data, localShapeCollection: shapeCollection_pool.newShapeCollection() }; + this.shapes.push(shapeData); + this.addShapeToModifier(shapeData); + if (this._isAnimated) { + data.setAsAnimated(); + } + } + }; + ShapeModifier.prototype.init = function (elem, data) { + this.shapes = []; + this.elem = elem; + this.initDynamicPropertyContainer(elem); + this.initModifierProperties(elem, data); + this.frameId = initialDefaultFrame; + this.closed = false; + this.k = false; + if (this.dynamicProperties.length) { + this.k = true; + } else { + this.getValue(true); + } + }; + ShapeModifier.prototype.processKeys = function () { + if (this.elem.globalData.frameId === this.frameId) { + return; + } + this.frameId = this.elem.globalData.frameId; + this.iterateDynamicProperties(); + }; + + extendPrototype([DynamicPropertyContainer], ShapeModifier); + function TrimModifier() { + } + extendPrototype([ShapeModifier], TrimModifier); + TrimModifier.prototype.initModifierProperties = function (elem, data) { + this.s = PropertyFactory.getProp(elem, data.s, 0, 0.01, this); + this.e = PropertyFactory.getProp(elem, data.e, 0, 0.01, this); + this.o = PropertyFactory.getProp(elem, data.o, 0, 0, this); + this.sValue = 0; + this.eValue = 0; + this.getValue = this.processKeys; + this.m = data.m; + this._isAnimated = !!this.s.effectsSequence.length || !!this.e.effectsSequence.length || !!this.o.effectsSequence.length; + }; + + TrimModifier.prototype.addShapeToModifier = function (shapeData) { + shapeData.pathsData = []; + }; + + TrimModifier.prototype.calculateShapeEdges = function (s, e, shapeLength, addedLength, totalModifierLength) { + var segments = []; + if (e <= 1) { + segments.push({ + s: s, + e: e + }); + } else if (s >= 1) { + segments.push({ + s: s - 1, + e: e - 1 + }); + } else { + segments.push({ + s: s, + e: 1 + }); + segments.push({ + s: 0, + e: e - 1 + }); + } + var shapeSegments = []; + var i, len = segments.length, segmentOb; + for (i = 0; i < len; i += 1) { + segmentOb = segments[i]; + if (segmentOb.e * totalModifierLength < addedLength || segmentOb.s * totalModifierLength > addedLength + shapeLength) { + + } else { + var shapeS, shapeE; + if (segmentOb.s * totalModifierLength <= addedLength) { + shapeS = 0; + } else { + shapeS = (segmentOb.s * totalModifierLength - addedLength) / shapeLength; + } + if (segmentOb.e * totalModifierLength >= addedLength + shapeLength) { + shapeE = 1; + } else { + shapeE = ((segmentOb.e * totalModifierLength - addedLength) / shapeLength); + } + shapeSegments.push([shapeS, shapeE]); + } + } + if (!shapeSegments.length) { + shapeSegments.push([0, 0]); + } + return shapeSegments; + }; + + TrimModifier.prototype.releasePathsData = function (pathsData) { + var i, len = pathsData.length; + for (i = 0; i < len; i += 1) { + segments_length_pool.release(pathsData[i]); + } + pathsData.length = 0; + return pathsData; + }; + + TrimModifier.prototype.processShapes = function (_isFirstFrame) { + var s, e; + if (this._mdf || _isFirstFrame) { + var o = (this.o.v % 360) / 360; + if (o < 0) { + o += 1; + } + s = (this.s.v > 1 ? 1 : this.s.v < 0 ? 0 : this.s.v) + o; + e = (this.e.v > 1 ? 1 : this.e.v < 0 ? 0 : this.e.v) + o; + if (s === e) { + + } + if (s > e) { + var _s = s; + s = e; + e = _s; + } + s = Math.round(s * 10000) * 0.0001; + e = Math.round(e * 10000) * 0.0001; + this.sValue = s; + this.eValue = e; + } else { + s = this.sValue; + e = this.eValue; + } + var shapePaths; + var i, len = this.shapes.length, j, jLen; + var pathsData, pathData, totalShapeLength, totalModifierLength = 0; + + if (e === s) { + for (i = 0; i < len; i += 1) { + this.shapes[i].localShapeCollection.releaseShapes(); + this.shapes[i].shape._mdf = true; + this.shapes[i].shape.paths = this.shapes[i].localShapeCollection; + } + } else if (!((e === 1 && s === 0) || (e === 0 && s === 1))) { + var segments = [], shapeData, localShapeCollection; + for (i = 0; i < len; i += 1) { + shapeData = this.shapes[i]; + // if shape hasn't changed and trim properties haven't changed, cached previous path can be used + if (!shapeData.shape._mdf && !this._mdf && !_isFirstFrame && this.m !== 2) { + shapeData.shape.paths = shapeData.localShapeCollection; + } else { + shapePaths = shapeData.shape.paths; + jLen = shapePaths._length; + totalShapeLength = 0; + if (!shapeData.shape._mdf && shapeData.pathsData.length) { + totalShapeLength = shapeData.totalShapeLength; + } else { + pathsData = this.releasePathsData(shapeData.pathsData); + for (j = 0; j < jLen; j += 1) { + pathData = bez.getSegmentsLength(shapePaths.shapes[j]); + pathsData.push(pathData); + totalShapeLength += pathData.totalLength; + } + shapeData.totalShapeLength = totalShapeLength; + shapeData.pathsData = pathsData; + } + + totalModifierLength += totalShapeLength; + shapeData.shape._mdf = true; + } + } + var shapeS = s, shapeE = e, addedLength = 0, edges; + for (i = len - 1; i >= 0; i -= 1) { + shapeData = this.shapes[i]; + if (shapeData.shape._mdf) { + localShapeCollection = shapeData.localShapeCollection; + localShapeCollection.releaseShapes(); + //if m === 2 means paths are trimmed individually so edges need to be found for this specific shape relative to whoel group + if (this.m === 2 && len > 1) { + edges = this.calculateShapeEdges(s, e, shapeData.totalShapeLength, addedLength, totalModifierLength); + addedLength += shapeData.totalShapeLength; + } else { + edges = [[shapeS, shapeE]]; + } + jLen = edges.length; + for (j = 0; j < jLen; j += 1) { + shapeS = edges[j][0]; + shapeE = edges[j][1]; + segments.length = 0; + if (shapeE <= 1) { + segments.push({ + s: shapeData.totalShapeLength * shapeS, + e: shapeData.totalShapeLength * shapeE + }); + } else if (shapeS >= 1) { + segments.push({ + s: shapeData.totalShapeLength * (shapeS - 1), + e: shapeData.totalShapeLength * (shapeE - 1) + }); + } else { + segments.push({ + s: shapeData.totalShapeLength * shapeS, + e: shapeData.totalShapeLength + }); + segments.push({ + s: 0, + e: shapeData.totalShapeLength * (shapeE - 1) + }); + } + var newShapesData = this.addShapes(shapeData, segments[0]); + if (segments[0].s !== segments[0].e) { + if (segments.length > 1) { + var lastShapeInCollection = shapeData.shape.paths.shapes[shapeData.shape.paths._length - 1]; + if (lastShapeInCollection.c) { + var lastShape = newShapesData.pop(); + this.addPaths(newShapesData, localShapeCollection); + newShapesData = this.addShapes(shapeData, segments[1], lastShape); + } else { + this.addPaths(newShapesData, localShapeCollection); + newShapesData = this.addShapes(shapeData, segments[1]); + } + } + this.addPaths(newShapesData, localShapeCollection); + } + + } + shapeData.shape.paths = localShapeCollection; + } + } + } else if (this._mdf) { + for (i = 0; i < len; i += 1) { + //Releasign Trim Cached paths data when no trim applied in case shapes are modified inbetween. + //Don't remove this even if it's losing cached info. + this.shapes[i].pathsData.length = 0; + this.shapes[i].shape._mdf = true; + } + } + }; + + TrimModifier.prototype.addPaths = function (newPaths, localShapeCollection) { + var i, len = newPaths.length; + for (i = 0; i < len; i += 1) { + localShapeCollection.addShape(newPaths[i]); + } + }; + + TrimModifier.prototype.addSegment = function (pt1, pt2, pt3, pt4, shapePath, pos, newShape) { + shapePath.setXYAt(pt2[0], pt2[1], 'o', pos); + shapePath.setXYAt(pt3[0], pt3[1], 'i', pos + 1); + if (newShape) { + shapePath.setXYAt(pt1[0], pt1[1], 'v', pos); + } + shapePath.setXYAt(pt4[0], pt4[1], 'v', pos + 1); + }; + + TrimModifier.prototype.addSegmentFromArray = function (points, shapePath, pos, newShape) { + shapePath.setXYAt(points[1], points[5], 'o', pos); + shapePath.setXYAt(points[2], points[6], 'i', pos + 1); + if (newShape) { + shapePath.setXYAt(points[0], points[4], 'v', pos); + } + shapePath.setXYAt(points[3], points[7], 'v', pos + 1); + }; + + TrimModifier.prototype.addShapes = function (shapeData, shapeSegment, shapePath) { + var pathsData = shapeData.pathsData; + var shapePaths = shapeData.shape.paths.shapes; + var i, len = shapeData.shape.paths._length, j, jLen; + var addedLength = 0; + var currentLengthData, segmentCount; + var lengths; + var segment; + var shapes = []; + var initPos; + var newShape = true; + if (!shapePath) { + shapePath = shape_pool.newElement(); + segmentCount = 0; + initPos = 0; + } else { + segmentCount = shapePath._length; + initPos = shapePath._length; + } + shapes.push(shapePath); + for (i = 0; i < len; i += 1) { + lengths = pathsData[i].lengths; + shapePath.c = shapePaths[i].c; + jLen = shapePaths[i].c ? lengths.length : lengths.length + 1; + for (j = 1; j < jLen; j += 1) { + currentLengthData = lengths[j - 1]; + if (addedLength + currentLengthData.addedLength < shapeSegment.s) { + addedLength += currentLengthData.addedLength; + shapePath.c = false; + } else if (addedLength > shapeSegment.e) { + shapePath.c = false; + break; + } else { + if (shapeSegment.s <= addedLength && shapeSegment.e >= addedLength + currentLengthData.addedLength) { + this.addSegment(shapePaths[i].v[j - 1], shapePaths[i].o[j - 1], shapePaths[i].i[j], shapePaths[i].v[j], shapePath, segmentCount, newShape); + newShape = false; + } else { + segment = bez.getNewSegment(shapePaths[i].v[j - 1], shapePaths[i].v[j], shapePaths[i].o[j - 1], shapePaths[i].i[j], (shapeSegment.s - addedLength) / currentLengthData.addedLength, (shapeSegment.e - addedLength) / currentLengthData.addedLength, lengths[j - 1]); + this.addSegmentFromArray(segment, shapePath, segmentCount, newShape); + // this.addSegment(segment.pt1, segment.pt3, segment.pt4, segment.pt2, shapePath, segmentCount, newShape); + newShape = false; + shapePath.c = false; + } + addedLength += currentLengthData.addedLength; + segmentCount += 1; + } + } + if (shapePaths[i].c && lengths.length) { + currentLengthData = lengths[j - 1]; + if (addedLength <= shapeSegment.e) { + var segmentLength = lengths[j - 1].addedLength; + if (shapeSegment.s <= addedLength && shapeSegment.e >= addedLength + segmentLength) { + this.addSegment(shapePaths[i].v[j - 1], shapePaths[i].o[j - 1], shapePaths[i].i[0], shapePaths[i].v[0], shapePath, segmentCount, newShape); + newShape = false; + } else { + segment = bez.getNewSegment(shapePaths[i].v[j - 1], shapePaths[i].v[0], shapePaths[i].o[j - 1], shapePaths[i].i[0], (shapeSegment.s - addedLength) / segmentLength, (shapeSegment.e - addedLength) / segmentLength, lengths[j - 1]); + this.addSegmentFromArray(segment, shapePath, segmentCount, newShape); + // this.addSegment(segment.pt1, segment.pt3, segment.pt4, segment.pt2, shapePath, segmentCount, newShape); + newShape = false; + shapePath.c = false; + } + } else { + shapePath.c = false; + } + addedLength += currentLengthData.addedLength; + segmentCount += 1; + } + if (shapePath._length) { + shapePath.setXYAt(shapePath.v[initPos][0], shapePath.v[initPos][1], 'i', initPos); + shapePath.setXYAt(shapePath.v[shapePath._length - 1][0], shapePath.v[shapePath._length - 1][1], 'o', shapePath._length - 1); + } + if (addedLength > shapeSegment.e) { + break; + } + if (i < len - 1) { + shapePath = shape_pool.newElement(); + newShape = true; + shapes.push(shapePath); + segmentCount = 0; + } + } + return shapes; + }; + + + ShapeModifiers.registerModifier('tm', TrimModifier); + function RoundCornersModifier() { } + extendPrototype([ShapeModifier], RoundCornersModifier); + RoundCornersModifier.prototype.initModifierProperties = function (elem, data) { + this.getValue = this.processKeys; + this.rd = PropertyFactory.getProp(elem, data.r, 0, null, this); + this._isAnimated = !!this.rd.effectsSequence.length; + }; + + RoundCornersModifier.prototype.processPath = function (path, round) { + var cloned_path = shape_pool.newElement(); + cloned_path.c = path.c; + var i, len = path._length; + var currentV, currentI, currentO, closerV, newV, newO, newI, distance, newPosPerc, index = 0; + var vX, vY, oX, oY, iX, iY; + for (i = 0; i < len; i += 1) { + currentV = path.v[i]; + currentO = path.o[i]; + currentI = path.i[i]; + if (currentV[0] === currentO[0] && currentV[1] === currentO[1] && currentV[0] === currentI[0] && currentV[1] === currentI[1]) { + if ((i === 0 || i === len - 1) && !path.c) { + cloned_path.setTripleAt(currentV[0], currentV[1], currentO[0], currentO[1], currentI[0], currentI[1], index); + /*cloned_path.v[index] = currentV; + cloned_path.o[index] = currentO; + cloned_path.i[index] = currentI;*/ + index += 1; + } else { + if (i === 0) { + closerV = path.v[len - 1]; + } else { + closerV = path.v[i - 1]; + } + distance = Math.sqrt(Math.pow(currentV[0] - closerV[0], 2) + Math.pow(currentV[1] - closerV[1], 2)); + newPosPerc = distance ? Math.min(distance / 2, round) / distance : 0; + vX = iX = currentV[0] + (closerV[0] - currentV[0]) * newPosPerc; + vY = iY = currentV[1] - (currentV[1] - closerV[1]) * newPosPerc; + oX = vX - (vX - currentV[0]) * roundCorner; + oY = vY - (vY - currentV[1]) * roundCorner; + cloned_path.setTripleAt(vX, vY, oX, oY, iX, iY, index); + index += 1; + + if (i === len - 1) { + closerV = path.v[0]; + } else { + closerV = path.v[i + 1]; + } + distance = Math.sqrt(Math.pow(currentV[0] - closerV[0], 2) + Math.pow(currentV[1] - closerV[1], 2)); + newPosPerc = distance ? Math.min(distance / 2, round) / distance : 0; + vX = oX = currentV[0] + (closerV[0] - currentV[0]) * newPosPerc; + vY = oY = currentV[1] + (closerV[1] - currentV[1]) * newPosPerc; + iX = vX - (vX - currentV[0]) * roundCorner; + iY = vY - (vY - currentV[1]) * roundCorner; + cloned_path.setTripleAt(vX, vY, oX, oY, iX, iY, index); + index += 1; + } + } else { + cloned_path.setTripleAt(path.v[i][0], path.v[i][1], path.o[i][0], path.o[i][1], path.i[i][0], path.i[i][1], index); + index += 1; + } + } + return cloned_path; + }; + + RoundCornersModifier.prototype.processShapes = function (_isFirstFrame) { + var shapePaths; + var i, len = this.shapes.length; + var j, jLen; + var rd = this.rd.v; + + if (rd !== 0) { + var shapeData, newPaths, localShapeCollection; + for (i = 0; i < len; i += 1) { + shapeData = this.shapes[i]; + newPaths = shapeData.shape.paths; + localShapeCollection = shapeData.localShapeCollection; + if (!(!shapeData.shape._mdf && !this._mdf && !_isFirstFrame)) { + localShapeCollection.releaseShapes(); + shapeData.shape._mdf = true; + shapePaths = shapeData.shape.paths.shapes; + jLen = shapeData.shape.paths._length; + for (j = 0; j < jLen; j += 1) { + localShapeCollection.addShape(this.processPath(shapePaths[j], rd)); + } + } + shapeData.shape.paths = shapeData.localShapeCollection; + } + + } + if (!this.dynamicProperties.length) { + this._mdf = false; + } + }; + + ShapeModifiers.registerModifier('rd', RoundCornersModifier); + function RepeaterModifier() { } + extendPrototype([ShapeModifier], RepeaterModifier); + + RepeaterModifier.prototype.initModifierProperties = function (elem, data) { + this.getValue = this.processKeys; + this.c = PropertyFactory.getProp(elem, data.c, 0, null, this); + this.o = PropertyFactory.getProp(elem, data.o, 0, null, this); + this.tr = TransformPropertyFactory.getTransformProperty(elem, data.tr, this); + this.so = PropertyFactory.getProp(elem, data.tr.so, 0, 0.01, this); + this.eo = PropertyFactory.getProp(elem, data.tr.eo, 0, 0.01, this); + this.data = data; + if (!this.dynamicProperties.length) { + this.getValue(true); + } + this._isAnimated = !!this.dynamicProperties.length; + this.pMatrix = new Matrix(); + this.rMatrix = new Matrix(); + this.sMatrix = new Matrix(); + this.tMatrix = new Matrix(); + this.matrix = new Matrix(); + }; + + RepeaterModifier.prototype.applyTransforms = function (pMatrix, rMatrix, sMatrix, transform, perc, inv) { + var dir = inv ? -1 : 1; + var scaleX = transform.s.v[0] + (1 - transform.s.v[0]) * (1 - perc); + var scaleY = transform.s.v[1] + (1 - transform.s.v[1]) * (1 - perc); + pMatrix.translate(transform.p.v[0] * dir * perc, transform.p.v[1] * dir * perc, transform.p.v[2]); + rMatrix.translate(-transform.a.v[0], -transform.a.v[1], transform.a.v[2]); + rMatrix.rotate(-transform.r.v * dir * perc); + rMatrix.translate(transform.a.v[0], transform.a.v[1], transform.a.v[2]); + sMatrix.translate(-transform.a.v[0], -transform.a.v[1], transform.a.v[2]); + sMatrix.scale(inv ? 1 / scaleX : scaleX, inv ? 1 / scaleY : scaleY); + sMatrix.translate(transform.a.v[0], transform.a.v[1], transform.a.v[2]); + }; + + RepeaterModifier.prototype.init = function (elem, arr, pos, elemsData) { + this.elem = elem; + this.arr = arr; + this.pos = pos; + this.elemsData = elemsData; + this._currentCopies = 0; + this._elements = []; + this._groups = []; + this.frameId = -1; + this.initDynamicPropertyContainer(elem); + this.initModifierProperties(elem, arr[pos]); + var cont = 0; + while (pos > 0) { + pos -= 1; + //this._elements.unshift(arr.splice(pos,1)[0]); + this._elements.unshift(arr[pos]); + cont += 1; + } + if (this.dynamicProperties.length) { + this.k = true; + } else { + this.getValue(true); + } + }; + + RepeaterModifier.prototype.resetElements = function (elements) { + var i, len = elements.length; + for (i = 0; i < len; i += 1) { + elements[i]._processed = false; + if (elements[i].ty === 'gr') { + this.resetElements(elements[i].it); + } + } + }; + + RepeaterModifier.prototype.cloneElements = function (elements) { + var i, len = elements.length; + var newElements = JSON.parse(JSON.stringify(elements)); + this.resetElements(newElements); + return newElements; + }; + + RepeaterModifier.prototype.changeGroupRender = function (elements, renderFlag) { + var i, len = elements.length; + for (i = 0; i < len; i += 1) { + elements[i]._render = renderFlag; + if (elements[i].ty === 'gr') { + this.changeGroupRender(elements[i].it, renderFlag); + } + } + }; + + RepeaterModifier.prototype.processShapes = function (_isFirstFrame) { + var items, itemsTransform, i, dir, cont; + if (this._mdf || _isFirstFrame) { + var copies = Math.ceil(this.c.v); + if (this._groups.length < copies) { + while (this._groups.length < copies) { + var group = { + it: this.cloneElements(this._elements), + ty: 'gr' + }; + group.it.push({ "a": { "a": 0, "ix": 1, "k": [0, 0] }, "nm": "Transform", "o": { "a": 0, "ix": 7, "k": 100 }, "p": { "a": 0, "ix": 2, "k": [0, 0] }, "r": { "a": 1, "ix": 6, "k": [{ s: 0, e: 0, t: 0 }, { s: 0, e: 0, t: 1 }] }, "s": { "a": 0, "ix": 3, "k": [100, 100] }, "sa": { "a": 0, "ix": 5, "k": 0 }, "sk": { "a": 0, "ix": 4, "k": 0 }, "ty": "tr" }); + + this.arr.splice(0, 0, group); + this._groups.splice(0, 0, group); + this._currentCopies += 1; + } + this.elem.reloadShapes(); + } + cont = 0; + var renderFlag; + for (i = 0; i <= this._groups.length - 1; i += 1) { + renderFlag = cont < copies; + this._groups[i]._render = renderFlag; + this.changeGroupRender(this._groups[i].it, renderFlag); + cont += 1; + } + + this._currentCopies = copies; + //// + + var offset = this.o.v; + var offsetModulo = offset % 1; + var roundOffset = offset > 0 ? Math.floor(offset) : Math.ceil(offset); + var k; + var tMat = this.tr.v.props; + var pProps = this.pMatrix.props; + var rProps = this.rMatrix.props; + var sProps = this.sMatrix.props; + this.pMatrix.reset(); + this.rMatrix.reset(); + this.sMatrix.reset(); + this.tMatrix.reset(); + this.matrix.reset(); + var iteration = 0; + + if (offset > 0) { + while (iteration < roundOffset) { + this.applyTransforms(this.pMatrix, this.rMatrix, this.sMatrix, this.tr, 1, false); + iteration += 1; + } + if (offsetModulo) { + this.applyTransforms(this.pMatrix, this.rMatrix, this.sMatrix, this.tr, offsetModulo, false); + iteration += offsetModulo; + } + } else if (offset < 0) { + while (iteration > roundOffset) { + this.applyTransforms(this.pMatrix, this.rMatrix, this.sMatrix, this.tr, 1, true); + iteration -= 1; + } + if (offsetModulo) { + this.applyTransforms(this.pMatrix, this.rMatrix, this.sMatrix, this.tr, - offsetModulo, true); + iteration -= offsetModulo; + } + } + i = this.data.m === 1 ? 0 : this._currentCopies - 1; + dir = this.data.m === 1 ? 1 : -1; + cont = this._currentCopies; + var j, jLen; + while (cont) { + items = this.elemsData[i].it; + itemsTransform = items[items.length - 1].transform.mProps.v.props; + jLen = itemsTransform.length; + items[items.length - 1].transform.mProps._mdf = true; + items[items.length - 1].transform.op._mdf = true; + items[items.length - 1].transform.op.v = this.so.v + (this.eo.v - this.so.v) * (i / (this._currentCopies - 1)); + if (iteration !== 0) { + if ((i !== 0 && dir === 1) || (i !== this._currentCopies - 1 && dir === -1)) { + this.applyTransforms(this.pMatrix, this.rMatrix, this.sMatrix, this.tr, 1, false); + } + this.matrix.transform(rProps[0], rProps[1], rProps[2], rProps[3], rProps[4], rProps[5], rProps[6], rProps[7], rProps[8], rProps[9], rProps[10], rProps[11], rProps[12], rProps[13], rProps[14], rProps[15]); + this.matrix.transform(sProps[0], sProps[1], sProps[2], sProps[3], sProps[4], sProps[5], sProps[6], sProps[7], sProps[8], sProps[9], sProps[10], sProps[11], sProps[12], sProps[13], sProps[14], sProps[15]); + this.matrix.transform(pProps[0], pProps[1], pProps[2], pProps[3], pProps[4], pProps[5], pProps[6], pProps[7], pProps[8], pProps[9], pProps[10], pProps[11], pProps[12], pProps[13], pProps[14], pProps[15]); + + for (j = 0; j < jLen; j += 1) { + itemsTransform[j] = this.matrix.props[j]; + } + this.matrix.reset(); + } else { + this.matrix.reset(); + for (j = 0; j < jLen; j += 1) { + itemsTransform[j] = this.matrix.props[j]; + } + } + iteration += 1; + cont -= 1; + i += dir; + } + } else { + cont = this._currentCopies; + i = 0; + dir = 1; + while (cont) { + items = this.elemsData[i].it; + itemsTransform = items[items.length - 1].transform.mProps.v.props; + items[items.length - 1].transform.mProps._mdf = false; + items[items.length - 1].transform.op._mdf = false; + cont -= 1; + i += dir; + } + } + }; + + RepeaterModifier.prototype.addShape = function () { }; + + ShapeModifiers.registerModifier('rp', RepeaterModifier); + function ShapeCollection() { + this._length = 0; + this._maxLength = 4; + this.shapes = createSizedArray(this._maxLength); + } + + ShapeCollection.prototype.addShape = function (shapeData) { + if (this._length === this._maxLength) { + this.shapes = this.shapes.concat(createSizedArray(this._maxLength)); + this._maxLength *= 2; + } + this.shapes[this._length] = shapeData; + this._length += 1; + }; + + ShapeCollection.prototype.releaseShapes = function () { + var i; + for (i = 0; i < this._length; i += 1) { + shape_pool.release(this.shapes[i]); + } + this._length = 0; + }; + function DashProperty(elem, data, renderer, container) { + this.elem = elem; + this.frameId = -1; + this.dataProps = createSizedArray(data.length); + this.renderer = renderer; + this.k = false; + this.dashStr = ''; + this.dashArray = createTypedArray('float32', data.length ? data.length - 1 : 0); + this.dashoffset = createTypedArray('float32', 1); + this.initDynamicPropertyContainer(container); + var i, len = data.length || 0, prop; + for (i = 0; i < len; i += 1) { + prop = PropertyFactory.getProp(elem, data[i].v, 0, 0, this); + this.k = prop.k || this.k; + this.dataProps[i] = { n: data[i].n, p: prop }; + } + if (!this.k) { + this.getValue(true); + } + this._isAnimated = this.k; + } + + DashProperty.prototype.getValue = function (forceRender) { + if (this.elem.globalData.frameId === this.frameId && !forceRender) { + return; + } + this.frameId = this.elem.globalData.frameId; + this.iterateDynamicProperties(); + this._mdf = this._mdf || forceRender; + if (this._mdf) { + var i = 0, len = this.dataProps.length; + if (this.renderer === 'svg') { + this.dashStr = ''; + } + for (i = 0; i < len; i += 1) { + if (this.dataProps[i].n != 'o') { + if (this.renderer === 'svg') { + this.dashStr += ' ' + this.dataProps[i].p.v; + } else { + this.dashArray[i] = this.dataProps[i].p.v; + } + } else { + this.dashoffset[0] = this.dataProps[i].p.v; + } + } + } + }; + extendPrototype([DynamicPropertyContainer], DashProperty); + function GradientProperty(elem, data, container) { + this.data = data; + this.c = createTypedArray('uint8c', data.p * 4); + var cLength = data.k.k[0].s ? (data.k.k[0].s.length - data.p * 4) : data.k.k.length - data.p * 4; + this.o = createTypedArray('float32', cLength); + this._cmdf = false; + this._omdf = false; + this._collapsable = this.checkCollapsable(); + this._hasOpacity = cLength; + this.initDynamicPropertyContainer(container); + this.prop = PropertyFactory.getProp(elem, data.k, 1, null, this); + this.k = this.prop.k; + this.getValue(true); + } + + GradientProperty.prototype.comparePoints = function (values, points) { + var i = 0, len = this.o.length / 2, diff; + while (i < len) { + diff = Math.abs(values[i * 4] - values[points * 4 + i * 2]); + if (diff > 0.01) { + return false; + } + i += 1; + } + return true; + }; + + GradientProperty.prototype.checkCollapsable = function () { + if (this.o.length / 2 !== this.c.length / 4) { + return false; + } + if (this.data.k.k[0].s) { + var i = 0, len = this.data.k.k.length; + while (i < len) { + if (!this.comparePoints(this.data.k.k[i].s, this.data.p)) { + return false; + } + i += 1; + } + } else if (!this.comparePoints(this.data.k.k, this.data.p)) { + return false; + } + return true; + }; + + GradientProperty.prototype.getValue = function (forceRender) { + this.prop.getValue(); + this._mdf = false; + this._cmdf = false; + this._omdf = false; + if (this.prop._mdf || forceRender) { + var i, len = this.data.p * 4; + var mult, val; + for (i = 0; i < len; i += 1) { + mult = i % 4 === 0 ? 100 : 255; + val = Math.round(this.prop.v[i] * mult); + if (this.c[i] !== val) { + this.c[i] = val; + this._cmdf = !forceRender; + } + } + if (this.o.length) { + len = this.prop.v.length; + for (i = this.data.p * 4; i < len; i += 1) { + mult = i % 2 === 0 ? 100 : 1; + val = i % 2 === 0 ? Math.round(this.prop.v[i] * 100) : this.prop.v[i]; + if (this.o[i - this.data.p * 4] !== val) { + this.o[i - this.data.p * 4] = val; + this._omdf = !forceRender; + } + } + } + this._mdf = !forceRender; + } + }; + + extendPrototype([DynamicPropertyContainer], GradientProperty); + var buildShapeString = function (pathNodes, length, closed, mat) { + if (length === 0) { + return ''; + } + var _o = pathNodes.o; + var _i = pathNodes.i; + var _v = pathNodes.v; + var i, shapeString = " M" + mat.applyToPointStringified(_v[0][0], _v[0][1]); + for (i = 1; i < length; i += 1) { + shapeString += " C" + mat.applyToPointStringified(_o[i - 1][0], _o[i - 1][1]) + " " + mat.applyToPointStringified(_i[i][0], _i[i][1]) + " " + mat.applyToPointStringified(_v[i][0], _v[i][1]); + } + if (closed && length) { + shapeString += " C" + mat.applyToPointStringified(_o[i - 1][0], _o[i - 1][1]) + " " + mat.applyToPointStringified(_i[0][0], _i[0][1]) + " " + mat.applyToPointStringified(_v[0][0], _v[0][1]); + shapeString += 'z'; + } + return shapeString; + } + var ImagePreloader = (function () { + + var proxyImage = (function () { + var canvas = createTag('canvas'); + canvas.width = 1; + canvas.height = 1; + var ctx = canvas.getContext('2d'); + ctx.fillStyle = 'rgba(0,0,0,0)'; + ctx.fillRect(0, 0, 1, 1); + return canvas; + }()) + + function imageLoaded() { + this.loadedAssets += 1; + if (this.loadedAssets === this.totalImages) { + if (this.imagesLoadedCb) { + this.imagesLoadedCb(null); + } + } + } + + function getAssetsPath(assetData, assetsPath, original_path) { + var path = ''; + if (assetData.e) { + path = assetData.p; + } else if (assetsPath) { + var imagePath = assetData.p; + if (imagePath.indexOf('images/') !== -1) { + imagePath = imagePath.split('/')[1]; + } + path = assetsPath + imagePath; + } else { + path = original_path; + path += assetData.u ? assetData.u : ''; + path += assetData.p; + } + return path; + } + + function createImageData(assetData) { + var path = getAssetsPath(assetData, this.assetsPath, this.path); + var img = createTag('img'); + img.crossOrigin = 'anonymous'; + img.addEventListener('load', this._imageLoaded.bind(this), false); + img.addEventListener('error', function () { + ob.img = proxyImage; + this._imageLoaded(); + }.bind(this), false); + img.src = path; + var ob = { + img: img, + assetData: assetData + } + return ob; + } + + function loadAssets(assets, cb) { + this.imagesLoadedCb = cb; + var i, len = assets.length; + for (i = 0; i < len; i += 1) { + if (!assets[i].layers) { + this.totalImages += 1; + this.images.push(this._createImageData(assets[i])); + } + } + } + + function setPath(path) { + this.path = path || ''; + } + + function setAssetsPath(path) { + this.assetsPath = path || ''; + } + + function getImage(assetData) { + var i = 0, len = this.images.length; + while (i < len) { + if (this.images[i].assetData === assetData) { + return this.images[i].img; + } + i += 1; + } + } + + function destroy() { + this.imagesLoadedCb = null; + this.images.length = 0; + } + + function loaded() { + return this.totalImages === this.loadedAssets; + } + + return function ImagePreloader() { + this.loadAssets = loadAssets; + this.setAssetsPath = setAssetsPath; + this.setPath = setPath; + this.loaded = loaded; + this.destroy = destroy; + this.getImage = getImage; + this._createImageData = createImageData; + this._imageLoaded = imageLoaded; + this.assetsPath = ''; + this.path = ''; + this.totalImages = 0; + this.loadedAssets = 0; + this.imagesLoadedCb = null; + this.images = []; + }; + }()); + var featureSupport = (function () { + var ob = { + maskType: true + }; + if (/MSIE 10/i.test(navigator.userAgent) || /MSIE 9/i.test(navigator.userAgent) || /rv:11.0/i.test(navigator.userAgent) || /Edge\/\d./i.test(navigator.userAgent)) { + ob.maskType = false; + } + return ob; + }()); + var filtersFactory = (function () { + var ob = {}; + ob.createFilter = createFilter; + ob.createAlphaToLuminanceFilter = createAlphaToLuminanceFilter; + + function createFilter(filId) { + var fil = createNS('filter'); + fil.setAttribute('id', filId); + fil.setAttribute('filterUnits', 'objectBoundingBox'); + fil.setAttribute('x', '0%'); + fil.setAttribute('y', '0%'); + fil.setAttribute('width', '100%'); + fil.setAttribute('height', '100%'); + return fil; + } + + function createAlphaToLuminanceFilter() { + var feColorMatrix = createNS('feColorMatrix'); + feColorMatrix.setAttribute('type', 'matrix'); + feColorMatrix.setAttribute('color-interpolation-filters', 'sRGB'); + feColorMatrix.setAttribute('values', '0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 1'); + return feColorMatrix; + } + + return ob; + }()); + var assetLoader = (function () { + + function formatResponse(xhr) { + if (xhr.response && typeof xhr.response === 'object') { + return xhr.response; + } else if (xhr.response && typeof xhr.response === 'string') { + return JSON.parse(xhr.response); + } else if (xhr.responseText) { + return JSON.parse(xhr.responseText); + } + } + + function loadAsset(path, callback, errorCallback) { + var response; + var xhr = new XMLHttpRequest(); + xhr.open('GET', path, true); + // set responseType after calling open or IE will break. + try { + // This crashes on Android WebView prior to KitKat + xhr.responseType = "json"; + } catch (err) { } + xhr.send(); + xhr.onreadystatechange = function () { + if (xhr.readyState == 4) { + if (xhr.status == 200) { + response = formatResponse(xhr); + callback(response); + } else { + try { + response = formatResponse(xhr); + callback(response); + } catch (err) { + if (errorCallback) { + errorCallback(err); + } + } + } + } + }; + } + return { + load: loadAsset + } + }()) + + function TextAnimatorProperty(textData, renderType, elem) { + this._isFirstFrame = true; + this._hasMaskedPath = false; + this._frameId = -1; + this._textData = textData; + this._renderType = renderType; + this._elem = elem; + this._animatorsData = createSizedArray(this._textData.a.length); + this._pathData = {}; + this._moreOptions = { + alignment: {} + }; + this.renderedLetters = []; + this.lettersChangedFlag = false; + this.initDynamicPropertyContainer(elem); + + } + + TextAnimatorProperty.prototype.searchProperties = function () { + var i, len = this._textData.a.length, animatorProps; + var getProp = PropertyFactory.getProp; + for (i = 0; i < len; i += 1) { + animatorProps = this._textData.a[i]; + this._animatorsData[i] = new TextAnimatorDataProperty(this._elem, animatorProps, this); + } + if (this._textData.p && 'm' in this._textData.p) { + this._pathData = { + f: getProp(this._elem, this._textData.p.f, 0, 0, this), + l: getProp(this._elem, this._textData.p.l, 0, 0, this), + r: this._textData.p.r, + m: this._elem.maskManager.getMaskProperty(this._textData.p.m) + }; + this._hasMaskedPath = true; + } else { + this._hasMaskedPath = false; + } + this._moreOptions.alignment = getProp(this._elem, this._textData.m.a, 1, 0, this); + }; + + TextAnimatorProperty.prototype.getMeasures = function (documentData, lettersChangedFlag) { + this.lettersChangedFlag = lettersChangedFlag; + if (!this._mdf && !this._isFirstFrame && !lettersChangedFlag && (!this._hasMaskedPath || !this._pathData.m._mdf)) { + return; + } + this._isFirstFrame = false; + var alignment = this._moreOptions.alignment.v; + var animators = this._animatorsData; + var textData = this._textData; + var matrixHelper = this.mHelper; + var renderType = this._renderType; + var renderedLettersCount = this.renderedLetters.length; + var data = this.data; + var xPos, yPos; + var i, len; + var letters = documentData.l, pathInfo, currentLength, currentPoint, segmentLength, flag, pointInd, segmentInd, prevPoint, points, segments, partialLength, totalLength, perc, tanAngle, mask; + if (this._hasMaskedPath) { + mask = this._pathData.m; + if (!this._pathData.n || this._pathData._mdf) { + var paths = mask.v; + if (this._pathData.r) { + paths = paths.reverse(); + } + // TODO: release bezier data cached from previous pathInfo: this._pathData.pi + pathInfo = { + tLength: 0, + segments: [] + }; + len = paths._length - 1; + var bezierData; + totalLength = 0; + for (i = 0; i < len; i += 1) { + bezierData = bez.buildBezierData(paths.v[i] + , paths.v[i + 1] + , [paths.o[i][0] - paths.v[i][0], paths.o[i][1] - paths.v[i][1]] + , [paths.i[i + 1][0] - paths.v[i + 1][0], paths.i[i + 1][1] - paths.v[i + 1][1]]); + pathInfo.tLength += bezierData.segmentLength; + pathInfo.segments.push(bezierData); + totalLength += bezierData.segmentLength; + } + i = len; + if (mask.v.c) { + bezierData = bez.buildBezierData(paths.v[i] + , paths.v[0] + , [paths.o[i][0] - paths.v[i][0], paths.o[i][1] - paths.v[i][1]] + , [paths.i[0][0] - paths.v[0][0], paths.i[0][1] - paths.v[0][1]]); + pathInfo.tLength += bezierData.segmentLength; + pathInfo.segments.push(bezierData); + totalLength += bezierData.segmentLength; + } + this._pathData.pi = pathInfo; + } + pathInfo = this._pathData.pi; + + currentLength = this._pathData.f.v; + segmentInd = 0; + pointInd = 1; + segmentLength = 0; + flag = true; + segments = pathInfo.segments; + if (currentLength < 0 && mask.v.c) { + if (pathInfo.tLength < Math.abs(currentLength)) { + currentLength = -Math.abs(currentLength) % pathInfo.tLength; + } + segmentInd = segments.length - 1; + points = segments[segmentInd].points; + pointInd = points.length - 1; + while (currentLength < 0) { + currentLength += points[pointInd].partialLength; + pointInd -= 1; + if (pointInd < 0) { + segmentInd -= 1; + points = segments[segmentInd].points; + pointInd = points.length - 1; + } + } + + } + points = segments[segmentInd].points; + prevPoint = points[pointInd - 1]; + currentPoint = points[pointInd]; + partialLength = currentPoint.partialLength; + } + + + len = letters.length; + xPos = 0; + yPos = 0; + var yOff = documentData.finalSize * 1.2 * 0.714; + var firstLine = true; + var animatorProps, animatorSelector; + var j, jLen; + var letterValue; + + jLen = animators.length; + var lastLetter; + + var mult, ind = -1, offf, xPathPos, yPathPos; + var initPathPos = currentLength, initSegmentInd = segmentInd, initPointInd = pointInd, currentLine = -1; + var elemOpacity; + var sc, sw, fc, k; + var lineLength = 0; + var letterSw, letterSc, letterFc, letterM = '', letterP = this.defaultPropsArray, letterO; + + // + if (documentData.j === 2 || documentData.j === 1) { + var animatorJustifyOffset = 0; + var animatorFirstCharOffset = 0; + var justifyOffsetMult = documentData.j === 2 ? -0.5 : -1; + var lastIndex = 0; + var isNewLine = true; + + for (i = 0; i < len; i += 1) { + if (letters[i].n) { + if (animatorJustifyOffset) { + animatorJustifyOffset += animatorFirstCharOffset; + } + while (lastIndex < i) { + letters[lastIndex].animatorJustifyOffset = animatorJustifyOffset; + lastIndex += 1; + } + animatorJustifyOffset = 0; + isNewLine = true; + } else { + for (j = 0; j < jLen; j += 1) { + animatorProps = animators[j].a; + if (animatorProps.t.propType) { + if (isNewLine && documentData.j === 2) { + animatorFirstCharOffset += animatorProps.t.v * justifyOffsetMult; + } + animatorSelector = animators[j].s; + mult = animatorSelector.getMult(letters[i].anIndexes[j], textData.a[j].s.totalChars); + if (mult.length) { + animatorJustifyOffset += animatorProps.t.v * mult[0] * justifyOffsetMult; + } else { + animatorJustifyOffset += animatorProps.t.v * mult * justifyOffsetMult; + } + } + } + isNewLine = false; + } + } + if (animatorJustifyOffset) { + animatorJustifyOffset += animatorFirstCharOffset; + } + while (lastIndex < i) { + letters[lastIndex].animatorJustifyOffset = animatorJustifyOffset; + lastIndex += 1; + } + } + // + + for (i = 0; i < len; i += 1) { + + matrixHelper.reset(); + elemOpacity = 1; + if (letters[i].n) { + xPos = 0; + yPos += documentData.yOffset; + yPos += firstLine ? 1 : 0; + currentLength = initPathPos; + firstLine = false; + lineLength = 0; + if (this._hasMaskedPath) { + segmentInd = initSegmentInd; + pointInd = initPointInd; + points = segments[segmentInd].points; + prevPoint = points[pointInd - 1]; + currentPoint = points[pointInd]; + partialLength = currentPoint.partialLength; + segmentLength = 0; + } + letterO = letterSw = letterFc = letterM = ''; + letterP = this.defaultPropsArray; + } else { + if (this._hasMaskedPath) { + if (currentLine !== letters[i].line) { + switch (documentData.j) { + case 1: + currentLength += totalLength - documentData.lineWidths[letters[i].line]; + break; + case 2: + currentLength += (totalLength - documentData.lineWidths[letters[i].line]) / 2; + break; + } + currentLine = letters[i].line; + } + if (ind !== letters[i].ind) { + if (letters[ind]) { + currentLength += letters[ind].extra; + } + currentLength += letters[i].an / 2; + ind = letters[i].ind; + } + currentLength += alignment[0] * letters[i].an / 200; + var animatorOffset = 0; + for (j = 0; j < jLen; j += 1) { + animatorProps = animators[j].a; + if (animatorProps.p.propType) { + animatorSelector = animators[j].s; + mult = animatorSelector.getMult(letters[i].anIndexes[j], textData.a[j].s.totalChars); + if (mult.length) { + animatorOffset += animatorProps.p.v[0] * mult[0]; + } else { + animatorOffset += animatorProps.p.v[0] * mult; + } + + } + if (animatorProps.a.propType) { + animatorSelector = animators[j].s; + mult = animatorSelector.getMult(letters[i].anIndexes[j], textData.a[j].s.totalChars); + if (mult.length) { + animatorOffset += animatorProps.a.v[0] * mult[0]; + } else { + animatorOffset += animatorProps.a.v[0] * mult; + } + + } + } + flag = true; + while (flag) { + if (segmentLength + partialLength >= currentLength + animatorOffset || !points) { + perc = (currentLength + animatorOffset - segmentLength) / currentPoint.partialLength; + xPathPos = prevPoint.point[0] + (currentPoint.point[0] - prevPoint.point[0]) * perc; + yPathPos = prevPoint.point[1] + (currentPoint.point[1] - prevPoint.point[1]) * perc; + matrixHelper.translate(-alignment[0] * letters[i].an / 200, -(alignment[1] * yOff / 100)); + flag = false; + } else if (points) { + segmentLength += currentPoint.partialLength; + pointInd += 1; + if (pointInd >= points.length) { + pointInd = 0; + segmentInd += 1; + if (!segments[segmentInd]) { + if (mask.v.c) { + pointInd = 0; + segmentInd = 0; + points = segments[segmentInd].points; + } else { + segmentLength -= currentPoint.partialLength; + points = null; + } + } else { + points = segments[segmentInd].points; + } + } + if (points) { + prevPoint = currentPoint; + currentPoint = points[pointInd]; + partialLength = currentPoint.partialLength; + } + } + } + offf = letters[i].an / 2 - letters[i].add; + matrixHelper.translate(-offf, 0, 0); + } else { + offf = letters[i].an / 2 - letters[i].add; + matrixHelper.translate(-offf, 0, 0); + + // Grouping alignment + matrixHelper.translate(-alignment[0] * letters[i].an / 200, -alignment[1] * yOff / 100, 0); + } + + lineLength += letters[i].l / 2; + for (j = 0; j < jLen; j += 1) { + animatorProps = animators[j].a; + if (animatorProps.t.propType) { + animatorSelector = animators[j].s; + mult = animatorSelector.getMult(letters[i].anIndexes[j], textData.a[j].s.totalChars); + //This condition is to prevent applying tracking to first character in each line. Might be better to use a boolean "isNewLine" + if (xPos !== 0 || documentData.j !== 0) { + if (this._hasMaskedPath) { + if (mult.length) { + currentLength += animatorProps.t.v * mult[0]; + } else { + currentLength += animatorProps.t.v * mult; + } + } else { + if (mult.length) { + xPos += animatorProps.t.v * mult[0]; + } else { + xPos += animatorProps.t.v * mult; + } + } + } + } + } + lineLength += letters[i].l / 2; + if (documentData.strokeWidthAnim) { + sw = documentData.sw || 0; + } + if (documentData.strokeColorAnim) { + if (documentData.sc) { + sc = [documentData.sc[0], documentData.sc[1], documentData.sc[2]]; + } else { + sc = [0, 0, 0]; + } + } + if (documentData.fillColorAnim && documentData.fc) { + fc = [documentData.fc[0], documentData.fc[1], documentData.fc[2]]; + } + for (j = 0; j < jLen; j += 1) { + animatorProps = animators[j].a; + if (animatorProps.a.propType) { + animatorSelector = animators[j].s; + mult = animatorSelector.getMult(letters[i].anIndexes[j], textData.a[j].s.totalChars); + + if (mult.length) { + matrixHelper.translate(-animatorProps.a.v[0] * mult[0], -animatorProps.a.v[1] * mult[1], animatorProps.a.v[2] * mult[2]); + } else { + matrixHelper.translate(-animatorProps.a.v[0] * mult, -animatorProps.a.v[1] * mult, animatorProps.a.v[2] * mult); + } + } + } + for (j = 0; j < jLen; j += 1) { + animatorProps = animators[j].a; + if (animatorProps.s.propType) { + animatorSelector = animators[j].s; + mult = animatorSelector.getMult(letters[i].anIndexes[j], textData.a[j].s.totalChars); + if (mult.length) { + matrixHelper.scale(1 + ((animatorProps.s.v[0] - 1) * mult[0]), 1 + ((animatorProps.s.v[1] - 1) * mult[1]), 1); + } else { + matrixHelper.scale(1 + ((animatorProps.s.v[0] - 1) * mult), 1 + ((animatorProps.s.v[1] - 1) * mult), 1); + } + } + } + for (j = 0; j < jLen; j += 1) { + animatorProps = animators[j].a; + animatorSelector = animators[j].s; + mult = animatorSelector.getMult(letters[i].anIndexes[j], textData.a[j].s.totalChars); + if (animatorProps.sk.propType) { + if (mult.length) { + matrixHelper.skewFromAxis(-animatorProps.sk.v * mult[0], animatorProps.sa.v * mult[1]); + } else { + matrixHelper.skewFromAxis(-animatorProps.sk.v * mult, animatorProps.sa.v * mult); + } + } + if (animatorProps.r.propType) { + if (mult.length) { + matrixHelper.rotateZ(-animatorProps.r.v * mult[2]); + } else { + matrixHelper.rotateZ(-animatorProps.r.v * mult); + } + } + if (animatorProps.ry.propType) { + + if (mult.length) { + matrixHelper.rotateY(animatorProps.ry.v * mult[1]); + } else { + matrixHelper.rotateY(animatorProps.ry.v * mult); + } + } + if (animatorProps.rx.propType) { + if (mult.length) { + matrixHelper.rotateX(animatorProps.rx.v * mult[0]); + } else { + matrixHelper.rotateX(animatorProps.rx.v * mult); + } + } + if (animatorProps.o.propType) { + if (mult.length) { + elemOpacity += ((animatorProps.o.v) * mult[0] - elemOpacity) * mult[0]; + } else { + elemOpacity += ((animatorProps.o.v) * mult - elemOpacity) * mult; + } + } + if (documentData.strokeWidthAnim && animatorProps.sw.propType) { + if (mult.length) { + sw += animatorProps.sw.v * mult[0]; + } else { + sw += animatorProps.sw.v * mult; + } + } + if (documentData.strokeColorAnim && animatorProps.sc.propType) { + for (k = 0; k < 3; k += 1) { + if (mult.length) { + sc[k] = sc[k] + (animatorProps.sc.v[k] - sc[k]) * mult[0]; + } else { + sc[k] = sc[k] + (animatorProps.sc.v[k] - sc[k]) * mult; + } + } + } + if (documentData.fillColorAnim && documentData.fc) { + if (animatorProps.fc.propType) { + for (k = 0; k < 3; k += 1) { + if (mult.length) { + fc[k] = fc[k] + (animatorProps.fc.v[k] - fc[k]) * mult[0]; + } else { + fc[k] = fc[k] + (animatorProps.fc.v[k] - fc[k]) * mult; + } + } + } + if (animatorProps.fh.propType) { + if (mult.length) { + fc = addHueToRGB(fc, animatorProps.fh.v * mult[0]); + } else { + fc = addHueToRGB(fc, animatorProps.fh.v * mult); + } + } + if (animatorProps.fs.propType) { + if (mult.length) { + fc = addSaturationToRGB(fc, animatorProps.fs.v * mult[0]); + } else { + fc = addSaturationToRGB(fc, animatorProps.fs.v * mult); + } + } + if (animatorProps.fb.propType) { + if (mult.length) { + fc = addBrightnessToRGB(fc, animatorProps.fb.v * mult[0]); + } else { + fc = addBrightnessToRGB(fc, animatorProps.fb.v * mult); + } + } + } + } + + for (j = 0; j < jLen; j += 1) { + animatorProps = animators[j].a; + + if (animatorProps.p.propType) { + animatorSelector = animators[j].s; + mult = animatorSelector.getMult(letters[i].anIndexes[j], textData.a[j].s.totalChars); + if (this._hasMaskedPath) { + if (mult.length) { + matrixHelper.translate(0, animatorProps.p.v[1] * mult[0], -animatorProps.p.v[2] * mult[1]); + } else { + matrixHelper.translate(0, animatorProps.p.v[1] * mult, -animatorProps.p.v[2] * mult); + } + } else { + if (mult.length) { + matrixHelper.translate(animatorProps.p.v[0] * mult[0], animatorProps.p.v[1] * mult[1], -animatorProps.p.v[2] * mult[2]); + } else { + matrixHelper.translate(animatorProps.p.v[0] * mult, animatorProps.p.v[1] * mult, -animatorProps.p.v[2] * mult); + + } + } + } + } + if (documentData.strokeWidthAnim) { + letterSw = sw < 0 ? 0 : sw; + } + if (documentData.strokeColorAnim) { + letterSc = 'rgb(' + Math.round(sc[0] * 255) + ',' + Math.round(sc[1] * 255) + ',' + Math.round(sc[2] * 255) + ')'; + } + if (documentData.fillColorAnim && documentData.fc) { + letterFc = 'rgb(' + Math.round(fc[0] * 255) + ',' + Math.round(fc[1] * 255) + ',' + Math.round(fc[2] * 255) + ')'; + } + + if (this._hasMaskedPath) { + matrixHelper.translate(0, -documentData.ls); + + matrixHelper.translate(0, alignment[1] * yOff / 100 + yPos, 0); + if (textData.p.p) { + tanAngle = (currentPoint.point[1] - prevPoint.point[1]) / (currentPoint.point[0] - prevPoint.point[0]); + var rot = Math.atan(tanAngle) * 180 / Math.PI; + if (currentPoint.point[0] < prevPoint.point[0]) { + rot += 180; + } + matrixHelper.rotate(-rot * Math.PI / 180); + } + matrixHelper.translate(xPathPos, yPathPos, 0); + currentLength -= alignment[0] * letters[i].an / 200; + if (letters[i + 1] && ind !== letters[i + 1].ind) { + currentLength += letters[i].an / 2; + currentLength += documentData.tr / 1000 * documentData.finalSize; + } + } else { + + matrixHelper.translate(xPos, yPos, 0); + + if (documentData.ps) { + //matrixHelper.translate(documentData.ps[0],documentData.ps[1],0); + matrixHelper.translate(documentData.ps[0], documentData.ps[1] + documentData.ascent, 0); + } + switch (documentData.j) { + case 1: + matrixHelper.translate(letters[i].animatorJustifyOffset + documentData.justifyOffset + (documentData.boxWidth - documentData.lineWidths[letters[i].line]), 0, 0); + break; + case 2: + matrixHelper.translate(letters[i].animatorJustifyOffset + documentData.justifyOffset + (documentData.boxWidth - documentData.lineWidths[letters[i].line]) / 2, 0, 0); + break; + } + matrixHelper.translate(0, -documentData.ls); + matrixHelper.translate(offf, 0, 0); + matrixHelper.translate(alignment[0] * letters[i].an / 200, alignment[1] * yOff / 100, 0); + xPos += letters[i].l + documentData.tr / 1000 * documentData.finalSize; + } + if (renderType === 'html') { + letterM = matrixHelper.toCSS(); + } else if (renderType === 'svg') { + letterM = matrixHelper.to2dCSS(); + } else { + letterP = [matrixHelper.props[0], matrixHelper.props[1], matrixHelper.props[2], matrixHelper.props[3], matrixHelper.props[4], matrixHelper.props[5], matrixHelper.props[6], matrixHelper.props[7], matrixHelper.props[8], matrixHelper.props[9], matrixHelper.props[10], matrixHelper.props[11], matrixHelper.props[12], matrixHelper.props[13], matrixHelper.props[14], matrixHelper.props[15]]; + } + letterO = elemOpacity; + } + + if (renderedLettersCount <= i) { + letterValue = new LetterProps(letterO, letterSw, letterSc, letterFc, letterM, letterP); + this.renderedLetters.push(letterValue); + renderedLettersCount += 1; + this.lettersChangedFlag = true; + } else { + letterValue = this.renderedLetters[i]; + this.lettersChangedFlag = letterValue.update(letterO, letterSw, letterSc, letterFc, letterM, letterP) || this.lettersChangedFlag; + } + } + }; + + TextAnimatorProperty.prototype.getValue = function () { + if (this._elem.globalData.frameId === this._frameId) { + return; + } + this._frameId = this._elem.globalData.frameId; + this.iterateDynamicProperties(); + }; + + TextAnimatorProperty.prototype.mHelper = new Matrix(); + TextAnimatorProperty.prototype.defaultPropsArray = []; + extendPrototype([DynamicPropertyContainer], TextAnimatorProperty); + function TextAnimatorDataProperty(elem, animatorProps, container) { + var defaultData = { propType: false }; + var getProp = PropertyFactory.getProp; + var textAnimator_animatables = animatorProps.a; + this.a = { + r: textAnimator_animatables.r ? getProp(elem, textAnimator_animatables.r, 0, degToRads, container) : defaultData, + rx: textAnimator_animatables.rx ? getProp(elem, textAnimator_animatables.rx, 0, degToRads, container) : defaultData, + ry: textAnimator_animatables.ry ? getProp(elem, textAnimator_animatables.ry, 0, degToRads, container) : defaultData, + sk: textAnimator_animatables.sk ? getProp(elem, textAnimator_animatables.sk, 0, degToRads, container) : defaultData, + sa: textAnimator_animatables.sa ? getProp(elem, textAnimator_animatables.sa, 0, degToRads, container) : defaultData, + s: textAnimator_animatables.s ? getProp(elem, textAnimator_animatables.s, 1, 0.01, container) : defaultData, + a: textAnimator_animatables.a ? getProp(elem, textAnimator_animatables.a, 1, 0, container) : defaultData, + o: textAnimator_animatables.o ? getProp(elem, textAnimator_animatables.o, 0, 0.01, container) : defaultData, + p: textAnimator_animatables.p ? getProp(elem, textAnimator_animatables.p, 1, 0, container) : defaultData, + sw: textAnimator_animatables.sw ? getProp(elem, textAnimator_animatables.sw, 0, 0, container) : defaultData, + sc: textAnimator_animatables.sc ? getProp(elem, textAnimator_animatables.sc, 1, 0, container) : defaultData, + fc: textAnimator_animatables.fc ? getProp(elem, textAnimator_animatables.fc, 1, 0, container) : defaultData, + fh: textAnimator_animatables.fh ? getProp(elem, textAnimator_animatables.fh, 0, 0, container) : defaultData, + fs: textAnimator_animatables.fs ? getProp(elem, textAnimator_animatables.fs, 0, 0.01, container) : defaultData, + fb: textAnimator_animatables.fb ? getProp(elem, textAnimator_animatables.fb, 0, 0.01, container) : defaultData, + t: textAnimator_animatables.t ? getProp(elem, textAnimator_animatables.t, 0, 0, container) : defaultData + }; + + this.s = TextSelectorProp.getTextSelectorProp(elem, animatorProps.s, container); + this.s.t = animatorProps.s.t; + } + function LetterProps(o, sw, sc, fc, m, p) { + this.o = o; + this.sw = sw; + this.sc = sc; + this.fc = fc; + this.m = m; + this.p = p; + this._mdf = { + o: true, + sw: !!sw, + sc: !!sc, + fc: !!fc, + m: true, + p: true + }; + } + + LetterProps.prototype.update = function (o, sw, sc, fc, m, p) { + this._mdf.o = false; + this._mdf.sw = false; + this._mdf.sc = false; + this._mdf.fc = false; + this._mdf.m = false; + this._mdf.p = false; + var updated = false; + + if (this.o !== o) { + this.o = o; + this._mdf.o = true; + updated = true; + } + if (this.sw !== sw) { + this.sw = sw; + this._mdf.sw = true; + updated = true; + } + if (this.sc !== sc) { + this.sc = sc; + this._mdf.sc = true; + updated = true; + } + if (this.fc !== fc) { + this.fc = fc; + this._mdf.fc = true; + updated = true; + } + if (this.m !== m) { + this.m = m; + this._mdf.m = true; + updated = true; + } + if (p.length && (this.p[0] !== p[0] || this.p[1] !== p[1] || this.p[4] !== p[4] || this.p[5] !== p[5] || this.p[12] !== p[12] || this.p[13] !== p[13])) { + this.p = p; + this._mdf.p = true; + updated = true; + } + return updated; + }; + function TextProperty(elem, data) { + this._frameId = initialDefaultFrame; + this.pv = ''; + this.v = ''; + this.kf = false; + this._isFirstFrame = true; + this._mdf = false; + this.data = data; + this.elem = elem; + this.comp = this.elem.comp; + this.keysIndex = 0; + this.canResize = false; + this.minimumFontSize = 1; + this.effectsSequence = []; + this.currentData = { + ascent: 0, + boxWidth: this.defaultBoxWidth, + f: '', + fStyle: '', + fWeight: '', + fc: '', + j: '', + justifyOffset: '', + l: [], + lh: 0, + lineWidths: [], + ls: '', + of: '', + s: '', + sc: '', + sw: 0, + t: 0, + tr: 0, + sz: 0, + ps: null, + fillColorAnim: false, + strokeColorAnim: false, + strokeWidthAnim: false, + yOffset: 0, + finalSize: 0, + finalText: [], + finalLineHeight: 0, + __complete: false + + }; + this.copyData(this.currentData, this.data.d.k[0].s); + + if (!this.searchProperty()) { + this.completeTextData(this.currentData); + } + } + + TextProperty.prototype.defaultBoxWidth = [0, 0]; + + TextProperty.prototype.copyData = function (obj, data) { + for (var s in data) { + if (data.hasOwnProperty(s)) { + obj[s] = data[s]; + } + } + return obj; + } + + TextProperty.prototype.setCurrentData = function (data) { + if (!data.__complete) { + this.completeTextData(data); + } + this.currentData = data; + this.currentData.boxWidth = this.currentData.boxWidth || this.defaultBoxWidth; + this._mdf = true; + }; + + TextProperty.prototype.searchProperty = function () { + return this.searchKeyframes(); + }; + + TextProperty.prototype.searchKeyframes = function () { + this.kf = this.data.d.k.length > 1; + if (this.kf) { + this.addEffect(this.getKeyframeValue.bind(this)); + } + return this.kf; + } + + TextProperty.prototype.addEffect = function (effectFunction) { + this.effectsSequence.push(effectFunction); + this.elem.addDynamicProperty(this); + }; + + TextProperty.prototype.getValue = function (_finalValue) { + if ((this.elem.globalData.frameId === this.frameId || !this.effectsSequence.length) && !_finalValue) { + return; + } + this.currentData.t = this.data.d.k[this.keysIndex].s.t; + var currentValue = this.currentData; + var currentIndex = this.keysIndex; + if (this.lock) { + this.setCurrentData(this.currentData); + return; + } + this.lock = true; + this._mdf = false; + var multipliedValue; + var i, len = this.effectsSequence.length; + var finalValue = _finalValue || this.data.d.k[this.keysIndex].s; + for (i = 0; i < len; i += 1) { + //Checking if index changed to prevent creating a new object every time the expression updates. + if (currentIndex !== this.keysIndex) { + finalValue = this.effectsSequence[i](finalValue, finalValue.t); + } else { + finalValue = this.effectsSequence[i](this.currentData, finalValue.t); + } + } + if (currentValue !== finalValue) { + this.setCurrentData(finalValue); + } + this.pv = this.v = this.currentData; + this.lock = false; + this.frameId = this.elem.globalData.frameId; + } + + TextProperty.prototype.getKeyframeValue = function () { + var textKeys = this.data.d.k, textDocumentData; + var frameNum = this.elem.comp.renderedFrame; + var i = 0, len = textKeys.length; + while (i <= len - 1) { + textDocumentData = textKeys[i].s; + if (i === len - 1 || textKeys[i + 1].t > frameNum) { + break; + } + i += 1; + } + if (this.keysIndex !== i) { + this.keysIndex = i; + } + return this.data.d.k[this.keysIndex].s; + }; + + TextProperty.prototype.buildFinalText = function (text) { + var combinedCharacters = FontManager.getCombinedCharacterCodes(); + var charactersArray = []; + var i = 0, len = text.length; + var charCode; + while (i < len) { + charCode = text.charCodeAt(i); + if (combinedCharacters.indexOf(charCode) !== -1) { + charactersArray[charactersArray.length - 1] += text.charAt(i); + } else { + if (charCode >= 0xD800 && charCode <= 0xDBFF) { + charCode = text.charCodeAt(i + 1); + if (charCode >= 0xDC00 && charCode <= 0xDFFF) { + charactersArray.push(text.substr(i, 2)); + ++i; + } else { + charactersArray.push(text.charAt(i)); + } + } else { + charactersArray.push(text.charAt(i)); + } + } + i += 1; + } + return charactersArray; + } + + TextProperty.prototype.completeTextData = function (documentData) { + documentData.__complete = true; + var fontManager = this.elem.globalData.fontManager; + var data = this.data; + var letters = []; + var i, len; + var newLineFlag, index = 0, val; + var anchorGrouping = data.m.g; + var currentSize = 0, currentPos = 0, currentLine = 0, lineWidths = []; + var lineWidth = 0; + var maxLineWidth = 0; + var j, jLen; + var fontData = fontManager.getFontByName(documentData.f); + var charData, cLength = 0; + var styles = fontData.fStyle ? fontData.fStyle.split(' ') : []; + + var fWeight = 'normal', fStyle = 'normal'; + len = styles.length; + var styleName; + for (i = 0; i < len; i += 1) { + styleName = styles[i].toLowerCase(); + switch (styleName) { + case 'italic': + fStyle = 'italic'; + break; + case 'bold': + fWeight = '700'; + break; + case 'black': + fWeight = '900'; + break; + case 'medium': + fWeight = '500'; + break; + case 'regular': + case 'normal': + fWeight = '400'; + break; + case 'light': + case 'thin': + fWeight = '200'; + break; + } + } + documentData.fWeight = fontData.fWeight || fWeight; + documentData.fStyle = fStyle; + documentData.finalSize = documentData.s; + documentData.finalText = this.buildFinalText(documentData.t); + len = documentData.finalText.length; + documentData.finalLineHeight = documentData.lh; + var trackingOffset = documentData.tr / 1000 * documentData.finalSize; + var charCode; + if (documentData.sz) { + var flag = true; + var boxWidth = documentData.sz[0]; + var boxHeight = documentData.sz[1]; + var currentHeight, finalText; + while (flag) { + finalText = this.buildFinalText(documentData.t); + currentHeight = 0; + lineWidth = 0; + len = finalText.length; + trackingOffset = documentData.tr / 1000 * documentData.finalSize; + var lastSpaceIndex = -1; + for (i = 0; i < len; i += 1) { + charCode = finalText[i].charCodeAt(0); + newLineFlag = false; + if (finalText[i] === ' ') { + lastSpaceIndex = i; + } else if (charCode === 13 || charCode === 3) { + lineWidth = 0; + newLineFlag = true; + currentHeight += documentData.finalLineHeight || documentData.finalSize * 1.2; + } + if (fontManager.chars) { + charData = fontManager.getCharData(finalText[i], fontData.fStyle, fontData.fFamily); + cLength = newLineFlag ? 0 : charData.w * documentData.finalSize / 100; + } else { + //tCanvasHelper.font = documentData.s + 'px '+ fontData.fFamily; + cLength = fontManager.measureText(finalText[i], documentData.f, documentData.finalSize); + } + if (lineWidth + cLength > boxWidth && finalText[i] !== ' ') { + if (lastSpaceIndex === -1) { + len += 1; + } else { + i = lastSpaceIndex; + } + currentHeight += documentData.finalLineHeight || documentData.finalSize * 1.2; + finalText.splice(i, lastSpaceIndex === i ? 1 : 0, "\r"); + //finalText = finalText.substr(0,i) + "\r" + finalText.substr(i === lastSpaceIndex ? i + 1 : i); + lastSpaceIndex = -1; + lineWidth = 0; + } else { + lineWidth += cLength; + lineWidth += trackingOffset; + } + } + currentHeight += fontData.ascent * documentData.finalSize / 100; + if (this.canResize && documentData.finalSize > this.minimumFontSize && boxHeight < currentHeight) { + documentData.finalSize -= 1; + documentData.finalLineHeight = documentData.finalSize * documentData.lh / documentData.s; + } else { + documentData.finalText = finalText; + len = documentData.finalText.length; + flag = false; + } + } + + } + lineWidth = - trackingOffset; + cLength = 0; + var uncollapsedSpaces = 0; + var currentChar; + for (i = 0; i < len; i += 1) { + newLineFlag = false; + currentChar = documentData.finalText[i]; + charCode = currentChar.charCodeAt(0); + if (charCode === 13 || charCode === 3) { + uncollapsedSpaces = 0; + lineWidths.push(lineWidth); + maxLineWidth = lineWidth > maxLineWidth ? lineWidth : maxLineWidth; + lineWidth = - 2 * trackingOffset; + val = ''; + newLineFlag = true; + currentLine += 1; + } else { + val = currentChar; + } + if (fontManager.chars) { + charData = fontManager.getCharData(currentChar, fontData.fStyle, fontManager.getFontByName(documentData.f).fFamily); + cLength = newLineFlag ? 0 : charData.w * documentData.finalSize / 100; + } else { + //var charWidth = fontManager.measureText(val, documentData.f, documentData.finalSize); + //tCanvasHelper.font = documentData.finalSize + 'px '+ fontManager.getFontByName(documentData.f).fFamily; + cLength = fontManager.measureText(val, documentData.f, documentData.finalSize); + } + + // + if (currentChar === ' ') { + uncollapsedSpaces += cLength + trackingOffset; + } else { + lineWidth += cLength + trackingOffset + uncollapsedSpaces; + uncollapsedSpaces = 0; + } + letters.push({ l: cLength, an: cLength, add: currentSize, n: newLineFlag, anIndexes: [], val: val, line: currentLine, animatorJustifyOffset: 0 }); + if (anchorGrouping == 2) { + currentSize += cLength; + if (val === '' || val === ' ' || i === len - 1) { + if (val === '' || val === ' ') { + currentSize -= cLength; + } + while (currentPos <= i) { + letters[currentPos].an = currentSize; + letters[currentPos].ind = index; + letters[currentPos].extra = cLength; + currentPos += 1; + } + index += 1; + currentSize = 0; + } + } else if (anchorGrouping == 3) { + currentSize += cLength; + if (val === '' || i === len - 1) { + if (val === '') { + currentSize -= cLength; + } + while (currentPos <= i) { + letters[currentPos].an = currentSize; + letters[currentPos].ind = index; + letters[currentPos].extra = cLength; + currentPos += 1; + } + currentSize = 0; + index += 1; + } + } else { + letters[index].ind = index; + letters[index].extra = 0; + index += 1; + } + } + documentData.l = letters; + maxLineWidth = lineWidth > maxLineWidth ? lineWidth : maxLineWidth; + lineWidths.push(lineWidth); + if (documentData.sz) { + documentData.boxWidth = documentData.sz[0]; + documentData.justifyOffset = 0; + } else { + documentData.boxWidth = maxLineWidth; + switch (documentData.j) { + case 1: + documentData.justifyOffset = - documentData.boxWidth; + break; + case 2: + documentData.justifyOffset = - documentData.boxWidth / 2; + break; + default: + documentData.justifyOffset = 0; + } + } + documentData.lineWidths = lineWidths; + + var animators = data.a, animatorData, letterData; + jLen = animators.length; + var based, ind, indexes = []; + for (j = 0; j < jLen; j += 1) { + animatorData = animators[j]; + if (animatorData.a.sc) { + documentData.strokeColorAnim = true; + } + if (animatorData.a.sw) { + documentData.strokeWidthAnim = true; + } + if (animatorData.a.fc || animatorData.a.fh || animatorData.a.fs || animatorData.a.fb) { + documentData.fillColorAnim = true; + } + ind = 0; + based = animatorData.s.b; + for (i = 0; i < len; i += 1) { + letterData = letters[i]; + letterData.anIndexes[j] = ind; + if ((based == 1 && letterData.val !== '') || (based == 2 && letterData.val !== '' && letterData.val !== ' ') || (based == 3 && (letterData.n || letterData.val == ' ' || i == len - 1)) || (based == 4 && (letterData.n || i == len - 1))) { + if (animatorData.s.rn === 1) { + indexes.push(ind); + } + ind += 1; + } + } + data.a[j].s.totalChars = ind; + var currentInd = -1, newInd; + if (animatorData.s.rn === 1) { + for (i = 0; i < len; i += 1) { + letterData = letters[i]; + if (currentInd != letterData.anIndexes[j]) { + currentInd = letterData.anIndexes[j]; + newInd = indexes.splice(Math.floor(Math.random() * indexes.length), 1)[0]; + } + letterData.anIndexes[j] = newInd; + } + } + } + documentData.yOffset = documentData.finalLineHeight || documentData.finalSize * 1.2; + documentData.ls = documentData.ls || 0; + documentData.ascent = fontData.ascent * documentData.finalSize / 100; + }; + + TextProperty.prototype.updateDocumentData = function (newData, index) { + index = index === undefined ? this.keysIndex : index; + var dData = this.copyData({}, this.data.d.k[index].s); + dData = this.copyData(dData, newData); + this.data.d.k[index].s = dData; + this.recalculate(index); + this.elem.addDynamicProperty(this); + }; + + TextProperty.prototype.recalculate = function (index) { + var dData = this.data.d.k[index].s; + dData.__complete = false; + this.keysIndex = 0; + this._isFirstFrame = true; + this.getValue(dData); + } + + TextProperty.prototype.canResizeFont = function (_canResize) { + this.canResize = _canResize; + this.recalculate(this.keysIndex); + this.elem.addDynamicProperty(this); + }; + + TextProperty.prototype.setMinimumFontSize = function (_fontValue) { + this.minimumFontSize = Math.floor(_fontValue) || 1; + this.recalculate(this.keysIndex); + this.elem.addDynamicProperty(this); + }; + + var TextSelectorProp = (function () { + var max = Math.max; + var min = Math.min; + var floor = Math.floor; + + function TextSelectorProp(elem, data) { + this._currentTextLength = -1; + this.k = false; + this.data = data; + this.elem = elem; + this.comp = elem.comp; + this.finalS = 0; + this.finalE = 0; + this.initDynamicPropertyContainer(elem); + this.s = PropertyFactory.getProp(elem, data.s || { k: 0 }, 0, 0, this); + if ('e' in data) { + this.e = PropertyFactory.getProp(elem, data.e, 0, 0, this); + } else { + this.e = { v: 100 }; + } + this.o = PropertyFactory.getProp(elem, data.o || { k: 0 }, 0, 0, this); + this.xe = PropertyFactory.getProp(elem, data.xe || { k: 0 }, 0, 0, this); + this.ne = PropertyFactory.getProp(elem, data.ne || { k: 0 }, 0, 0, this); + this.a = PropertyFactory.getProp(elem, data.a, 0, 0.01, this); + if (!this.dynamicProperties.length) { + this.getValue(); + } + } + + TextSelectorProp.prototype = { + getMult: function (ind) { + if (this._currentTextLength !== this.elem.textProperty.currentData.l.length) { + this.getValue(); + } + //var easer = bez.getEasingCurve(this.ne.v/100,0,1-this.xe.v/100,1); + var x1 = 0; + var y1 = 0; + var x2 = 1; + var y2 = 1; + if (this.ne.v > 0) { + x1 = this.ne.v / 100.0; + } + else { + y1 = -this.ne.v / 100.0; + } + if (this.xe.v > 0) { + x2 = 1.0 - this.xe.v / 100.0; + } + else { + y2 = 1.0 + this.xe.v / 100.0; + } + var easer = BezierFactory.getBezierEasing(x1, y1, x2, y2).get; + + var mult = 0; + var s = this.finalS; + var e = this.finalE; + var type = this.data.sh; + if (type === 2) { + if (e === s) { + mult = ind >= e ? 1 : 0; + } else { + mult = max(0, min(0.5 / (e - s) + (ind - s) / (e - s), 1)); + } + mult = easer(mult); + } else if (type === 3) { + if (e === s) { + mult = ind >= e ? 0 : 1; + } else { + mult = 1 - max(0, min(0.5 / (e - s) + (ind - s) / (e - s), 1)); + } + + mult = easer(mult); + } else if (type === 4) { + if (e === s) { + mult = 0; + } else { + mult = max(0, min(0.5 / (e - s) + (ind - s) / (e - s), 1)); + if (mult < 0.5) { + mult *= 2; + } else { + mult = 1 - 2 * (mult - 0.5); + } + } + mult = easer(mult); + } else if (type === 5) { + if (e === s) { + mult = 0; + } else { + var tot = e - s; + /*ind += 0.5; + mult = -4/(tot*tot)*(ind*ind)+(4/tot)*ind;*/ + ind = min(max(0, ind + 0.5 - s), e - s); + var x = -tot / 2 + ind; + var a = tot / 2; + mult = Math.sqrt(1 - (x * x) / (a * a)); + } + mult = easer(mult); + } else if (type === 6) { + if (e === s) { + mult = 0; + } else { + ind = min(max(0, ind + 0.5 - s), e - s); + mult = (1 + (Math.cos((Math.PI + Math.PI * 2 * (ind) / (e - s))))) / 2; + } + mult = easer(mult); + } else { + if (ind >= floor(s)) { + if (ind - s < 0) { + mult = max(0, min(min(e, 1) - (s - ind), 1)); + } else { + mult = max(0, min(e - ind, 1)); + } + } + mult = easer(mult); + } + return mult * this.a.v; + }, + getValue: function (newCharsFlag) { + this.iterateDynamicProperties(); + this._mdf = newCharsFlag || this._mdf; + this._currentTextLength = this.elem.textProperty.currentData.l.length || 0; + if (newCharsFlag && this.data.r === 2) { + this.e.v = this._currentTextLength; + } + var divisor = this.data.r === 2 ? 1 : 100 / this.data.totalChars; + var o = this.o.v / divisor; + var s = this.s.v / divisor + o; + var e = (this.e.v / divisor) + o; + if (s > e) { + var _s = s; + s = e; + e = _s; + } + this.finalS = s; + this.finalE = e; + } + } + extendPrototype([DynamicPropertyContainer], TextSelectorProp); + + function getTextSelectorProp(elem, data, arr) { + return new TextSelectorProp(elem, data, arr); + } + + return { + getTextSelectorProp: getTextSelectorProp + }; + }()); + + + var pool_factory = (function () { + return function (initialLength, _create, _release, _clone) { + + var _length = 0; + var _maxLength = initialLength; + var pool = createSizedArray(_maxLength); + + var ob = { + newElement: newElement, + release: release + }; + + function newElement() { + var element; + if (_length) { + _length -= 1; + element = pool[_length]; + } else { + element = _create(); + } + return element; + } + + function release(element) { + if (_length === _maxLength) { + pool = pooling.double(pool); + _maxLength = _maxLength * 2; + } + if (_release) { + _release(element); + } + pool[_length] = element; + _length += 1; + } + + function clone() { + var clonedElement = newElement(); + return _clone(clonedElement); + } + + return ob; + }; + }()); + + var pooling = (function () { + + function double(arr) { + return arr.concat(createSizedArray(arr.length)); + } + + return { + double: double + }; + }()); + var point_pool = (function () { + + function create() { + return createTypedArray('float32', 2); + } + return pool_factory(8, create); + }()); + var shape_pool = (function () { + + function create() { + return new ShapePath(); + } + + function release(shapePath) { + var len = shapePath._length, i; + for (i = 0; i < len; i += 1) { + point_pool.release(shapePath.v[i]); + point_pool.release(shapePath.i[i]); + point_pool.release(shapePath.o[i]); + shapePath.v[i] = null; + shapePath.i[i] = null; + shapePath.o[i] = null; + } + shapePath._length = 0; + shapePath.c = false; + } + + function clone(shape) { + var cloned = factory.newElement(); + var i, len = shape._length === undefined ? shape.v.length : shape._length; + cloned.setLength(len); + cloned.c = shape.c; + var pt; + + for (i = 0; i < len; i += 1) { + cloned.setTripleAt(shape.v[i][0], shape.v[i][1], shape.o[i][0], shape.o[i][1], shape.i[i][0], shape.i[i][1], i); + } + return cloned; + } + + var factory = pool_factory(4, create, release); + factory.clone = clone; + + return factory; + }()); + var shapeCollection_pool = (function () { + var ob = { + newShapeCollection: newShapeCollection, + release: release + }; + + var _length = 0; + var _maxLength = 4; + var pool = createSizedArray(_maxLength); + + function newShapeCollection() { + var shapeCollection; + if (_length) { + _length -= 1; + shapeCollection = pool[_length]; + } else { + shapeCollection = new ShapeCollection(); + } + return shapeCollection; + } + + function release(shapeCollection) { + var i, len = shapeCollection._length; + for (i = 0; i < len; i += 1) { + shape_pool.release(shapeCollection.shapes[i]); + } + shapeCollection._length = 0; + + if (_length === _maxLength) { + pool = pooling.double(pool); + _maxLength = _maxLength * 2; + } + pool[_length] = shapeCollection; + _length += 1; + } + + return ob; + }()); + var segments_length_pool = (function () { + + function create() { + return { + lengths: [], + totalLength: 0 + }; + } + + function release(element) { + var i, len = element.lengths.length; + for (i = 0; i < len; i += 1) { + bezier_length_pool.release(element.lengths[i]); + } + element.lengths.length = 0; + } + + return pool_factory(8, create, release); + }()); + var bezier_length_pool = (function () { + + function create() { + return { + addedLength: 0, + percents: createTypedArray('float32', defaultCurveSegments), + lengths: createTypedArray('float32', defaultCurveSegments), + }; + } + return pool_factory(8, create); + }()); + function BaseRenderer() { } + BaseRenderer.prototype.checkLayers = function (num) { + var i, len = this.layers.length, data; + this.completeLayers = true; + for (i = len - 1; i >= 0; i--) { + if (!this.elements[i]) { + data = this.layers[i]; + if (data.ip - data.st <= (num - this.layers[i].st) && data.op - data.st > (num - this.layers[i].st)) { + this.buildItem(i); + } + } + this.completeLayers = this.elements[i] ? this.completeLayers : false; + } + this.checkPendingElements(); + }; + + BaseRenderer.prototype.createItem = function (layer) { + switch (layer.ty) { + case 2: + return this.createImage(layer); + case 0: + return this.createComp(layer); + case 1: + return this.createSolid(layer); + case 3: + return this.createNull(layer); + case 4: + return this.createShape(layer); + case 5: + return this.createText(layer); + case 13: + return this.createCamera(layer); + } + return this.createNull(layer); + }; + + BaseRenderer.prototype.createCamera = function () { + throw new Error('You\'re using a 3d camera. Try the html renderer.'); + }; + + BaseRenderer.prototype.buildAllItems = function () { + var i, len = this.layers.length; + for (i = 0; i < len; i += 1) { + this.buildItem(i); + } + this.checkPendingElements(); + }; + + BaseRenderer.prototype.includeLayers = function (newLayers) { + this.completeLayers = false; + var i, len = newLayers.length; + var j, jLen = this.layers.length; + for (i = 0; i < len; i += 1) { + j = 0; + while (j < jLen) { + if (this.layers[j].id == newLayers[i].id) { + this.layers[j] = newLayers[i]; + break; + } + j += 1; + } + } + }; + + BaseRenderer.prototype.setProjectInterface = function (pInterface) { + this.globalData.projectInterface = pInterface; + }; + + BaseRenderer.prototype.initItems = function () { + if (!this.globalData.progressiveLoad) { + this.buildAllItems(); + } + }; + BaseRenderer.prototype.buildElementParenting = function (element, parentName, hierarchy) { + var elements = this.elements; + var layers = this.layers; + var i = 0, len = layers.length; + while (i < len) { + if (layers[i].ind == parentName) { + if (!elements[i] || elements[i] === true) { + this.buildItem(i); + this.addPendingElement(element); + } else { + hierarchy.push(elements[i]); + elements[i].setAsParent(); + if (layers[i].parent !== undefined) { + this.buildElementParenting(element, layers[i].parent, hierarchy); + } else { + element.setHierarchy(hierarchy); + } + } + } + i += 1; + } + }; + + BaseRenderer.prototype.addPendingElement = function (element) { + this.pendingElements.push(element); + }; + + BaseRenderer.prototype.searchExtraCompositions = function (assets) { + var i, len = assets.length; + for (i = 0; i < len; i += 1) { + if (assets[i].xt) { + var comp = this.createComp(assets[i]); + comp.initExpressions(); + this.globalData.projectInterface.registerComposition(comp); + } + } + }; + + BaseRenderer.prototype.setupGlobalData = function (animData, fontsContainer) { + this.globalData.fontManager = new FontManager(); + this.globalData.fontManager.addChars(animData.chars); + this.globalData.fontManager.addFonts(animData.fonts, fontsContainer); + this.globalData.getAssetData = this.animationItem.getAssetData.bind(this.animationItem); + this.globalData.getAssetsPath = this.animationItem.getAssetsPath.bind(this.animationItem); + this.globalData.imageLoader = this.animationItem.imagePreloader; + this.globalData.frameId = 0; + this.globalData.frameRate = animData.fr; + this.globalData.nm = animData.nm; + this.globalData.compSize = { + w: animData.w, + h: animData.h + } + } + function SVGRenderer(animationItem, config) { + this.animationItem = animationItem; + this.layers = null; + this.renderedFrame = -1; + this.svgElement = createNS('svg'); + var ariaLabel = ''; + if (config && config.title) { + var titleElement = createNS('title'); + var titleId = createElementID(); + titleElement.setAttribute('id', titleId); + titleElement.textContent = config.title; + this.svgElement.appendChild(titleElement); + ariaLabel += titleId; + } + if (config && config.description) { + var descElement = createNS('desc'); + var descId = createElementID(); + descElement.setAttribute('id', descId); + descElement.textContent = config.description; + this.svgElement.appendChild(descElement); + ariaLabel += ' ' + descId; + } + if (ariaLabel) { + this.svgElement.setAttribute('aria-labelledby', ariaLabel) + } + var defs = createNS('defs'); + this.svgElement.appendChild(defs); + var maskElement = createNS('g'); + this.svgElement.appendChild(maskElement); + this.layerElement = maskElement; + this.renderConfig = { + preserveAspectRatio: (config && config.preserveAspectRatio) || 'xMidYMid meet', + imagePreserveAspectRatio: (config && config.imagePreserveAspectRatio) || 'xMidYMid slice', + progressiveLoad: (config && config.progressiveLoad) || false, + hideOnTransparent: (config && config.hideOnTransparent === false) ? false : true, + viewBoxOnly: (config && config.viewBoxOnly) || false, + viewBoxSize: (config && config.viewBoxSize) || false, + className: (config && config.className) || '', + id: (config && config.id) || '', + focusable: config && config.focusable, + filterSize: { + width: config && config.filterSize && config.filterSize.width || '100%', + height: config && config.filterSize && config.filterSize.height || '100%', + x: config && config.filterSize && config.filterSize.x || '0%', + y: config && config.filterSize && config.filterSize.y || '0%', + } + }; + + this.globalData = { + _mdf: false, + frameNum: -1, + defs: defs, + renderConfig: this.renderConfig + }; + this.elements = []; + this.pendingElements = []; + this.destroyed = false; + this.rendererType = 'svg'; + + } + + extendPrototype([BaseRenderer], SVGRenderer); + + SVGRenderer.prototype.createNull = function (data) { + return new NullElement(data, this.globalData, this); + }; + + SVGRenderer.prototype.createShape = function (data) { + return new SVGShapeElement(data, this.globalData, this); + }; + + SVGRenderer.prototype.createText = function (data) { + return new SVGTextElement(data, this.globalData, this); + + }; + + SVGRenderer.prototype.createImage = function (data) { + return new IImageElement(data, this.globalData, this); + }; + + SVGRenderer.prototype.createComp = function (data) { + return new SVGCompElement(data, this.globalData, this); + + }; + + SVGRenderer.prototype.createSolid = function (data) { + return new ISolidElement(data, this.globalData, this); + }; + + SVGRenderer.prototype.configAnimation = function (animData) { + this.svgElement.setAttribute('xmlns', 'http://www.w3.org/2000/svg'); + if (this.renderConfig.viewBoxSize) { + this.svgElement.setAttribute('viewBox', this.renderConfig.viewBoxSize); + } else { + this.svgElement.setAttribute('viewBox', '0 0 ' + animData.w + ' ' + animData.h); + } + + if (!this.renderConfig.viewBoxOnly) { + this.svgElement.setAttribute('width', animData.w); + this.svgElement.setAttribute('height', animData.h); + this.svgElement.style.width = '100%'; + this.svgElement.style.height = '100%'; + this.svgElement.style.transform = 'translate3d(0,0,0)'; + } + if (this.renderConfig.className) { + this.svgElement.setAttribute('class', this.renderConfig.className); + } + if (this.renderConfig.id) { + this.svgElement.setAttribute('id', this.renderConfig.id); + } + if (this.renderConfig.focusable !== undefined) { + this.svgElement.setAttribute('focusable', this.renderConfig.focusable); + } + this.svgElement.setAttribute('preserveAspectRatio', this.renderConfig.preserveAspectRatio); + //this.layerElement.style.transform = 'translate3d(0,0,0)'; + //this.layerElement.style.transformOrigin = this.layerElement.style.mozTransformOrigin = this.layerElement.style.webkitTransformOrigin = this.layerElement.style['-webkit-transform'] = "0px 0px 0px"; + this.animationItem.wrapper.appendChild(this.svgElement); + //Mask animation + var defs = this.globalData.defs; + + this.setupGlobalData(animData, defs); + this.globalData.progressiveLoad = this.renderConfig.progressiveLoad; + this.data = animData; + + var maskElement = createNS('clipPath'); + var rect = createNS('rect'); + rect.setAttribute('width', animData.w); + rect.setAttribute('height', animData.h); + rect.setAttribute('x', 0); + rect.setAttribute('y', 0); + var maskId = createElementID(); + maskElement.setAttribute('id', maskId); + maskElement.appendChild(rect); + this.layerElement.setAttribute("clip-path", "url(" + locationHref + "#" + maskId + ")"); + + defs.appendChild(maskElement); + this.layers = animData.layers; + this.elements = createSizedArray(animData.layers.length); + }; + + + SVGRenderer.prototype.destroy = function () { + this.animationItem.wrapper.innerHTML = ''; + this.layerElement = null; + this.globalData.defs = null; + var i, len = this.layers ? this.layers.length : 0; + for (i = 0; i < len; i++) { + if (this.elements[i]) { + this.elements[i].destroy(); + } + } + this.elements.length = 0; + this.destroyed = true; + this.animationItem = null; + }; + + SVGRenderer.prototype.updateContainerSize = function () { + }; + + SVGRenderer.prototype.buildItem = function (pos) { + var elements = this.elements; + if (elements[pos] || this.layers[pos].ty == 99) { + return; + } + elements[pos] = true; + var element = this.createItem(this.layers[pos]); + + elements[pos] = element; + if (expressionsPlugin) { + if (this.layers[pos].ty === 0) { + this.globalData.projectInterface.registerComposition(element); + } + element.initExpressions(); + } + this.appendElementInPos(element, pos); + if (this.layers[pos].tt) { + if (!this.elements[pos - 1] || this.elements[pos - 1] === true) { + this.buildItem(pos - 1); + this.addPendingElement(element); + } else { + element.setMatte(elements[pos - 1].layerId); + } + } + }; + + SVGRenderer.prototype.checkPendingElements = function () { + while (this.pendingElements.length) { + var element = this.pendingElements.pop(); + element.checkParenting(); + if (element.data.tt) { + var i = 0, len = this.elements.length; + while (i < len) { + if (this.elements[i] === element) { + element.setMatte(this.elements[i - 1].layerId); + break; + } + i += 1; + } + } + } + }; + + SVGRenderer.prototype.renderFrame = function (num) { + if (this.renderedFrame === num || this.destroyed) { + return; + } + if (num === null) { + num = this.renderedFrame; + } else { + this.renderedFrame = num; + } + // console.log('-------'); + // console.log('FRAME ',num); + this.globalData.frameNum = num; + this.globalData.frameId += 1; + this.globalData.projectInterface.currentFrame = num; + this.globalData._mdf = false; + var i, len = this.layers.length; + if (!this.completeLayers) { + this.checkLayers(num); + } + for (i = len - 1; i >= 0; i--) { + if (this.completeLayers || this.elements[i]) { + this.elements[i].prepareFrame(num - this.layers[i].st); + } + } + if (this.globalData._mdf) { + for (i = 0; i < len; i += 1) { + if (this.completeLayers || this.elements[i]) { + this.elements[i].renderFrame(); + } + } + } + }; + + SVGRenderer.prototype.appendElementInPos = function (element, pos) { + var newElement = element.getBaseElement(); + if (!newElement) { + return; + } + var i = 0; + var nextElement; + while (i < pos) { + if (this.elements[i] && this.elements[i] !== true && this.elements[i].getBaseElement()) { + nextElement = this.elements[i].getBaseElement(); + } + i += 1; + } + if (nextElement) { + this.layerElement.insertBefore(newElement, nextElement); + } else { + this.layerElement.appendChild(newElement); + } + }; + + SVGRenderer.prototype.hide = function () { + this.layerElement.style.display = 'none'; + }; + + SVGRenderer.prototype.show = function () { + this.layerElement.style.display = 'block'; + }; + + function CanvasRenderer(animationItem, config) { + this.animationItem = animationItem; + this.renderConfig = { + clearCanvas: (config && config.clearCanvas !== undefined) ? config.clearCanvas : true, + context: (config && config.context) || null, + progressiveLoad: (config && config.progressiveLoad) || false, + preserveAspectRatio: (config && config.preserveAspectRatio) || 'xMidYMid meet', + imagePreserveAspectRatio: (config && config.imagePreserveAspectRatio) || 'xMidYMid slice', + className: (config && config.className) || '', + id: (config && config.id) || '', + }; + this.renderConfig.dpr = (config && config.dpr) || 1; + if (this.animationItem.wrapper) { + this.renderConfig.dpr = (config && config.dpr) || window.devicePixelRatio || 1; + } + this.renderedFrame = -1; + this.globalData = { + frameNum: -1, + _mdf: false, + renderConfig: this.renderConfig, + currentGlobalAlpha: -1 + }; + this.contextData = new CVContextData(); + this.elements = []; + this.pendingElements = []; + this.transformMat = new Matrix(); + this.completeLayers = false; + this.rendererType = 'canvas'; + } + extendPrototype([BaseRenderer], CanvasRenderer); + + CanvasRenderer.prototype.createShape = function (data) { + return new CVShapeElement(data, this.globalData, this); + }; + + CanvasRenderer.prototype.createText = function (data) { + return new CVTextElement(data, this.globalData, this); + }; + + CanvasRenderer.prototype.createImage = function (data) { + return new CVImageElement(data, this.globalData, this); + }; + + CanvasRenderer.prototype.createComp = function (data) { + return new CVCompElement(data, this.globalData, this); + }; + + CanvasRenderer.prototype.createSolid = function (data) { + return new CVSolidElement(data, this.globalData, this); + }; + + CanvasRenderer.prototype.createNull = SVGRenderer.prototype.createNull; + + CanvasRenderer.prototype.ctxTransform = function (props) { + if (props[0] === 1 && props[1] === 0 && props[4] === 0 && props[5] === 1 && props[12] === 0 && props[13] === 0) { + return; + } + if (!this.renderConfig.clearCanvas) { + this.canvasContext.transform(props[0], props[1], props[4], props[5], props[12], props[13]); + return; + } + this.transformMat.cloneFromProps(props); + var cProps = this.contextData.cTr.props; + this.transformMat.transform(cProps[0], cProps[1], cProps[2], cProps[3], cProps[4], cProps[5], cProps[6], cProps[7], cProps[8], cProps[9], cProps[10], cProps[11], cProps[12], cProps[13], cProps[14], cProps[15]); + //this.contextData.cTr.transform(props[0],props[1],props[2],props[3],props[4],props[5],props[6],props[7],props[8],props[9],props[10],props[11],props[12],props[13],props[14],props[15]); + this.contextData.cTr.cloneFromProps(this.transformMat.props); + var trProps = this.contextData.cTr.props; + this.canvasContext.setTransform(trProps[0], trProps[1], trProps[4], trProps[5], trProps[12], trProps[13]); + }; + + CanvasRenderer.prototype.ctxOpacity = function (op) { + /*if(op === 1){ + return; + }*/ + if (!this.renderConfig.clearCanvas) { + this.canvasContext.globalAlpha *= op < 0 ? 0 : op; + this.globalData.currentGlobalAlpha = this.contextData.cO; + return; + } + this.contextData.cO *= op < 0 ? 0 : op; + if (this.globalData.currentGlobalAlpha !== this.contextData.cO) { + this.canvasContext.globalAlpha = this.contextData.cO; + this.globalData.currentGlobalAlpha = this.contextData.cO; + } + }; + + CanvasRenderer.prototype.reset = function () { + if (!this.renderConfig.clearCanvas) { + this.canvasContext.restore(); + return; + } + this.contextData.reset(); + }; + + CanvasRenderer.prototype.save = function (actionFlag) { + if (!this.renderConfig.clearCanvas) { + this.canvasContext.save(); + return; + } + if (actionFlag) { + this.canvasContext.save(); + } + var props = this.contextData.cTr.props; + if (this.contextData._length <= this.contextData.cArrPos) { + this.contextData.duplicate(); + } + var i, arr = this.contextData.saved[this.contextData.cArrPos]; + for (i = 0; i < 16; i += 1) { + arr[i] = props[i]; + } + this.contextData.savedOp[this.contextData.cArrPos] = this.contextData.cO; + this.contextData.cArrPos += 1; + }; + + CanvasRenderer.prototype.restore = function (actionFlag) { + if (!this.renderConfig.clearCanvas) { + this.canvasContext.restore(); + return; + } + if (actionFlag) { + this.canvasContext.restore(); + this.globalData.blendMode = 'source-over'; + } + this.contextData.cArrPos -= 1; + var popped = this.contextData.saved[this.contextData.cArrPos]; + var i, arr = this.contextData.cTr.props; + for (i = 0; i < 16; i += 1) { + arr[i] = popped[i]; + } + this.canvasContext.setTransform(popped[0], popped[1], popped[4], popped[5], popped[12], popped[13]); + popped = this.contextData.savedOp[this.contextData.cArrPos]; + this.contextData.cO = popped; + if (this.globalData.currentGlobalAlpha !== popped) { + this.canvasContext.globalAlpha = popped; + this.globalData.currentGlobalAlpha = popped; + } + }; + + CanvasRenderer.prototype.configAnimation = function (animData) { + if (this.animationItem.wrapper) { + this.animationItem.container = createTag('canvas'); + this.animationItem.container.style.width = '100%'; + this.animationItem.container.style.height = '100%'; + //this.animationItem.container.style.transform = 'translate3d(0,0,0)'; + //this.animationItem.container.style.webkitTransform = 'translate3d(0,0,0)'; + this.animationItem.container.style.transformOrigin = this.animationItem.container.style.mozTransformOrigin = this.animationItem.container.style.webkitTransformOrigin = this.animationItem.container.style['-webkit-transform'] = "0px 0px 0px"; + this.animationItem.wrapper.appendChild(this.animationItem.container); + this.canvasContext = this.animationItem.container.getContext('2d'); + if (this.renderConfig.className) { + this.animationItem.container.setAttribute('class', this.renderConfig.className); + } + if (this.renderConfig.id) { + this.animationItem.container.setAttribute('id', this.renderConfig.id); + } + } else { + this.canvasContext = this.renderConfig.context; + } + this.data = animData; + this.layers = animData.layers; + this.transformCanvas = { + w: animData.w, + h: animData.h, + sx: 0, + sy: 0, + tx: 0, + ty: 0 + }; + this.setupGlobalData(animData, document.body); + this.globalData.canvasContext = this.canvasContext; + this.globalData.renderer = this; + this.globalData.isDashed = false; + this.globalData.progressiveLoad = this.renderConfig.progressiveLoad; + this.globalData.transformCanvas = this.transformCanvas; + this.elements = createSizedArray(animData.layers.length); + + this.updateContainerSize(); + }; + + CanvasRenderer.prototype.updateContainerSize = function () { + this.reset(); + var elementWidth, elementHeight; + if (this.animationItem.wrapper && this.animationItem.container) { + elementWidth = this.animationItem.wrapper.offsetWidth; + elementHeight = this.animationItem.wrapper.offsetHeight; + this.animationItem.container.setAttribute('width', elementWidth * this.renderConfig.dpr); + this.animationItem.container.setAttribute('height', elementHeight * this.renderConfig.dpr); + } else { + elementWidth = this.canvasContext.canvas.width * this.renderConfig.dpr; + elementHeight = this.canvasContext.canvas.height * this.renderConfig.dpr; + } + var elementRel, animationRel; + if (this.renderConfig.preserveAspectRatio.indexOf('meet') !== -1 || this.renderConfig.preserveAspectRatio.indexOf('slice') !== -1) { + var par = this.renderConfig.preserveAspectRatio.split(' '); + var fillType = par[1] || 'meet'; + var pos = par[0] || 'xMidYMid'; + var xPos = pos.substr(0, 4); + var yPos = pos.substr(4); + elementRel = elementWidth / elementHeight; + animationRel = this.transformCanvas.w / this.transformCanvas.h; + if (animationRel > elementRel && fillType === 'meet' || animationRel < elementRel && fillType === 'slice') { + this.transformCanvas.sx = elementWidth / (this.transformCanvas.w / this.renderConfig.dpr); + this.transformCanvas.sy = elementWidth / (this.transformCanvas.w / this.renderConfig.dpr); + } else { + this.transformCanvas.sx = elementHeight / (this.transformCanvas.h / this.renderConfig.dpr); + this.transformCanvas.sy = elementHeight / (this.transformCanvas.h / this.renderConfig.dpr); + } + + if (xPos === 'xMid' && ((animationRel < elementRel && fillType === 'meet') || (animationRel > elementRel && fillType === 'slice'))) { + this.transformCanvas.tx = (elementWidth - this.transformCanvas.w * (elementHeight / this.transformCanvas.h)) / 2 * this.renderConfig.dpr; + } else if (xPos === 'xMax' && ((animationRel < elementRel && fillType === 'meet') || (animationRel > elementRel && fillType === 'slice'))) { + this.transformCanvas.tx = (elementWidth - this.transformCanvas.w * (elementHeight / this.transformCanvas.h)) * this.renderConfig.dpr; + } else { + this.transformCanvas.tx = 0; + } + if (yPos === 'YMid' && ((animationRel > elementRel && fillType === 'meet') || (animationRel < elementRel && fillType === 'slice'))) { + this.transformCanvas.ty = ((elementHeight - this.transformCanvas.h * (elementWidth / this.transformCanvas.w)) / 2) * this.renderConfig.dpr; + } else if (yPos === 'YMax' && ((animationRel > elementRel && fillType === 'meet') || (animationRel < elementRel && fillType === 'slice'))) { + this.transformCanvas.ty = ((elementHeight - this.transformCanvas.h * (elementWidth / this.transformCanvas.w))) * this.renderConfig.dpr; + } else { + this.transformCanvas.ty = 0; + } + + } else if (this.renderConfig.preserveAspectRatio == 'none') { + this.transformCanvas.sx = elementWidth / (this.transformCanvas.w / this.renderConfig.dpr); + this.transformCanvas.sy = elementHeight / (this.transformCanvas.h / this.renderConfig.dpr); + this.transformCanvas.tx = 0; + this.transformCanvas.ty = 0; + } else { + this.transformCanvas.sx = this.renderConfig.dpr; + this.transformCanvas.sy = this.renderConfig.dpr; + this.transformCanvas.tx = 0; + this.transformCanvas.ty = 0; + } + this.transformCanvas.props = [this.transformCanvas.sx, 0, 0, 0, 0, this.transformCanvas.sy, 0, 0, 0, 0, 1, 0, this.transformCanvas.tx, this.transformCanvas.ty, 0, 1]; + /*var i, len = this.elements.length; + for(i=0;i= 0; i -= 1) { + if (this.elements[i]) { + this.elements[i].destroy(); + } + } + this.elements.length = 0; + this.globalData.canvasContext = null; + this.animationItem.container = null; + this.destroyed = true; + }; + + CanvasRenderer.prototype.renderFrame = function (num, forceRender) { + if ((this.renderedFrame === num && this.renderConfig.clearCanvas === true && !forceRender) || this.destroyed || num === -1) { + return; + } + this.renderedFrame = num; + this.globalData.frameNum = num - this.animationItem._isFirstFrame; + this.globalData.frameId += 1; + this.globalData._mdf = !this.renderConfig.clearCanvas || forceRender; + this.globalData.projectInterface.currentFrame = num; + + // console.log('--------'); + // console.log('NEW: ',num); + var i, len = this.layers.length; + if (!this.completeLayers) { + this.checkLayers(num); + } + + for (i = 0; i < len; i++) { + if (this.completeLayers || this.elements[i]) { + this.elements[i].prepareFrame(num - this.layers[i].st); + } + } + if (this.globalData._mdf) { + if (this.renderConfig.clearCanvas === true) { + this.canvasContext.clearRect(0, 0, this.transformCanvas.w, this.transformCanvas.h); + } else { + this.save(); + } + for (i = len - 1; i >= 0; i -= 1) { + if (this.completeLayers || this.elements[i]) { + this.elements[i].renderFrame(); + } + } + if (this.renderConfig.clearCanvas !== true) { + this.restore(); + } + } + }; + + CanvasRenderer.prototype.buildItem = function (pos) { + var elements = this.elements; + if (elements[pos] || this.layers[pos].ty == 99) { + return; + } + var element = this.createItem(this.layers[pos], this, this.globalData); + elements[pos] = element; + element.initExpressions(); + /*if(this.layers[pos].ty === 0){ + element.resize(this.globalData.transformCanvas); + }*/ + }; + + CanvasRenderer.prototype.checkPendingElements = function () { + while (this.pendingElements.length) { + var element = this.pendingElements.pop(); + element.checkParenting(); + } + }; + + CanvasRenderer.prototype.hide = function () { + this.animationItem.container.style.display = 'none'; + }; + + CanvasRenderer.prototype.show = function () { + this.animationItem.container.style.display = 'block'; + }; + + function HybridRenderer(animationItem, config) { + this.animationItem = animationItem; + this.layers = null; + this.renderedFrame = -1; + this.renderConfig = { + className: (config && config.className) || '', + imagePreserveAspectRatio: (config && config.imagePreserveAspectRatio) || 'xMidYMid slice', + hideOnTransparent: (config && config.hideOnTransparent === false) ? false : true, + filterSize: { + width: config && config.filterSize && config.filterSize.width || '400%', + height: config && config.filterSize && config.filterSize.height || '400%', + x: config && config.filterSize && config.filterSize.x || '-100%', + y: config && config.filterSize && config.filterSize.y || '-100%', + } + }; + this.globalData = { + _mdf: false, + frameNum: -1, + renderConfig: this.renderConfig + }; + this.pendingElements = []; + this.elements = []; + this.threeDElements = []; + this.destroyed = false; + this.camera = null; + this.supports3d = true; + this.rendererType = 'html'; + + } + + extendPrototype([BaseRenderer], HybridRenderer); + + HybridRenderer.prototype.buildItem = SVGRenderer.prototype.buildItem; + + HybridRenderer.prototype.checkPendingElements = function () { + while (this.pendingElements.length) { + var element = this.pendingElements.pop(); + element.checkParenting(); + } + }; + + HybridRenderer.prototype.appendElementInPos = function (element, pos) { + var newDOMElement = element.getBaseElement(); + if (!newDOMElement) { + return; + } + var layer = this.layers[pos]; + if (!layer.ddd || !this.supports3d) { + if (this.threeDElements) { + this.addTo3dContainer(newDOMElement, pos); + } else { + var i = 0; + var nextDOMElement, nextLayer, tmpDOMElement; + while (i < pos) { + if (this.elements[i] && this.elements[i] !== true && this.elements[i].getBaseElement) { + nextLayer = this.elements[i]; + tmpDOMElement = this.layers[i].ddd ? this.getThreeDContainerByPos(i) : nextLayer.getBaseElement(); + nextDOMElement = tmpDOMElement || nextDOMElement; + } + i += 1; + } + if (nextDOMElement) { + if (!layer.ddd || !this.supports3d) { + this.layerElement.insertBefore(newDOMElement, nextDOMElement); + } + } else { + if (!layer.ddd || !this.supports3d) { + this.layerElement.appendChild(newDOMElement); + } + } + } + + } else { + this.addTo3dContainer(newDOMElement, pos); + } + }; + + HybridRenderer.prototype.createShape = function (data) { + if (!this.supports3d) { + return new SVGShapeElement(data, this.globalData, this); + } + return new HShapeElement(data, this.globalData, this); + }; + + HybridRenderer.prototype.createText = function (data) { + if (!this.supports3d) { + return new SVGTextElement(data, this.globalData, this); + } + return new HTextElement(data, this.globalData, this); + }; + + HybridRenderer.prototype.createCamera = function (data) { + this.camera = new HCameraElement(data, this.globalData, this); + return this.camera; + }; + + HybridRenderer.prototype.createImage = function (data) { + if (!this.supports3d) { + return new IImageElement(data, this.globalData, this); + } + return new HImageElement(data, this.globalData, this); + }; + + HybridRenderer.prototype.createComp = function (data) { + if (!this.supports3d) { + return new SVGCompElement(data, this.globalData, this); + } + return new HCompElement(data, this.globalData, this); + + }; + + HybridRenderer.prototype.createSolid = function (data) { + if (!this.supports3d) { + return new ISolidElement(data, this.globalData, this); + } + return new HSolidElement(data, this.globalData, this); + }; + + HybridRenderer.prototype.createNull = SVGRenderer.prototype.createNull; + + HybridRenderer.prototype.getThreeDContainerByPos = function (pos) { + var i = 0, len = this.threeDElements.length; + while (i < len) { + if (this.threeDElements[i].startPos <= pos && this.threeDElements[i].endPos >= pos) { + return this.threeDElements[i].perspectiveElem; + } + i += 1; + } + }; + + HybridRenderer.prototype.createThreeDContainer = function (pos, type) { + var perspectiveElem = createTag('div'); + styleDiv(perspectiveElem); + var container = createTag('div'); + styleDiv(container); + if (type === '3d') { + perspectiveElem.style.width = this.globalData.compSize.w + 'px'; + perspectiveElem.style.height = this.globalData.compSize.h + 'px'; + perspectiveElem.style.transformOrigin = perspectiveElem.style.mozTransformOrigin = perspectiveElem.style.webkitTransformOrigin = "50% 50%"; + container.style.transform = container.style.webkitTransform = 'matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1)'; + } + + perspectiveElem.appendChild(container); + //this.resizerElem.appendChild(perspectiveElem); + var threeDContainerData = { + container: container, + perspectiveElem: perspectiveElem, + startPos: pos, + endPos: pos, + type: type + }; + this.threeDElements.push(threeDContainerData); + return threeDContainerData; + }; + + HybridRenderer.prototype.build3dContainers = function () { + var i, len = this.layers.length; + var lastThreeDContainerData; + var currentContainer = ''; + for (i = 0; i < len; i += 1) { + if (this.layers[i].ddd && this.layers[i].ty !== 3) { + if (currentContainer !== '3d') { + currentContainer = '3d'; + lastThreeDContainerData = this.createThreeDContainer(i, '3d'); + } + lastThreeDContainerData.endPos = Math.max(lastThreeDContainerData.endPos, i); + } else { + if (currentContainer !== '2d') { + currentContainer = '2d'; + lastThreeDContainerData = this.createThreeDContainer(i, '2d'); + } + lastThreeDContainerData.endPos = Math.max(lastThreeDContainerData.endPos, i); + } + } + len = this.threeDElements.length; + for (i = len - 1; i >= 0; i--) { + this.resizerElem.appendChild(this.threeDElements[i].perspectiveElem); + } + }; + + HybridRenderer.prototype.addTo3dContainer = function (elem, pos) { + var i = 0, len = this.threeDElements.length; + while (i < len) { + if (pos <= this.threeDElements[i].endPos) { + var j = this.threeDElements[i].startPos; + var nextElement; + while (j < pos) { + if (this.elements[j] && this.elements[j].getBaseElement) { + nextElement = this.elements[j].getBaseElement(); + } + j += 1; + } + if (nextElement) { + this.threeDElements[i].container.insertBefore(elem, nextElement); + } else { + this.threeDElements[i].container.appendChild(elem); + } + break; + } + i += 1; + } + }; + + HybridRenderer.prototype.configAnimation = function (animData) { + var resizerElem = createTag('div'); + var wrapper = this.animationItem.wrapper; + resizerElem.style.width = animData.w + 'px'; + resizerElem.style.height = animData.h + 'px'; + this.resizerElem = resizerElem; + styleDiv(resizerElem); + resizerElem.style.transformStyle = resizerElem.style.webkitTransformStyle = resizerElem.style.mozTransformStyle = "flat"; + if (this.renderConfig.className) { + resizerElem.setAttribute('class', this.renderConfig.className); + } + wrapper.appendChild(resizerElem); + + resizerElem.style.overflow = 'hidden'; + var svg = createNS('svg'); + svg.setAttribute('width', '1'); + svg.setAttribute('height', '1'); + styleDiv(svg); + this.resizerElem.appendChild(svg); + var defs = createNS('defs'); + svg.appendChild(defs); + this.data = animData; + //Mask animation + this.setupGlobalData(animData, svg); + this.globalData.defs = defs; + this.layers = animData.layers; + this.layerElement = this.resizerElem; + this.build3dContainers(); + this.updateContainerSize(); + }; + + HybridRenderer.prototype.destroy = function () { + this.animationItem.wrapper.innerHTML = ''; + this.animationItem.container = null; + this.globalData.defs = null; + var i, len = this.layers ? this.layers.length : 0; + for (i = 0; i < len; i++) { + this.elements[i].destroy(); + } + this.elements.length = 0; + this.destroyed = true; + this.animationItem = null; + }; + + HybridRenderer.prototype.updateContainerSize = function () { + var elementWidth = this.animationItem.wrapper.offsetWidth; + var elementHeight = this.animationItem.wrapper.offsetHeight; + var elementRel = elementWidth / elementHeight; + var animationRel = this.globalData.compSize.w / this.globalData.compSize.h; + var sx, sy, tx, ty; + if (animationRel > elementRel) { + sx = elementWidth / (this.globalData.compSize.w); + sy = elementWidth / (this.globalData.compSize.w); + tx = 0; + ty = ((elementHeight - this.globalData.compSize.h * (elementWidth / this.globalData.compSize.w)) / 2); + } else { + sx = elementHeight / (this.globalData.compSize.h); + sy = elementHeight / (this.globalData.compSize.h); + tx = (elementWidth - this.globalData.compSize.w * (elementHeight / this.globalData.compSize.h)) / 2; + ty = 0; + } + this.resizerElem.style.transform = this.resizerElem.style.webkitTransform = 'matrix3d(' + sx + ',0,0,0,0,' + sy + ',0,0,0,0,1,0,' + tx + ',' + ty + ',0,1)'; + }; + + HybridRenderer.prototype.renderFrame = SVGRenderer.prototype.renderFrame; + + HybridRenderer.prototype.hide = function () { + this.resizerElem.style.display = 'none'; + }; + + HybridRenderer.prototype.show = function () { + this.resizerElem.style.display = 'block'; + }; + + HybridRenderer.prototype.initItems = function () { + this.buildAllItems(); + if (this.camera) { + this.camera.setup(); + } else { + var cWidth = this.globalData.compSize.w; + var cHeight = this.globalData.compSize.h; + var i, len = this.threeDElements.length; + for (i = 0; i < len; i += 1) { + this.threeDElements[i].perspectiveElem.style.perspective = this.threeDElements[i].perspectiveElem.style.webkitPerspective = Math.sqrt(Math.pow(cWidth, 2) + Math.pow(cHeight, 2)) + 'px'; + } + } + }; + + HybridRenderer.prototype.searchExtraCompositions = function (assets) { + var i, len = assets.length; + var floatingContainer = createTag('div'); + for (i = 0; i < len; i += 1) { + if (assets[i].xt) { + var comp = this.createComp(assets[i], floatingContainer, this.globalData.comp, null); + comp.initExpressions(); + this.globalData.projectInterface.registerComposition(comp); + } + } + }; + + function MaskElement(data, element, globalData) { + this.data = data; + this.element = element; + this.globalData = globalData; + this.storedData = []; + this.masksProperties = this.data.masksProperties || []; + this.maskElement = null; + var defs = this.globalData.defs; + var i, len = this.masksProperties ? this.masksProperties.length : 0; + this.viewData = createSizedArray(len); + this.solidPath = ''; + + + var path, properties = this.masksProperties; + var count = 0; + var currentMasks = []; + var j, jLen; + var layerId = createElementID(); + var rect, expansor, feMorph, x; + var maskType = 'clipPath', maskRef = 'clip-path'; + for (i = 0; i < len; i++) { + if ((properties[i].mode !== 'a' && properties[i].mode !== 'n') || properties[i].inv || properties[i].o.k !== 100 || properties[i].o.x) { + maskType = 'mask'; + maskRef = 'mask'; + } + + if ((properties[i].mode == 's' || properties[i].mode == 'i') && count === 0) { + rect = createNS('rect'); + rect.setAttribute('fill', '#ffffff'); + rect.setAttribute('width', this.element.comp.data.w || 0); + rect.setAttribute('height', this.element.comp.data.h || 0); + currentMasks.push(rect); + } else { + rect = null; + } + + path = createNS('path'); + if (properties[i].mode == 'n') { + // TODO move this to a factory or to a constructor + this.viewData[i] = { + op: PropertyFactory.getProp(this.element, properties[i].o, 0, 0.01, this.element), + prop: ShapePropertyFactory.getShapeProp(this.element, properties[i], 3), + elem: path, + lastPath: '' + }; + defs.appendChild(path); + continue; + } + count += 1; + + path.setAttribute('fill', properties[i].mode === 's' ? '#000000' : '#ffffff'); + path.setAttribute('clip-rule', 'nonzero'); + var filterID; + + if (properties[i].x.k !== 0) { + maskType = 'mask'; + maskRef = 'mask'; + x = PropertyFactory.getProp(this.element, properties[i].x, 0, null, this.element); + filterID = createElementID(); + expansor = createNS('filter'); + expansor.setAttribute('id', filterID); + feMorph = createNS('feMorphology'); + feMorph.setAttribute('operator', 'erode'); + feMorph.setAttribute('in', 'SourceGraphic'); + feMorph.setAttribute('radius', '0'); + expansor.appendChild(feMorph); + defs.appendChild(expansor); + path.setAttribute('stroke', properties[i].mode === 's' ? '#000000' : '#ffffff'); + } else { + feMorph = null; + x = null; + } + + // TODO move this to a factory or to a constructor + this.storedData[i] = { + elem: path, + x: x, + expan: feMorph, + lastPath: '', + lastOperator: '', + filterId: filterID, + lastRadius: 0 + }; + if (properties[i].mode == 'i') { + jLen = currentMasks.length; + var g = createNS('g'); + for (j = 0; j < jLen; j += 1) { + g.appendChild(currentMasks[j]); + } + var mask = createNS('mask'); + mask.setAttribute('mask-type', 'alpha'); + mask.setAttribute('id', layerId + '_' + count); + mask.appendChild(path); + defs.appendChild(mask); + g.setAttribute('mask', 'url(' + locationHref + '#' + layerId + '_' + count + ')'); + + currentMasks.length = 0; + currentMasks.push(g); + } else { + currentMasks.push(path); + } + if (properties[i].inv && !this.solidPath) { + this.solidPath = this.createLayerSolidPath(); + } + // TODO move this to a factory or to a constructor + this.viewData[i] = { + elem: path, + lastPath: '', + op: PropertyFactory.getProp(this.element, properties[i].o, 0, 0.01, this.element), + prop: ShapePropertyFactory.getShapeProp(this.element, properties[i], 3), + invRect: rect + }; + if (!this.viewData[i].prop.k) { + this.drawPath(properties[i], this.viewData[i].prop.v, this.viewData[i]); + } + } + + this.maskElement = createNS(maskType); + + len = currentMasks.length; + for (i = 0; i < len; i += 1) { + this.maskElement.appendChild(currentMasks[i]); + } + + if (count > 0) { + this.maskElement.setAttribute('id', layerId); + this.element.maskedElement.setAttribute(maskRef, "url(" + locationHref + "#" + layerId + ")"); + defs.appendChild(this.maskElement); + } + if (this.viewData.length) { + this.element.addRenderableComponent(this); + } + + } + + MaskElement.prototype.getMaskProperty = function (pos) { + return this.viewData[pos].prop; + }; + + MaskElement.prototype.renderFrame = function (isFirstFrame) { + var finalMat = this.element.finalTransform.mat; + var i, len = this.masksProperties.length; + for (i = 0; i < len; i++) { + if (this.viewData[i].prop._mdf || isFirstFrame) { + this.drawPath(this.masksProperties[i], this.viewData[i].prop.v, this.viewData[i]); + } + if (this.viewData[i].op._mdf || isFirstFrame) { + this.viewData[i].elem.setAttribute('fill-opacity', this.viewData[i].op.v); + } + if (this.masksProperties[i].mode !== 'n') { + if (this.viewData[i].invRect && (this.element.finalTransform.mProp._mdf || isFirstFrame)) { + this.viewData[i].invRect.setAttribute('transform', finalMat.getInverseMatrix().to2dCSS()) + } + if (this.storedData[i].x && (this.storedData[i].x._mdf || isFirstFrame)) { + var feMorph = this.storedData[i].expan; + if (this.storedData[i].x.v < 0) { + if (this.storedData[i].lastOperator !== 'erode') { + this.storedData[i].lastOperator = 'erode'; + this.storedData[i].elem.setAttribute('filter', 'url(' + locationHref + '#' + this.storedData[i].filterId + ')'); + } + feMorph.setAttribute('radius', -this.storedData[i].x.v); + } else { + if (this.storedData[i].lastOperator !== 'dilate') { + this.storedData[i].lastOperator = 'dilate'; + this.storedData[i].elem.setAttribute('filter', null); + } + this.storedData[i].elem.setAttribute('stroke-width', this.storedData[i].x.v * 2); + + } + } + } + } + }; + + MaskElement.prototype.getMaskelement = function () { + return this.maskElement; + }; + + MaskElement.prototype.createLayerSolidPath = function () { + var path = 'M0,0 '; + path += ' h' + this.globalData.compSize.w; + path += ' v' + this.globalData.compSize.h; + path += ' h-' + this.globalData.compSize.w; + path += ' v-' + this.globalData.compSize.h + ' '; + return path; + }; + + MaskElement.prototype.drawPath = function (pathData, pathNodes, viewData) { + var pathString = " M" + pathNodes.v[0][0] + ',' + pathNodes.v[0][1]; + var i, len; + len = pathNodes._length; + for (i = 1; i < len; i += 1) { + //pathString += " C"+pathNodes.o[i-1][0]+','+pathNodes.o[i-1][1] + " "+pathNodes.i[i][0]+','+pathNodes.i[i][1] + " "+pathNodes.v[i][0]+','+pathNodes.v[i][1]; + pathString += " C" + pathNodes.o[i - 1][0] + ',' + pathNodes.o[i - 1][1] + " " + pathNodes.i[i][0] + ',' + pathNodes.i[i][1] + " " + pathNodes.v[i][0] + ',' + pathNodes.v[i][1]; + } + //pathString += " C"+pathNodes.o[i-1][0]+','+pathNodes.o[i-1][1] + " "+pathNodes.i[0][0]+','+pathNodes.i[0][1] + " "+pathNodes.v[0][0]+','+pathNodes.v[0][1]; + if (pathNodes.c && len > 1) { + pathString += " C" + pathNodes.o[i - 1][0] + ',' + pathNodes.o[i - 1][1] + " " + pathNodes.i[0][0] + ',' + pathNodes.i[0][1] + " " + pathNodes.v[0][0] + ',' + pathNodes.v[0][1]; + } + //pathNodes.__renderedString = pathString; + + if (viewData.lastPath !== pathString) { + var pathShapeValue = ''; + if (viewData.elem) { + if (pathNodes.c) { + pathShapeValue = pathData.inv ? this.solidPath + pathString : pathString; + } + viewData.elem.setAttribute('d', pathShapeValue); + } + viewData.lastPath = pathString; + } + }; + + MaskElement.prototype.destroy = function () { + this.element = null; + this.globalData = null; + this.maskElement = null; + this.data = null; + this.masksProperties = null; + }; + + /** + * @file + * Handles AE's layer parenting property. + * + */ + + function HierarchyElement() { } + + HierarchyElement.prototype = { + /** + * @function + * Initializes hierarchy properties + * + */ + initHierarchy: function () { + //element's parent list + this.hierarchy = []; + //if element is parent of another layer _isParent will be true + this._isParent = false; + this.checkParenting(); + }, + /** + * @function + * Sets layer's hierarchy. + * @param {array} hierarch + * layer's parent list + * + */ + setHierarchy: function (hierarchy) { + this.hierarchy = hierarchy; + }, + /** + * @function + * Sets layer as parent. + * + */ + setAsParent: function () { + this._isParent = true; + }, + /** + * @function + * Searches layer's parenting chain + * + */ + checkParenting: function () { + if (this.data.parent !== undefined) { + this.comp.buildElementParenting(this, this.data.parent, []); + } + } + }; + /** + * @file + * Handles element's layer frame update. + * Checks layer in point and out point + * + */ + + function FrameElement() { } + + FrameElement.prototype = { + /** + * @function + * Initializes frame related properties. + * + */ + initFrame: function () { + //set to true when inpoint is rendered + this._isFirstFrame = false; + //list of animated properties + this.dynamicProperties = []; + // If layer has been modified in current tick this will be true + this._mdf = false; + }, + /** + * @function + * Calculates all dynamic values + * + * @param {number} num + * current frame number in Layer's time + * @param {boolean} isVisible + * if layers is currently in range + * + */ + prepareProperties: function (num, isVisible) { + var i, len = this.dynamicProperties.length; + for (i = 0; i < len; i += 1) { + if (isVisible || (this._isParent && this.dynamicProperties[i].propType === 'transform')) { + this.dynamicProperties[i].getValue(); + if (this.dynamicProperties[i]._mdf) { + this.globalData._mdf = true; + this._mdf = true; + } + } + } + }, + addDynamicProperty: function (prop) { + if (this.dynamicProperties.indexOf(prop) === -1) { + this.dynamicProperties.push(prop); + } + } + }; + function TransformElement() { } + + TransformElement.prototype = { + initTransform: function () { + this.finalTransform = { + mProp: this.data.ks ? TransformPropertyFactory.getTransformProperty(this, this.data.ks, this) : { o: 0 }, + _matMdf: false, + _opMdf: false, + mat: new Matrix() + }; + if (this.data.ao) { + this.finalTransform.mProp.autoOriented = true; + } + + //TODO: check TYPE 11: Guided elements + if (this.data.ty !== 11) { + //this.createElements(); + } + }, + renderTransform: function () { + + this.finalTransform._opMdf = this.finalTransform.mProp.o._mdf || this._isFirstFrame; + this.finalTransform._matMdf = this.finalTransform.mProp._mdf || this._isFirstFrame; + + if (this.hierarchy) { + var mat; + var finalMat = this.finalTransform.mat; + var i = 0, len = this.hierarchy.length; + //Checking if any of the transformation matrices in the hierarchy chain has changed. + if (!this.finalTransform._matMdf) { + while (i < len) { + if (this.hierarchy[i].finalTransform.mProp._mdf) { + this.finalTransform._matMdf = true; + break; + } + i += 1; + } + } + + if (this.finalTransform._matMdf) { + mat = this.finalTransform.mProp.v.props; + finalMat.cloneFromProps(mat); + for (i = 0; i < len; i += 1) { + mat = this.hierarchy[i].finalTransform.mProp.v.props; + finalMat.transform(mat[0], mat[1], mat[2], mat[3], mat[4], mat[5], mat[6], mat[7], mat[8], mat[9], mat[10], mat[11], mat[12], mat[13], mat[14], mat[15]); + } + } + } + }, + globalToLocal: function (pt) { + var transforms = []; + transforms.push(this.finalTransform); + var flag = true; + var comp = this.comp; + while (flag) { + if (comp.finalTransform) { + if (comp.data.hasMask) { + transforms.splice(0, 0, comp.finalTransform); + } + comp = comp.comp; + } else { + flag = false; + } + } + var i, len = transforms.length, ptNew; + for (i = 0; i < len; i += 1) { + ptNew = transforms[i].mat.applyToPointArray(0, 0, 0); + //ptNew = transforms[i].mat.applyToPointArray(pt[0],pt[1],pt[2]); + pt = [pt[0] - ptNew[0], pt[1] - ptNew[1], 0]; + } + return pt; + }, + mHelper: new Matrix() + }; + function RenderableElement() { + + } + + RenderableElement.prototype = { + initRenderable: function () { + //layer's visibility related to inpoint and outpoint. Rename isVisible to isInRange + this.isInRange = false; + //layer's display state + this.hidden = false; + // If layer's transparency equals 0, it can be hidden + this.isTransparent = false; + //list of animated components + this.renderableComponents = []; + }, + addRenderableComponent: function (component) { + if (this.renderableComponents.indexOf(component) === -1) { + this.renderableComponents.push(component); + } + }, + removeRenderableComponent: function (component) { + if (this.renderableComponents.indexOf(component) !== -1) { + this.renderableComponents.splice(this.renderableComponents.indexOf(component), 1); + } + }, + prepareRenderableFrame: function (num) { + this.checkLayerLimits(num); + }, + checkTransparency: function () { + if (this.finalTransform.mProp.o.v <= 0) { + if (!this.isTransparent && this.globalData.renderConfig.hideOnTransparent) { + this.isTransparent = true; + this.hide(); + } + } else if (this.isTransparent) { + this.isTransparent = false; + this.show(); + } + }, + /** + * @function + * Initializes frame related properties. + * + * @param {number} num + * current frame number in Layer's time + * + */ + checkLayerLimits: function (num) { + if (this.data.ip - this.data.st <= num && this.data.op - this.data.st > num) { + if (this.isInRange !== true) { + this.globalData._mdf = true; + this._mdf = true; + this.isInRange = true; + this.show(); + } + } else { + if (this.isInRange !== false) { + this.globalData._mdf = true; + this.isInRange = false; + this.hide(); + } + } + }, + renderRenderable: function () { + var i, len = this.renderableComponents.length; + for (i = 0; i < len; i += 1) { + this.renderableComponents[i].renderFrame(this._isFirstFrame); + } + /*this.maskManager.renderFrame(this.finalTransform.mat); + this.renderableEffectsManager.renderFrame(this._isFirstFrame);*/ + }, + sourceRectAtTime: function () { + return { + top: 0, + left: 0, + width: 100, + height: 100 + }; + }, + getLayerSize: function () { + if (this.data.ty === 5) { + return { w: this.data.textData.width, h: this.data.textData.height }; + } else { + return { w: this.data.width, h: this.data.height }; + } + } + }; + function RenderableDOMElement() { } + + (function () { + var _prototype = { + initElement: function (data, globalData, comp) { + this.initFrame(); + this.initBaseData(data, globalData, comp); + this.initTransform(data, globalData, comp); + this.initHierarchy(); + this.initRenderable(); + this.initRendererElement(); + this.createContainerElements(); + this.createRenderableComponents(); + this.createContent(); + this.hide(); + }, + hide: function () { + if (!this.hidden && (!this.isInRange || this.isTransparent)) { + var elem = this.baseElement || this.layerElement; + elem.style.display = 'none'; + this.hidden = true; + } + }, + show: function () { + if (this.isInRange && !this.isTransparent) { + if (!this.data.hd) { + var elem = this.baseElement || this.layerElement; + elem.style.display = 'block'; + } + this.hidden = false; + this._isFirstFrame = true; + } + }, + renderFrame: function () { + //If it is exported as hidden (data.hd === true) no need to render + //If it is not visible no need to render + if (this.data.hd || this.hidden) { + return; + } + this.renderTransform(); + this.renderRenderable(); + this.renderElement(); + this.renderInnerContent(); + if (this._isFirstFrame) { + this._isFirstFrame = false; + } + }, + renderInnerContent: function () { }, + prepareFrame: function (num) { + this._mdf = false; + this.prepareRenderableFrame(num); + this.prepareProperties(num, this.isInRange); + this.checkTransparency(); + }, + destroy: function () { + this.innerElem = null; + this.destroyBaseElement(); + } + }; + extendPrototype([RenderableElement, createProxyFunction(_prototype)], RenderableDOMElement); + }()); + function ProcessedElement(element, position) { + this.elem = element; + this.pos = position; + } + function SVGStyleData(data, level) { + this.data = data; + this.type = data.ty; + this.d = ''; + this.lvl = level; + this._mdf = false; + this.closed = data.hd === true; + this.pElem = createNS('path'); + this.msElem = null; + } + + SVGStyleData.prototype.reset = function () { + this.d = ''; + this._mdf = false; + }; + function SVGShapeData(transformers, level, shape) { + this.caches = []; + this.styles = []; + this.transformers = transformers; + this.lStr = ''; + this.sh = shape; + this.lvl = level; + //TODO find if there are some cases where _isAnimated can be false. + // For now, since shapes add up with other shapes. They have to be calculated every time. + // One way of finding out is checking if all styles associated to this shape depend only of this shape + this._isAnimated = !!shape.k; + // TODO: commenting this for now since all shapes are animated + var i = 0, len = transformers.length; + while (i < len) { + if (transformers[i].mProps.dynamicProperties.length) { + this._isAnimated = true; + break; + } + i += 1; + } + } + + SVGShapeData.prototype.setAsAnimated = function () { + this._isAnimated = true; + } + function SVGTransformData(mProps, op, container) { + this.transform = { + mProps: mProps, + op: op, + container: container + }; + this.elements = []; + this._isAnimated = this.transform.mProps.dynamicProperties.length || this.transform.op.effectsSequence.length; + } + function SVGStrokeStyleData(elem, data, styleOb) { + this.initDynamicPropertyContainer(elem); + this.getValue = this.iterateDynamicProperties; + this.o = PropertyFactory.getProp(elem, data.o, 0, 0.01, this); + this.w = PropertyFactory.getProp(elem, data.w, 0, null, this); + this.d = new DashProperty(elem, data.d || {}, 'svg', this); + this.c = PropertyFactory.getProp(elem, data.c, 1, 255, this); + this.style = styleOb; + this._isAnimated = !!this._isAnimated; + } + + extendPrototype([DynamicPropertyContainer], SVGStrokeStyleData); + function SVGFillStyleData(elem, data, styleOb) { + this.initDynamicPropertyContainer(elem); + this.getValue = this.iterateDynamicProperties; + this.o = PropertyFactory.getProp(elem, data.o, 0, 0.01, this); + this.c = PropertyFactory.getProp(elem, data.c, 1, 255, this); + this.style = styleOb; + } + + extendPrototype([DynamicPropertyContainer], SVGFillStyleData); + function SVGGradientFillStyleData(elem, data, styleOb) { + this.initDynamicPropertyContainer(elem); + this.getValue = this.iterateDynamicProperties; + this.initGradientData(elem, data, styleOb); + } + + SVGGradientFillStyleData.prototype.initGradientData = function (elem, data, styleOb) { + this.o = PropertyFactory.getProp(elem, data.o, 0, 0.01, this); + this.s = PropertyFactory.getProp(elem, data.s, 1, null, this); + this.e = PropertyFactory.getProp(elem, data.e, 1, null, this); + this.h = PropertyFactory.getProp(elem, data.h || { k: 0 }, 0, 0.01, this); + this.a = PropertyFactory.getProp(elem, data.a || { k: 0 }, 0, degToRads, this); + this.g = new GradientProperty(elem, data.g, this); + this.style = styleOb; + this.stops = []; + this.setGradientData(styleOb.pElem, data); + this.setGradientOpacity(data, styleOb); + this._isAnimated = !!this._isAnimated; + + }; + + SVGGradientFillStyleData.prototype.setGradientData = function (pathElement, data) { + + var gradientId = createElementID(); + var gfill = createNS(data.t === 1 ? 'linearGradient' : 'radialGradient'); + gfill.setAttribute('id', gradientId); + gfill.setAttribute('spreadMethod', 'pad'); + gfill.setAttribute('gradientUnits', 'userSpaceOnUse'); + var stops = []; + var stop, j, jLen; + jLen = data.g.p * 4; + for (j = 0; j < jLen; j += 4) { + stop = createNS('stop'); + gfill.appendChild(stop); + stops.push(stop); + } + pathElement.setAttribute(data.ty === 'gf' ? 'fill' : 'stroke', 'url(' + locationHref + '#' + gradientId + ')'); + + this.gf = gfill; + this.cst = stops; + }; + + SVGGradientFillStyleData.prototype.setGradientOpacity = function (data, styleOb) { + if (this.g._hasOpacity && !this.g._collapsable) { + var stop, j, jLen; + var mask = createNS("mask"); + var maskElement = createNS('path'); + mask.appendChild(maskElement); + var opacityId = createElementID(); + var maskId = createElementID(); + mask.setAttribute('id', maskId); + var opFill = createNS(data.t === 1 ? 'linearGradient' : 'radialGradient'); + opFill.setAttribute('id', opacityId); + opFill.setAttribute('spreadMethod', 'pad'); + opFill.setAttribute('gradientUnits', 'userSpaceOnUse'); + jLen = data.g.k.k[0].s ? data.g.k.k[0].s.length : data.g.k.k.length; + var stops = this.stops; + for (j = data.g.p * 4; j < jLen; j += 2) { + stop = createNS('stop'); + stop.setAttribute('stop-color', 'rgb(255,255,255)'); + opFill.appendChild(stop); + stops.push(stop); + } + maskElement.setAttribute(data.ty === 'gf' ? 'fill' : 'stroke', 'url(' + locationHref + '#' + opacityId + ')'); + this.of = opFill; + this.ms = mask; + this.ost = stops; + this.maskId = maskId; + styleOb.msElem = maskElement; + } + }; + + extendPrototype([DynamicPropertyContainer], SVGGradientFillStyleData); + function SVGGradientStrokeStyleData(elem, data, styleOb) { + this.initDynamicPropertyContainer(elem); + this.getValue = this.iterateDynamicProperties; + this.w = PropertyFactory.getProp(elem, data.w, 0, null, this); + this.d = new DashProperty(elem, data.d || {}, 'svg', this); + this.initGradientData(elem, data, styleOb); + this._isAnimated = !!this._isAnimated; + } + + extendPrototype([SVGGradientFillStyleData, DynamicPropertyContainer], SVGGradientStrokeStyleData); + function ShapeGroupData() { + this.it = []; + this.prevViewData = []; + this.gr = createNS('g'); + } + var SVGElementsRenderer = (function () { + var _identityMatrix = new Matrix(); + var _matrixHelper = new Matrix(); + + var ob = { + createRenderFunction: createRenderFunction + } + + function createRenderFunction(data) { + var ty = data.ty; + switch (data.ty) { + case 'fl': + return renderFill; + case 'gf': + return renderGradient; + case 'gs': + return renderGradientStroke; + case 'st': + return renderStroke; + case 'sh': + case 'el': + case 'rc': + case 'sr': + return renderPath; + case 'tr': + return renderContentTransform; + } + } + + function renderContentTransform(styleData, itemData, isFirstFrame) { + if (isFirstFrame || itemData.transform.op._mdf) { + itemData.transform.container.setAttribute('opacity', itemData.transform.op.v); + } + if (isFirstFrame || itemData.transform.mProps._mdf) { + itemData.transform.container.setAttribute('transform', itemData.transform.mProps.v.to2dCSS()); + } + } + + function renderPath(styleData, itemData, isFirstFrame) { + var j, jLen, pathStringTransformed, redraw, pathNodes, l, lLen = itemData.styles.length; + var lvl = itemData.lvl; + var paths, mat, props, iterations, k; + for (l = 0; l < lLen; l += 1) { + redraw = itemData.sh._mdf || isFirstFrame; + if (itemData.styles[l].lvl < lvl) { + mat = _matrixHelper.reset(); + iterations = lvl - itemData.styles[l].lvl; + k = itemData.transformers.length - 1; + while (!redraw && iterations > 0) { + redraw = itemData.transformers[k].mProps._mdf || redraw; + iterations--; + k--; + } + if (redraw) { + iterations = lvl - itemData.styles[l].lvl; + k = itemData.transformers.length - 1; + while (iterations > 0) { + props = itemData.transformers[k].mProps.v.props; + mat.transform(props[0], props[1], props[2], props[3], props[4], props[5], props[6], props[7], props[8], props[9], props[10], props[11], props[12], props[13], props[14], props[15]); + iterations--; + k--; + } + } + } else { + mat = _identityMatrix; + } + paths = itemData.sh.paths; + jLen = paths._length; + if (redraw) { + pathStringTransformed = ''; + for (j = 0; j < jLen; j += 1) { + pathNodes = paths.shapes[j]; + if (pathNodes && pathNodes._length) { + pathStringTransformed += buildShapeString(pathNodes, pathNodes._length, pathNodes.c, mat); + } + } + itemData.caches[l] = pathStringTransformed; + } else { + pathStringTransformed = itemData.caches[l]; + } + itemData.styles[l].d += styleData.hd === true ? '' : pathStringTransformed; + itemData.styles[l]._mdf = redraw || itemData.styles[l]._mdf; + } + } + + function renderFill(styleData, itemData, isFirstFrame) { + var styleElem = itemData.style; + + if (itemData.c._mdf || isFirstFrame) { + styleElem.pElem.setAttribute('fill', 'rgb(' + bm_floor(itemData.c.v[0]) + ',' + bm_floor(itemData.c.v[1]) + ',' + bm_floor(itemData.c.v[2]) + ')'); + } + if (itemData.o._mdf || isFirstFrame) { + styleElem.pElem.setAttribute('fill-opacity', itemData.o.v); + } + }; + + function renderGradientStroke(styleData, itemData, isFirstFrame) { + renderGradient(styleData, itemData, isFirstFrame); + renderStroke(styleData, itemData, isFirstFrame); + } + + function renderGradient(styleData, itemData, isFirstFrame) { + var gfill = itemData.gf; + var hasOpacity = itemData.g._hasOpacity; + var pt1 = itemData.s.v, pt2 = itemData.e.v; + + if (itemData.o._mdf || isFirstFrame) { + var attr = styleData.ty === 'gf' ? 'fill-opacity' : 'stroke-opacity'; + itemData.style.pElem.setAttribute(attr, itemData.o.v); + } + if (itemData.s._mdf || isFirstFrame) { + var attr1 = styleData.t === 1 ? 'x1' : 'cx'; + var attr2 = attr1 === 'x1' ? 'y1' : 'cy'; + gfill.setAttribute(attr1, pt1[0]); + gfill.setAttribute(attr2, pt1[1]); + if (hasOpacity && !itemData.g._collapsable) { + itemData.of.setAttribute(attr1, pt1[0]); + itemData.of.setAttribute(attr2, pt1[1]); + } + } + var stops, i, len, stop; + if (itemData.g._cmdf || isFirstFrame) { + stops = itemData.cst; + var cValues = itemData.g.c; + len = stops.length; + for (i = 0; i < len; i += 1) { + stop = stops[i]; + stop.setAttribute('offset', cValues[i * 4] + '%'); + stop.setAttribute('stop-color', 'rgb(' + cValues[i * 4 + 1] + ',' + cValues[i * 4 + 2] + ',' + cValues[i * 4 + 3] + ')'); + } + } + if (hasOpacity && (itemData.g._omdf || isFirstFrame)) { + var oValues = itemData.g.o; + if (itemData.g._collapsable) { + stops = itemData.cst; + } else { + stops = itemData.ost; + } + len = stops.length; + for (i = 0; i < len; i += 1) { + stop = stops[i]; + if (!itemData.g._collapsable) { + stop.setAttribute('offset', oValues[i * 2] + '%'); + } + stop.setAttribute('stop-opacity', oValues[i * 2 + 1]); + } + } + if (styleData.t === 1) { + if (itemData.e._mdf || isFirstFrame) { + gfill.setAttribute('x2', pt2[0]); + gfill.setAttribute('y2', pt2[1]); + if (hasOpacity && !itemData.g._collapsable) { + itemData.of.setAttribute('x2', pt2[0]); + itemData.of.setAttribute('y2', pt2[1]); + } + } + } else { + var rad; + if (itemData.s._mdf || itemData.e._mdf || isFirstFrame) { + rad = Math.sqrt(Math.pow(pt1[0] - pt2[0], 2) + Math.pow(pt1[1] - pt2[1], 2)); + gfill.setAttribute('r', rad); + if (hasOpacity && !itemData.g._collapsable) { + itemData.of.setAttribute('r', rad); + } + } + if (itemData.e._mdf || itemData.h._mdf || itemData.a._mdf || isFirstFrame) { + if (!rad) { + rad = Math.sqrt(Math.pow(pt1[0] - pt2[0], 2) + Math.pow(pt1[1] - pt2[1], 2)); + } + var ang = Math.atan2(pt2[1] - pt1[1], pt2[0] - pt1[0]); + + var percent = itemData.h.v >= 1 ? 0.99 : itemData.h.v <= -1 ? -0.99 : itemData.h.v; + var dist = rad * percent; + var x = Math.cos(ang + itemData.a.v) * dist + pt1[0]; + var y = Math.sin(ang + itemData.a.v) * dist + pt1[1]; + gfill.setAttribute('fx', x); + gfill.setAttribute('fy', y); + if (hasOpacity && !itemData.g._collapsable) { + itemData.of.setAttribute('fx', x); + itemData.of.setAttribute('fy', y); + } + } + //gfill.setAttribute('fy','200'); + } + }; + + function renderStroke(styleData, itemData, isFirstFrame) { + var styleElem = itemData.style; + var d = itemData.d; + if (d && (d._mdf || isFirstFrame) && d.dashStr) { + styleElem.pElem.setAttribute('stroke-dasharray', d.dashStr); + styleElem.pElem.setAttribute('stroke-dashoffset', d.dashoffset[0]); + } + if (itemData.c && (itemData.c._mdf || isFirstFrame)) { + styleElem.pElem.setAttribute('stroke', 'rgb(' + bm_floor(itemData.c.v[0]) + ',' + bm_floor(itemData.c.v[1]) + ',' + bm_floor(itemData.c.v[2]) + ')'); + } + if (itemData.o._mdf || isFirstFrame) { + styleElem.pElem.setAttribute('stroke-opacity', itemData.o.v); + } + if (itemData.w._mdf || isFirstFrame) { + styleElem.pElem.setAttribute('stroke-width', itemData.w.v); + if (styleElem.msElem) { + styleElem.msElem.setAttribute('stroke-width', itemData.w.v); + } + } + }; + + return ob; + }()) + function ShapeTransformManager() { + this.sequences = {}; + this.sequenceList = []; + this.transform_key_count = 0; + } + + ShapeTransformManager.prototype = { + addTransformSequence: function (transforms) { + var i, len = transforms.length; + var key = '_'; + for (i = 0; i < len; i += 1) { + key += transforms[i].transform.key + '_'; + } + var sequence = this.sequences[key]; + if (!sequence) { + sequence = { + transforms: [].concat(transforms), + finalTransform: new Matrix(), + _mdf: false + }; + this.sequences[key] = sequence; + this.sequenceList.push(sequence); + } + return sequence; + }, + processSequence: function (sequence, isFirstFrame) { + var i = 0, len = sequence.transforms.length, _mdf = isFirstFrame; + while (i < len && !isFirstFrame) { + if (sequence.transforms[i].transform.mProps._mdf) { + _mdf = true; + break; + } + i += 1 + } + if (_mdf) { + var props; + sequence.finalTransform.reset(); + for (i = len - 1; i >= 0; i -= 1) { + props = sequence.transforms[i].transform.mProps.v.props; + sequence.finalTransform.transform(props[0], props[1], props[2], props[3], props[4], props[5], props[6], props[7], props[8], props[9], props[10], props[11], props[12], props[13], props[14], props[15]); + } + } + sequence._mdf = _mdf; + + }, + processSequences: function (isFirstFrame) { + var i, len = this.sequenceList.length; + for (i = 0; i < len; i += 1) { + this.processSequence(this.sequenceList[i], isFirstFrame); + } + + }, + getNewKey: function () { + return '_' + this.transform_key_count++; + } + } + function CVShapeData(element, data, styles, transformsManager) { + this.styledShapes = []; + this.tr = [0, 0, 0, 0, 0, 0]; + var ty = 4; + if (data.ty == 'rc') { + ty = 5; + } else if (data.ty == 'el') { + ty = 6; + } else if (data.ty == 'sr') { + ty = 7; + } + this.sh = ShapePropertyFactory.getShapeProp(element, data, ty, element); + var i, len = styles.length, styledShape; + for (i = 0; i < len; i += 1) { + if (!styles[i].closed) { + styledShape = { + transforms: transformsManager.addTransformSequence(styles[i].transforms), + trNodes: [] + } + this.styledShapes.push(styledShape); + styles[i].elements.push(styledShape); + } + } + } + + CVShapeData.prototype.setAsAnimated = SVGShapeData.prototype.setAsAnimated; + function BaseElement() { + } + + BaseElement.prototype = { + checkMasks: function () { + if (!this.data.hasMask) { + return false; + } + var i = 0, len = this.data.masksProperties.length; + while (i < len) { + if ((this.data.masksProperties[i].mode !== 'n' && this.data.masksProperties[i].cl !== false)) { + return true; + } + i += 1; + } + return false; + }, + initExpressions: function () { + this.layerInterface = LayerExpressionInterface(this); + if (this.data.hasMask && this.maskManager) { + this.layerInterface.registerMaskInterface(this.maskManager); + } + var effectsInterface = EffectsExpressionInterface.createEffectsInterface(this, this.layerInterface); + this.layerInterface.registerEffectsInterface(effectsInterface); + + if (this.data.ty === 0 || this.data.xt) { + this.compInterface = CompExpressionInterface(this); + } else if (this.data.ty === 4) { + this.layerInterface.shapeInterface = ShapeExpressionInterface(this.shapesData, this.itemsData, this.layerInterface); + this.layerInterface.content = this.layerInterface.shapeInterface; + } else if (this.data.ty === 5) { + this.layerInterface.textInterface = TextExpressionInterface(this); + this.layerInterface.text = this.layerInterface.textInterface; + } + }, + setBlendMode: function () { + var blendModeValue = getBlendMode(this.data.bm); + var elem = this.baseElement || this.layerElement; + + elem.style['mix-blend-mode'] = blendModeValue; + }, + initBaseData: function (data, globalData, comp) { + this.globalData = globalData; + this.comp = comp; + this.data = data; + this.layerId = createElementID(); + + //Stretch factor for old animations missing this property. + if (!this.data.sr) { + this.data.sr = 1; + } + // effects manager + this.effectsManager = new EffectsManager(this.data, this, this.dynamicProperties); + + }, + getType: function () { + return this.type; + } + , sourceRectAtTime: function () { } + } + function NullElement(data, globalData, comp) { + this.initFrame(); + this.initBaseData(data, globalData, comp); + this.initFrame(); + this.initTransform(data, globalData, comp); + this.initHierarchy(); + } + + NullElement.prototype.prepareFrame = function (num) { + this.prepareProperties(num, true); + }; + + NullElement.prototype.renderFrame = function () { + }; + + NullElement.prototype.getBaseElement = function () { + return null; + }; + + NullElement.prototype.destroy = function () { + }; + + NullElement.prototype.sourceRectAtTime = function () { + }; + + NullElement.prototype.hide = function () { + }; + + extendPrototype([BaseElement, TransformElement, HierarchyElement, FrameElement], NullElement); + + function SVGBaseElement() { + } + + SVGBaseElement.prototype = { + initRendererElement: function () { + this.layerElement = createNS('g'); + }, + createContainerElements: function () { + this.matteElement = createNS('g'); + this.transformedElement = this.layerElement; + this.maskedElement = this.layerElement; + this._sizeChanged = false; + var layerElementParent = null; + //If this layer acts as a mask for the following layer + var filId, fil, gg; + if (this.data.td) { + if (this.data.td == 3 || this.data.td == 1) { + var masker = createNS('mask'); + masker.setAttribute('id', this.layerId); + masker.setAttribute('mask-type', this.data.td == 3 ? 'luminance' : 'alpha'); + masker.appendChild(this.layerElement); + layerElementParent = masker; + this.globalData.defs.appendChild(masker); + // This is only for IE and Edge when mask if of type alpha + if (!featureSupport.maskType && this.data.td == 1) { + masker.setAttribute('mask-type', 'luminance'); + filId = createElementID(); + fil = filtersFactory.createFilter(filId); + this.globalData.defs.appendChild(fil); + fil.appendChild(filtersFactory.createAlphaToLuminanceFilter()); + gg = createNS('g'); + gg.appendChild(this.layerElement); + layerElementParent = gg; + masker.appendChild(gg); + gg.setAttribute('filter', 'url(' + locationHref + '#' + filId + ')'); + } + } else if (this.data.td == 2) { + var maskGroup = createNS('mask'); + maskGroup.setAttribute('id', this.layerId); + maskGroup.setAttribute('mask-type', 'alpha'); + var maskGrouper = createNS('g'); + maskGroup.appendChild(maskGrouper); + filId = createElementID(); + fil = filtersFactory.createFilter(filId); + //// + + // This solution doesn't work on Android when meta tag with viewport attribute is set + /*var feColorMatrix = createNS('feColorMatrix'); + feColorMatrix.setAttribute('type', 'matrix'); + feColorMatrix.setAttribute('color-interpolation-filters', 'sRGB'); + feColorMatrix.setAttribute('values','1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 -1 1'); + fil.appendChild(feColorMatrix);*/ + //// + var feCTr = createNS('feComponentTransfer'); + feCTr.setAttribute('in', 'SourceGraphic'); + fil.appendChild(feCTr); + var feFunc = createNS('feFuncA'); + feFunc.setAttribute('type', 'table'); + feFunc.setAttribute('tableValues', '1.0 0.0'); + feCTr.appendChild(feFunc); + //// + this.globalData.defs.appendChild(fil); + var alphaRect = createNS('rect'); + alphaRect.setAttribute('width', this.comp.data.w); + alphaRect.setAttribute('height', this.comp.data.h); + alphaRect.setAttribute('x', '0'); + alphaRect.setAttribute('y', '0'); + alphaRect.setAttribute('fill', '#ffffff'); + alphaRect.setAttribute('opacity', '0'); + maskGrouper.setAttribute('filter', 'url(' + locationHref + '#' + filId + ')'); + maskGrouper.appendChild(alphaRect); + maskGrouper.appendChild(this.layerElement); + layerElementParent = maskGrouper; + if (!featureSupport.maskType) { + maskGroup.setAttribute('mask-type', 'luminance'); + fil.appendChild(filtersFactory.createAlphaToLuminanceFilter()); + gg = createNS('g'); + maskGrouper.appendChild(alphaRect); + gg.appendChild(this.layerElement); + layerElementParent = gg; + maskGrouper.appendChild(gg); + } + this.globalData.defs.appendChild(maskGroup); + } + } else if (this.data.tt) { + this.matteElement.appendChild(this.layerElement); + layerElementParent = this.matteElement; + this.baseElement = this.matteElement; + } else { + this.baseElement = this.layerElement; + } + if (this.data.ln) { + this.layerElement.setAttribute('id', this.data.ln); + } + if (this.data.cl) { + this.layerElement.setAttribute('class', this.data.cl); + } + //Clipping compositions to hide content that exceeds boundaries. If collapsed transformations is on, component should not be clipped + if (this.data.ty === 0 && !this.data.hd) { + var cp = createNS('clipPath'); + var pt = createNS('path'); + pt.setAttribute('d', 'M0,0 L' + this.data.w + ',0' + ' L' + this.data.w + ',' + this.data.h + ' L0,' + this.data.h + 'z'); + var clipId = createElementID(); + cp.setAttribute('id', clipId); + cp.appendChild(pt); + this.globalData.defs.appendChild(cp); + + if (this.checkMasks()) { + var cpGroup = createNS('g'); + cpGroup.setAttribute('clip-path', 'url(' + locationHref + '#' + clipId + ')'); + cpGroup.appendChild(this.layerElement); + this.transformedElement = cpGroup; + if (layerElementParent) { + layerElementParent.appendChild(this.transformedElement); + } else { + this.baseElement = this.transformedElement; + } + } else { + this.layerElement.setAttribute('clip-path', 'url(' + locationHref + '#' + clipId + ')'); + } + + } + if (this.data.bm !== 0) { + this.setBlendMode(); + } + + }, + renderElement: function () { + if (this.finalTransform._matMdf) { + this.transformedElement.setAttribute('transform', this.finalTransform.mat.to2dCSS()); + } + if (this.finalTransform._opMdf) { + this.transformedElement.setAttribute('opacity', this.finalTransform.mProp.o.v); + } + }, + destroyBaseElement: function () { + this.layerElement = null; + this.matteElement = null; + this.maskManager.destroy(); + }, + getBaseElement: function () { + if (this.data.hd) { + return null; + } + return this.baseElement; + }, + createRenderableComponents: function () { + this.maskManager = new MaskElement(this.data, this, this.globalData); + this.renderableEffectsManager = new SVGEffects(this); + }, + setMatte: function (id) { + if (!this.matteElement) { + return; + } + this.matteElement.setAttribute("mask", "url(" + locationHref + "#" + id + ")"); + } + }; + function IShapeElement() { + } + + IShapeElement.prototype = { + addShapeToModifiers: function (data) { + var i, len = this.shapeModifiers.length; + for (i = 0; i < len; i += 1) { + this.shapeModifiers[i].addShape(data); + } + }, + isShapeInAnimatedModifiers: function (data) { + var i = 0, len = this.shapeModifiers.length; + while (i < len) { + if (this.shapeModifiers[i].isAnimatedWithShape(data)) { + return true; + } + } + return false; + }, + renderModifiers: function () { + if (!this.shapeModifiers.length) { + return; + } + var i, len = this.shapes.length; + for (i = 0; i < len; i += 1) { + this.shapes[i].sh.reset(); + } + + len = this.shapeModifiers.length; + for (i = len - 1; i >= 0; i -= 1) { + this.shapeModifiers[i].processShapes(this._isFirstFrame); + } + }, + lcEnum: { + '1': 'butt', + '2': 'round', + '3': 'square' + }, + ljEnum: { + '1': 'miter', + '2': 'round', + '3': 'bevel' + }, + searchProcessedElement: function (elem) { + var elements = this.processedElements; + var i = 0, len = elements.length; + while (i < len) { + if (elements[i].elem === elem) { + return elements[i].pos; + } + i += 1; + } + return 0; + }, + addProcessedElement: function (elem, pos) { + var elements = this.processedElements; + var i = elements.length; + while (i) { + i -= 1; + if (elements[i].elem === elem) { + elements[i].pos = pos; + return; + } + } + elements.push(new ProcessedElement(elem, pos)); + }, + prepareFrame: function (num) { + this.prepareRenderableFrame(num); + this.prepareProperties(num, this.isInRange); + } + }; + function ITextElement() { + } + + ITextElement.prototype.initElement = function (data, globalData, comp) { + this.lettersChangedFlag = true; + this.initFrame(); + this.initBaseData(data, globalData, comp); + this.textProperty = new TextProperty(this, data.t, this.dynamicProperties); + this.textAnimator = new TextAnimatorProperty(data.t, this.renderType, this); + this.initTransform(data, globalData, comp); + this.initHierarchy(); + this.initRenderable(); + this.initRendererElement(); + this.createContainerElements(); + this.createRenderableComponents(); + this.createContent(); + this.hide(); + this.textAnimator.searchProperties(this.dynamicProperties); + }; + + ITextElement.prototype.prepareFrame = function (num) { + this._mdf = false; + this.prepareRenderableFrame(num); + this.prepareProperties(num, this.isInRange); + if (this.textProperty._mdf || this.textProperty._isFirstFrame) { + this.buildNewText(); + this.textProperty._isFirstFrame = false; + this.textProperty._mdf = false; + } + }; + + ITextElement.prototype.createPathShape = function (matrixHelper, shapes) { + var j, jLen = shapes.length; + var k, kLen, pathNodes; + var shapeStr = ''; + for (j = 0; j < jLen; j += 1) { + pathNodes = shapes[j].ks.k; + shapeStr += buildShapeString(pathNodes, pathNodes.i.length, true, matrixHelper); + } + return shapeStr; + }; + + ITextElement.prototype.updateDocumentData = function (newData, index) { + this.textProperty.updateDocumentData(newData, index); + }; + + ITextElement.prototype.canResizeFont = function (_canResize) { + this.textProperty.canResizeFont(_canResize); + }; + + ITextElement.prototype.setMinimumFontSize = function (_fontSize) { + this.textProperty.setMinimumFontSize(_fontSize); + }; + + ITextElement.prototype.applyTextPropertiesToMatrix = function (documentData, matrixHelper, lineNumber, xPos, yPos) { + if (documentData.ps) { + matrixHelper.translate(documentData.ps[0], documentData.ps[1] + documentData.ascent, 0); + } + matrixHelper.translate(0, -documentData.ls, 0); + switch (documentData.j) { + case 1: + matrixHelper.translate(documentData.justifyOffset + (documentData.boxWidth - documentData.lineWidths[lineNumber]), 0, 0); + break; + case 2: + matrixHelper.translate(documentData.justifyOffset + (documentData.boxWidth - documentData.lineWidths[lineNumber]) / 2, 0, 0); + break; + } + matrixHelper.translate(xPos, yPos, 0); + }; + + + ITextElement.prototype.buildColor = function (colorData) { + return 'rgb(' + Math.round(colorData[0] * 255) + ',' + Math.round(colorData[1] * 255) + ',' + Math.round(colorData[2] * 255) + ')'; + }; + + ITextElement.prototype.emptyProp = new LetterProps(); + + ITextElement.prototype.destroy = function () { + + }; + function ICompElement() { } + + extendPrototype([BaseElement, TransformElement, HierarchyElement, FrameElement, RenderableDOMElement], ICompElement); + + ICompElement.prototype.initElement = function (data, globalData, comp) { + this.initFrame(); + this.initBaseData(data, globalData, comp); + this.initTransform(data, globalData, comp); + this.initRenderable(); + this.initHierarchy(); + this.initRendererElement(); + this.createContainerElements(); + this.createRenderableComponents(); + if (this.data.xt || !globalData.progressiveLoad) { + this.buildAllItems(); + } + this.hide(); + }; + + /*ICompElement.prototype.hide = function(){ + if(!this.hidden){ + this.hideElement(); + var i,len = this.elements.length; + for( i = 0; i < len; i+=1 ){ + if(this.elements[i]){ + this.elements[i].hide(); + } + } + } + };*/ + + ICompElement.prototype.prepareFrame = function (num) { + this._mdf = false; + this.prepareRenderableFrame(num); + this.prepareProperties(num, this.isInRange); + if (!this.isInRange && !this.data.xt) { + return; + } + + if (!this.tm._placeholder) { + var timeRemapped = this.tm.v; + if (timeRemapped === this.data.op) { + timeRemapped = this.data.op - 1; + } + this.renderedFrame = timeRemapped; + } else { + this.renderedFrame = num / this.data.sr; + } + var i, len = this.elements.length; + if (!this.completeLayers) { + this.checkLayers(this.renderedFrame); + } + //This iteration needs to be backwards because of how expressions connect between each other + for (i = len - 1; i >= 0; i -= 1) { + if (this.completeLayers || this.elements[i]) { + this.elements[i].prepareFrame(this.renderedFrame - this.layers[i].st); + if (this.elements[i]._mdf) { + this._mdf = true; + } + } + } + }; + + ICompElement.prototype.renderInnerContent = function () { + var i, len = this.layers.length; + for (i = 0; i < len; i += 1) { + if (this.completeLayers || this.elements[i]) { + this.elements[i].renderFrame(); + } + } + }; + + ICompElement.prototype.setElements = function (elems) { + this.elements = elems; + }; + + ICompElement.prototype.getElements = function () { + return this.elements; + }; + + ICompElement.prototype.destroyElements = function () { + var i, len = this.layers.length; + for (i = 0; i < len; i += 1) { + if (this.elements[i]) { + this.elements[i].destroy(); + } + } + }; + + ICompElement.prototype.destroy = function () { + this.destroyElements(); + this.destroyBaseElement(); + }; + + function IImageElement(data, globalData, comp) { + this.assetData = globalData.getAssetData(data.refId); + this.initElement(data, globalData, comp); + this.sourceRect = { top: 0, left: 0, width: this.assetData.w, height: this.assetData.h }; + } + + extendPrototype([BaseElement, TransformElement, SVGBaseElement, HierarchyElement, FrameElement, RenderableDOMElement], IImageElement); + + IImageElement.prototype.createContent = function () { + + var assetPath = this.globalData.getAssetsPath(this.assetData); + + this.innerElem = createNS('image'); + this.innerElem.setAttribute('width', this.assetData.w + "px"); + this.innerElem.setAttribute('height', this.assetData.h + "px"); + this.innerElem.setAttribute('preserveAspectRatio', this.assetData.pr || this.globalData.renderConfig.imagePreserveAspectRatio); + this.innerElem.setAttributeNS('http://www.w3.org/1999/xlink', 'href', assetPath); + + this.layerElement.appendChild(this.innerElem); + }; + + IImageElement.prototype.sourceRectAtTime = function () { + return this.sourceRect; + } + function ISolidElement(data, globalData, comp) { + this.initElement(data, globalData, comp); + } + extendPrototype([IImageElement], ISolidElement); + + ISolidElement.prototype.createContent = function () { + + var rect = createNS('rect'); + ////rect.style.width = this.data.sw; + ////rect.style.height = this.data.sh; + ////rect.style.fill = this.data.sc; + rect.setAttribute('width', this.data.sw); + rect.setAttribute('height', this.data.sh); + rect.setAttribute('fill', this.data.sc); + this.layerElement.appendChild(rect); + }; + function SVGCompElement(data, globalData, comp) { + this.layers = data.layers; + this.supports3d = true; + this.completeLayers = false; + this.pendingElements = []; + this.elements = this.layers ? createSizedArray(this.layers.length) : []; + //this.layerElement = createNS('g'); + this.initElement(data, globalData, comp); + this.tm = data.tm ? PropertyFactory.getProp(this, data.tm, 0, globalData.frameRate, this) : { _placeholder: true }; + } + + extendPrototype([SVGRenderer, ICompElement, SVGBaseElement], SVGCompElement); + function SVGTextElement(data, globalData, comp) { + this.textSpans = []; + this.renderType = 'svg'; + this.initElement(data, globalData, comp); + } + + extendPrototype([BaseElement, TransformElement, SVGBaseElement, HierarchyElement, FrameElement, RenderableDOMElement, ITextElement], SVGTextElement); + + SVGTextElement.prototype.createContent = function () { + + if (this.data.singleShape && !this.globalData.fontManager.chars) { + this.textContainer = createNS('text'); + } + }; + + SVGTextElement.prototype.buildTextContents = function (textArray) { + var i = 0, len = textArray.length; + var textContents = [], currentTextContent = ''; + while (i < len) { + if (textArray[i] === String.fromCharCode(13) || textArray[i] === String.fromCharCode(3)) { + textContents.push(currentTextContent); + currentTextContent = ''; + } else { + currentTextContent += textArray[i]; + } + i += 1; + } + textContents.push(currentTextContent); + return textContents; + } + + SVGTextElement.prototype.buildNewText = function () { + var i, len; + + var documentData = this.textProperty.currentData; + this.renderedLetters = createSizedArray(documentData ? documentData.l.length : 0); + if (documentData.fc) { + this.layerElement.setAttribute('fill', this.buildColor(documentData.fc)); + } else { + this.layerElement.setAttribute('fill', 'rgba(0,0,0,0)'); + } + if (documentData.sc) { + this.layerElement.setAttribute('stroke', this.buildColor(documentData.sc)); + this.layerElement.setAttribute('stroke-width', documentData.sw); + } + this.layerElement.setAttribute('font-size', documentData.finalSize); + var fontData = this.globalData.fontManager.getFontByName(documentData.f); + if (fontData.fClass) { + this.layerElement.setAttribute('class', fontData.fClass); + } else { + this.layerElement.setAttribute('font-family', fontData.fFamily); + var fWeight = documentData.fWeight, fStyle = documentData.fStyle; + this.layerElement.setAttribute('font-style', fStyle); + this.layerElement.setAttribute('font-weight', fWeight); + } + this.layerElement.setAttribute('aria-label', documentData.t); + + var letters = documentData.l || []; + var usesGlyphs = !!this.globalData.fontManager.chars; + len = letters.length; + + var tSpan; + var matrixHelper = this.mHelper; + var shapes, shapeStr = '', singleShape = this.data.singleShape; + var xPos = 0, yPos = 0, firstLine = true; + var trackingOffset = documentData.tr / 1000 * documentData.finalSize; + if (singleShape && !usesGlyphs && !documentData.sz) { + var tElement = this.textContainer; + var justify = 'start'; + switch (documentData.j) { + case 1: + justify = 'end'; + break; + case 2: + justify = 'middle'; + break; + } + tElement.setAttribute('text-anchor', justify); + tElement.setAttribute('letter-spacing', trackingOffset); + var textContent = this.buildTextContents(documentData.finalText); + len = textContent.length; + yPos = documentData.ps ? documentData.ps[1] + documentData.ascent : 0; + for (i = 0; i < len; i += 1) { + tSpan = this.textSpans[i] || createNS('tspan'); + tSpan.textContent = textContent[i]; + tSpan.setAttribute('x', 0); + tSpan.setAttribute('y', yPos); + tSpan.style.display = 'inherit'; + tElement.appendChild(tSpan); + this.textSpans[i] = tSpan; + yPos += documentData.finalLineHeight; + } + + this.layerElement.appendChild(tElement); + } else { + var cachedSpansLength = this.textSpans.length; + var shapeData, charData; + for (i = 0; i < len; i += 1) { + if (!usesGlyphs || !singleShape || i === 0) { + tSpan = cachedSpansLength > i ? this.textSpans[i] : createNS(usesGlyphs ? 'path' : 'text'); + if (cachedSpansLength <= i) { + tSpan.setAttribute('stroke-linecap', 'butt'); + tSpan.setAttribute('stroke-linejoin', 'round'); + tSpan.setAttribute('stroke-miterlimit', '4'); + this.textSpans[i] = tSpan; + this.layerElement.appendChild(tSpan); + } + tSpan.style.display = 'inherit'; + } + + matrixHelper.reset(); + matrixHelper.scale(documentData.finalSize / 100, documentData.finalSize / 100); + if (singleShape) { + if (letters[i].n) { + xPos = -trackingOffset; + yPos += documentData.yOffset; + yPos += firstLine ? 1 : 0; + firstLine = false; + } + this.applyTextPropertiesToMatrix(documentData, matrixHelper, letters[i].line, xPos, yPos); + xPos += letters[i].l || 0; + //xPos += letters[i].val === ' ' ? 0 : trackingOffset; + xPos += trackingOffset; + } + if (usesGlyphs) { + charData = this.globalData.fontManager.getCharData(documentData.finalText[i], fontData.fStyle, this.globalData.fontManager.getFontByName(documentData.f).fFamily); + shapeData = charData && charData.data || {}; + shapes = shapeData.shapes ? shapeData.shapes[0].it : []; + if (!singleShape) { + tSpan.setAttribute('d', this.createPathShape(matrixHelper, shapes)); + } else { + shapeStr += this.createPathShape(matrixHelper, shapes); + } + } else { + if (singleShape) { + tSpan.setAttribute("transform", "translate(" + matrixHelper.props[12] + "," + matrixHelper.props[13] + ")"); + } + tSpan.textContent = letters[i].val; + tSpan.setAttributeNS("http://www.w3.org/XML/1998/namespace", "xml:space", "preserve"); + } + // + } + if (singleShape && tSpan) { + tSpan.setAttribute('d', shapeStr); + } + } + while (i < this.textSpans.length) { + this.textSpans[i].style.display = 'none'; + i += 1; + } + + this._sizeChanged = true; + }; + + SVGTextElement.prototype.sourceRectAtTime = function (time) { + this.prepareFrame(this.comp.renderedFrame - this.data.st); + this.renderInnerContent(); + if (this._sizeChanged) { + this._sizeChanged = false; + var textBox = this.layerElement.getBBox(); + this.bbox = { + top: textBox.y, + left: textBox.x, + width: textBox.width, + height: textBox.height + }; + } + return this.bbox; + }; + + SVGTextElement.prototype.renderInnerContent = function () { + + if (!this.data.singleShape) { + this.textAnimator.getMeasures(this.textProperty.currentData, this.lettersChangedFlag); + if (this.lettersChangedFlag || this.textAnimator.lettersChangedFlag) { + this._sizeChanged = true; + var i, len; + var renderedLetters = this.textAnimator.renderedLetters; + + var letters = this.textProperty.currentData.l; + + len = letters.length; + var renderedLetter, textSpan; + for (i = 0; i < len; i += 1) { + if (letters[i].n) { + continue; + } + renderedLetter = renderedLetters[i]; + textSpan = this.textSpans[i]; + if (renderedLetter._mdf.m) { + textSpan.setAttribute('transform', renderedLetter.m); + } + if (renderedLetter._mdf.o) { + textSpan.setAttribute('opacity', renderedLetter.o); + } + if (renderedLetter._mdf.sw) { + textSpan.setAttribute('stroke-width', renderedLetter.sw); + } + if (renderedLetter._mdf.sc) { + textSpan.setAttribute('stroke', renderedLetter.sc); + } + if (renderedLetter._mdf.fc) { + textSpan.setAttribute('fill', renderedLetter.fc); + } + } + } + } + }; + + function SVGShapeElement(data, globalData, comp) { + //List of drawable elements + this.shapes = []; + // Full shape data + this.shapesData = data.shapes; + //List of styles that will be applied to shapes + this.stylesList = []; + //List of modifiers that will be applied to shapes + this.shapeModifiers = []; + //List of items in shape tree + this.itemsData = []; + //List of items in previous shape tree + this.processedElements = []; + // List of animated components + this.animatedContents = []; + this.initElement(data, globalData, comp); + //Moving any property that doesn't get too much access after initialization because of v8 way of handling more than 10 properties. + // List of elements that have been created + this.prevViewData = []; + //Moving any property that doesn't get too much access after initialization because of v8 way of handling more than 10 properties. + } + + extendPrototype([BaseElement, TransformElement, SVGBaseElement, IShapeElement, HierarchyElement, FrameElement, RenderableDOMElement], SVGShapeElement); + + SVGShapeElement.prototype.initSecondaryElement = function () { + }; + + SVGShapeElement.prototype.identityMatrix = new Matrix(); + + SVGShapeElement.prototype.buildExpressionInterface = function () { }; + + SVGShapeElement.prototype.createContent = function () { + this.searchShapes(this.shapesData, this.itemsData, this.prevViewData, this.layerElement, 0, [], true); + this.filterUniqueShapes(); + }; + + /* + This method searches for multiple shapes that affect a single element and one of them is animated + */ + SVGShapeElement.prototype.filterUniqueShapes = function () { + var i, len = this.shapes.length, shape; + var j, jLen = this.stylesList.length; + var style, count = 0; + var tempShapes = []; + var areAnimated = false; + for (j = 0; j < jLen; j += 1) { + style = this.stylesList[j]; + areAnimated = false; + tempShapes.length = 0; + for (i = 0; i < len; i += 1) { + shape = this.shapes[i]; + if (shape.styles.indexOf(style) !== -1) { + tempShapes.push(shape); + areAnimated = shape._isAnimated || areAnimated; + } + } + if (tempShapes.length > 1 && areAnimated) { + this.setShapesAsAnimated(tempShapes); + } + } + } + + SVGShapeElement.prototype.setShapesAsAnimated = function (shapes) { + var i, len = shapes.length; + for (i = 0; i < len; i += 1) { + shapes[i].setAsAnimated(); + } + } + + SVGShapeElement.prototype.createStyleElement = function (data, level) { + //TODO: prevent drawing of hidden styles + var elementData; + var styleOb = new SVGStyleData(data, level); + + var pathElement = styleOb.pElem; + if (data.ty === 'st') { + elementData = new SVGStrokeStyleData(this, data, styleOb); + } else if (data.ty === 'fl') { + elementData = new SVGFillStyleData(this, data, styleOb); + } else if (data.ty === 'gf' || data.ty === 'gs') { + var gradientConstructor = data.ty === 'gf' ? SVGGradientFillStyleData : SVGGradientStrokeStyleData; + elementData = new gradientConstructor(this, data, styleOb); + this.globalData.defs.appendChild(elementData.gf); + if (elementData.maskId) { + this.globalData.defs.appendChild(elementData.ms); + this.globalData.defs.appendChild(elementData.of); + pathElement.setAttribute('mask', 'url(' + locationHref + '#' + elementData.maskId + ')'); + } + } + + if (data.ty === 'st' || data.ty === 'gs') { + pathElement.setAttribute('stroke-linecap', this.lcEnum[data.lc] || 'round'); + pathElement.setAttribute('stroke-linejoin', this.ljEnum[data.lj] || 'round'); + pathElement.setAttribute('fill-opacity', '0'); + if (data.lj === 1) { + pathElement.setAttribute('stroke-miterlimit', data.ml); + } + } + + if (data.r === 2) { + pathElement.setAttribute('fill-rule', 'evenodd'); + } + + if (data.ln) { + pathElement.setAttribute('id', data.ln); + } + if (data.cl) { + pathElement.setAttribute('class', data.cl); + } + if (data.bm) { + pathElement.style['mix-blend-mode'] = getBlendMode(data.bm); + } + this.stylesList.push(styleOb); + this.addToAnimatedContents(data, elementData); + return elementData; + }; + + SVGShapeElement.prototype.createGroupElement = function (data) { + var elementData = new ShapeGroupData(); + if (data.ln) { + elementData.gr.setAttribute('id', data.ln); + } + if (data.cl) { + elementData.gr.setAttribute('class', data.cl); + } + if (data.bm) { + elementData.gr.style['mix-blend-mode'] = getBlendMode(data.bm); + } + return elementData; + }; + + SVGShapeElement.prototype.createTransformElement = function (data, container) { + var transformProperty = TransformPropertyFactory.getTransformProperty(this, data, this); + var elementData = new SVGTransformData(transformProperty, transformProperty.o, container); + this.addToAnimatedContents(data, elementData); + return elementData; + }; + + SVGShapeElement.prototype.createShapeElement = function (data, ownTransformers, level) { + var ty = 4; + if (data.ty === 'rc') { + ty = 5; + } else if (data.ty === 'el') { + ty = 6; + } else if (data.ty === 'sr') { + ty = 7; + } + var shapeProperty = ShapePropertyFactory.getShapeProp(this, data, ty, this); + var elementData = new SVGShapeData(ownTransformers, level, shapeProperty); + this.shapes.push(elementData); + this.addShapeToModifiers(elementData); + this.addToAnimatedContents(data, elementData); + return elementData; + }; + + SVGShapeElement.prototype.addToAnimatedContents = function (data, element) { + var i = 0, len = this.animatedContents.length; + while (i < len) { + if (this.animatedContents[i].element === element) { + return; + } + i += 1; + } + this.animatedContents.push({ + fn: SVGElementsRenderer.createRenderFunction(data), + element: element, + data: data + }); + }; + + SVGShapeElement.prototype.setElementStyles = function (elementData) { + var arr = elementData.styles; + var j, jLen = this.stylesList.length; + for (j = 0; j < jLen; j += 1) { + if (!this.stylesList[j].closed) { + arr.push(this.stylesList[j]); + } + } + }; + + SVGShapeElement.prototype.reloadShapes = function () { + this._isFirstFrame = true; + var i, len = this.itemsData.length; + for (i = 0; i < len; i += 1) { + this.prevViewData[i] = this.itemsData[i]; + } + this.searchShapes(this.shapesData, this.itemsData, this.prevViewData, this.layerElement, 0, [], true); + this.filterUniqueShapes(); + len = this.dynamicProperties.length; + for (i = 0; i < len; i += 1) { + this.dynamicProperties[i].getValue(); + } + this.renderModifiers(); + }; + + SVGShapeElement.prototype.searchShapes = function (arr, itemsData, prevViewData, container, level, transformers, render) { + var ownTransformers = [].concat(transformers); + var i, len = arr.length - 1; + var j, jLen; + var ownStyles = [], ownModifiers = [], styleOb, currentTransform, modifier, processedPos; + for (i = len; i >= 0; i -= 1) { + processedPos = this.searchProcessedElement(arr[i]); + if (!processedPos) { + arr[i]._render = render; + } else { + itemsData[i] = prevViewData[processedPos - 1]; + } + if (arr[i].ty == 'fl' || arr[i].ty == 'st' || arr[i].ty == 'gf' || arr[i].ty == 'gs') { + if (!processedPos) { + itemsData[i] = this.createStyleElement(arr[i], level); + } else { + itemsData[i].style.closed = false; + } + if (arr[i]._render) { + container.appendChild(itemsData[i].style.pElem); + } + ownStyles.push(itemsData[i].style); + } else if (arr[i].ty == 'gr') { + if (!processedPos) { + itemsData[i] = this.createGroupElement(arr[i]); + } else { + jLen = itemsData[i].it.length; + for (j = 0; j < jLen; j += 1) { + itemsData[i].prevViewData[j] = itemsData[i].it[j]; + } + } + this.searchShapes(arr[i].it, itemsData[i].it, itemsData[i].prevViewData, itemsData[i].gr, level + 1, ownTransformers, render); + if (arr[i]._render) { + container.appendChild(itemsData[i].gr); + } + } else if (arr[i].ty == 'tr') { + if (!processedPos) { + itemsData[i] = this.createTransformElement(arr[i], container); + } + currentTransform = itemsData[i].transform; + ownTransformers.push(currentTransform); + } else if (arr[i].ty == 'sh' || arr[i].ty == 'rc' || arr[i].ty == 'el' || arr[i].ty == 'sr') { + if (!processedPos) { + itemsData[i] = this.createShapeElement(arr[i], ownTransformers, level); + } + this.setElementStyles(itemsData[i]); + + } else if (arr[i].ty == 'tm' || arr[i].ty == 'rd' || arr[i].ty == 'ms') { + if (!processedPos) { + modifier = ShapeModifiers.getModifier(arr[i].ty); + modifier.init(this, arr[i]); + itemsData[i] = modifier; + this.shapeModifiers.push(modifier); + } else { + modifier = itemsData[i]; + modifier.closed = false; + } + ownModifiers.push(modifier); + } else if (arr[i].ty == 'rp') { + if (!processedPos) { + modifier = ShapeModifiers.getModifier(arr[i].ty); + itemsData[i] = modifier; + modifier.init(this, arr, i, itemsData); + this.shapeModifiers.push(modifier); + render = false; + } else { + modifier = itemsData[i]; + modifier.closed = true; + } + ownModifiers.push(modifier); + } + this.addProcessedElement(arr[i], i + 1); + } + len = ownStyles.length; + for (i = 0; i < len; i += 1) { + ownStyles[i].closed = true; + } + len = ownModifiers.length; + for (i = 0; i < len; i += 1) { + ownModifiers[i].closed = true; + } + }; + + SVGShapeElement.prototype.renderInnerContent = function () { + this.renderModifiers(); + var i, len = this.stylesList.length; + for (i = 0; i < len; i += 1) { + this.stylesList[i].reset(); + } + this.renderShape(); + + for (i = 0; i < len; i += 1) { + if (this.stylesList[i]._mdf || this._isFirstFrame) { + if (this.stylesList[i].msElem) { + this.stylesList[i].msElem.setAttribute('d', this.stylesList[i].d); + //Adding M0 0 fixes same mask bug on all browsers + this.stylesList[i].d = 'M0 0' + this.stylesList[i].d; + } + this.stylesList[i].pElem.setAttribute('d', this.stylesList[i].d || 'M0 0'); + } + } + }; + + SVGShapeElement.prototype.renderShape = function () { + var i, len = this.animatedContents.length; + var animatedContent; + for (i = 0; i < len; i += 1) { + animatedContent = this.animatedContents[i]; + if ((this._isFirstFrame || animatedContent.element._isAnimated) && animatedContent.data !== true) { + animatedContent.fn(animatedContent.data, animatedContent.element, this._isFirstFrame); + } + } + } + + SVGShapeElement.prototype.destroy = function () { + this.destroyBaseElement(); + this.shapesData = null; + this.itemsData = null; + }; + + function SVGTintFilter(filter, filterManager) { + this.filterManager = filterManager; + var feColorMatrix = createNS('feColorMatrix'); + feColorMatrix.setAttribute('type', 'matrix'); + feColorMatrix.setAttribute('color-interpolation-filters', 'linearRGB'); + feColorMatrix.setAttribute('values', '0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0'); + feColorMatrix.setAttribute('result', 'f1'); + filter.appendChild(feColorMatrix); + feColorMatrix = createNS('feColorMatrix'); + feColorMatrix.setAttribute('type', 'matrix'); + feColorMatrix.setAttribute('color-interpolation-filters', 'sRGB'); + feColorMatrix.setAttribute('values', '1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0'); + feColorMatrix.setAttribute('result', 'f2'); + filter.appendChild(feColorMatrix); + this.matrixFilter = feColorMatrix; + if (filterManager.effectElements[2].p.v !== 100 || filterManager.effectElements[2].p.k) { + var feMerge = createNS('feMerge'); + filter.appendChild(feMerge); + var feMergeNode; + feMergeNode = createNS('feMergeNode'); + feMergeNode.setAttribute('in', 'SourceGraphic'); + feMerge.appendChild(feMergeNode); + feMergeNode = createNS('feMergeNode'); + feMergeNode.setAttribute('in', 'f2'); + feMerge.appendChild(feMergeNode); + } + } + + SVGTintFilter.prototype.renderFrame = function (forceRender) { + if (forceRender || this.filterManager._mdf) { + var colorBlack = this.filterManager.effectElements[0].p.v; + var colorWhite = this.filterManager.effectElements[1].p.v; + var opacity = this.filterManager.effectElements[2].p.v / 100; + this.matrixFilter.setAttribute('values', (colorWhite[0] - colorBlack[0]) + ' 0 0 0 ' + colorBlack[0] + ' ' + (colorWhite[1] - colorBlack[1]) + ' 0 0 0 ' + colorBlack[1] + ' ' + (colorWhite[2] - colorBlack[2]) + ' 0 0 0 ' + colorBlack[2] + ' 0 0 0 ' + opacity + ' 0'); + } + }; + function SVGFillFilter(filter, filterManager) { + this.filterManager = filterManager; + var feColorMatrix = createNS('feColorMatrix'); + feColorMatrix.setAttribute('type', 'matrix'); + feColorMatrix.setAttribute('color-interpolation-filters', 'sRGB'); + feColorMatrix.setAttribute('values', '1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0'); + filter.appendChild(feColorMatrix); + this.matrixFilter = feColorMatrix; + } + SVGFillFilter.prototype.renderFrame = function (forceRender) { + if (forceRender || this.filterManager._mdf) { + var color = this.filterManager.effectElements[2].p.v; + var opacity = this.filterManager.effectElements[6].p.v; + this.matrixFilter.setAttribute('values', '0 0 0 0 ' + color[0] + ' 0 0 0 0 ' + color[1] + ' 0 0 0 0 ' + color[2] + ' 0 0 0 ' + opacity + ' 0'); + } + }; + function SVGGaussianBlurEffect(filter, filterManager) { + // Outset the filter region by 100% on all sides to accommodate blur expansion. + filter.setAttribute('x', '-100%'); + filter.setAttribute('y', '-100%'); + filter.setAttribute('width', '300%'); + filter.setAttribute('height', '300%'); + + this.filterManager = filterManager; + var feGaussianBlur = createNS('feGaussianBlur'); + filter.appendChild(feGaussianBlur); + this.feGaussianBlur = feGaussianBlur; + } + + SVGGaussianBlurEffect.prototype.renderFrame = function (forceRender) { + if (forceRender || this.filterManager._mdf) { + // Empirical value, matching AE's blur appearance. + var kBlurrinessToSigma = 0.3; + var sigma = this.filterManager.effectElements[0].p.v * kBlurrinessToSigma; + + // Dimensions mapping: + // + // 1 -> horizontal & vertical + // 2 -> horizontal only + // 3 -> vertical only + // + var dimensions = this.filterManager.effectElements[1].p.v; + var sigmaX = (dimensions == 3) ? 0 : sigma; + var sigmaY = (dimensions == 2) ? 0 : sigma; + + this.feGaussianBlur.setAttribute('stdDeviation', sigmaX + " " + sigmaY); + + // Repeat edges mapping: + // + // 0 -> off -> duplicate + // 1 -> on -> wrap + var edgeMode = (this.filterManager.effectElements[2].p.v == 1) ? 'wrap' : 'duplicate'; + this.feGaussianBlur.setAttribute('edgeMode', edgeMode); + } + } + function SVGStrokeEffect(elem, filterManager) { + this.initialized = false; + this.filterManager = filterManager; + this.elem = elem; + this.paths = []; + } + + SVGStrokeEffect.prototype.initialize = function () { + + var elemChildren = this.elem.layerElement.children || this.elem.layerElement.childNodes; + var path, groupPath, i, len; + if (this.filterManager.effectElements[1].p.v === 1) { + len = this.elem.maskManager.masksProperties.length; + i = 0; + } else { + i = this.filterManager.effectElements[0].p.v - 1; + len = i + 1; + } + groupPath = createNS('g'); + groupPath.setAttribute('fill', 'none'); + groupPath.setAttribute('stroke-linecap', 'round'); + groupPath.setAttribute('stroke-dashoffset', 1); + for (i; i < len; i += 1) { + path = createNS('path'); + groupPath.appendChild(path); + this.paths.push({ p: path, m: i }); + } + if (this.filterManager.effectElements[10].p.v === 3) { + var mask = createNS('mask'); + var id = createElementID(); + mask.setAttribute('id', id); + mask.setAttribute('mask-type', 'alpha'); + mask.appendChild(groupPath); + this.elem.globalData.defs.appendChild(mask); + var g = createNS('g'); + g.setAttribute('mask', 'url(' + locationHref + '#' + id + ')'); + while (elemChildren[0]) { + g.appendChild(elemChildren[0]); + } + this.elem.layerElement.appendChild(g); + this.masker = mask; + groupPath.setAttribute('stroke', '#fff'); + } else if (this.filterManager.effectElements[10].p.v === 1 || this.filterManager.effectElements[10].p.v === 2) { + if (this.filterManager.effectElements[10].p.v === 2) { + elemChildren = this.elem.layerElement.children || this.elem.layerElement.childNodes; + while (elemChildren.length) { + this.elem.layerElement.removeChild(elemChildren[0]); + } + } + this.elem.layerElement.appendChild(groupPath); + this.elem.layerElement.removeAttribute('mask'); + groupPath.setAttribute('stroke', '#fff'); + } + this.initialized = true; + this.pathMasker = groupPath; + }; + + SVGStrokeEffect.prototype.renderFrame = function (forceRender) { + if (!this.initialized) { + this.initialize(); + } + var i, len = this.paths.length; + var mask, path; + for (i = 0; i < len; i += 1) { + if (this.paths[i].m === -1) { + continue; + } + mask = this.elem.maskManager.viewData[this.paths[i].m]; + path = this.paths[i].p; + if (forceRender || this.filterManager._mdf || mask.prop._mdf) { + path.setAttribute('d', mask.lastPath); + } + if (forceRender || this.filterManager.effectElements[9].p._mdf || this.filterManager.effectElements[4].p._mdf || this.filterManager.effectElements[7].p._mdf || this.filterManager.effectElements[8].p._mdf || mask.prop._mdf) { + var dasharrayValue; + if (this.filterManager.effectElements[7].p.v !== 0 || this.filterManager.effectElements[8].p.v !== 100) { + var s = Math.min(this.filterManager.effectElements[7].p.v, this.filterManager.effectElements[8].p.v) / 100; + var e = Math.max(this.filterManager.effectElements[7].p.v, this.filterManager.effectElements[8].p.v) / 100; + var l = path.getTotalLength(); + dasharrayValue = '0 0 0 ' + l * s + ' '; + var lineLength = l * (e - s); + var segment = 1 + this.filterManager.effectElements[4].p.v * 2 * this.filterManager.effectElements[9].p.v / 100; + var units = Math.floor(lineLength / segment); + var j; + for (j = 0; j < units; j += 1) { + dasharrayValue += '1 ' + this.filterManager.effectElements[4].p.v * 2 * this.filterManager.effectElements[9].p.v / 100 + ' '; + } + dasharrayValue += '0 ' + l * 10 + ' 0 0'; + } else { + dasharrayValue = '1 ' + this.filterManager.effectElements[4].p.v * 2 * this.filterManager.effectElements[9].p.v / 100; + } + path.setAttribute('stroke-dasharray', dasharrayValue); + } + } + if (forceRender || this.filterManager.effectElements[4].p._mdf) { + this.pathMasker.setAttribute('stroke-width', this.filterManager.effectElements[4].p.v * 2); + } + + if (forceRender || this.filterManager.effectElements[6].p._mdf) { + this.pathMasker.setAttribute('opacity', this.filterManager.effectElements[6].p.v); + } + if (this.filterManager.effectElements[10].p.v === 1 || this.filterManager.effectElements[10].p.v === 2) { + if (forceRender || this.filterManager.effectElements[3].p._mdf) { + var color = this.filterManager.effectElements[3].p.v; + this.pathMasker.setAttribute('stroke', 'rgb(' + bm_floor(color[0] * 255) + ',' + bm_floor(color[1] * 255) + ',' + bm_floor(color[2] * 255) + ')'); + } + } + }; + function SVGTritoneFilter(filter, filterManager) { + this.filterManager = filterManager; + var feColorMatrix = createNS('feColorMatrix'); + feColorMatrix.setAttribute('type', 'matrix'); + feColorMatrix.setAttribute('color-interpolation-filters', 'linearRGB'); + feColorMatrix.setAttribute('values', '0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0'); + feColorMatrix.setAttribute('result', 'f1'); + filter.appendChild(feColorMatrix); + var feComponentTransfer = createNS('feComponentTransfer'); + feComponentTransfer.setAttribute('color-interpolation-filters', 'sRGB'); + filter.appendChild(feComponentTransfer); + this.matrixFilter = feComponentTransfer; + var feFuncR = createNS('feFuncR'); + feFuncR.setAttribute('type', 'table'); + feComponentTransfer.appendChild(feFuncR); + this.feFuncR = feFuncR; + var feFuncG = createNS('feFuncG'); + feFuncG.setAttribute('type', 'table'); + feComponentTransfer.appendChild(feFuncG); + this.feFuncG = feFuncG; + var feFuncB = createNS('feFuncB'); + feFuncB.setAttribute('type', 'table'); + feComponentTransfer.appendChild(feFuncB); + this.feFuncB = feFuncB; + } + + SVGTritoneFilter.prototype.renderFrame = function (forceRender) { + if (forceRender || this.filterManager._mdf) { + var color1 = this.filterManager.effectElements[0].p.v; + var color2 = this.filterManager.effectElements[1].p.v; + var color3 = this.filterManager.effectElements[2].p.v; + var tableR = color3[0] + ' ' + color2[0] + ' ' + color1[0]; + var tableG = color3[1] + ' ' + color2[1] + ' ' + color1[1]; + var tableB = color3[2] + ' ' + color2[2] + ' ' + color1[2]; + this.feFuncR.setAttribute('tableValues', tableR); + this.feFuncG.setAttribute('tableValues', tableG); + this.feFuncB.setAttribute('tableValues', tableB); + //var opacity = this.filterManager.effectElements[2].p.v/100; + //this.matrixFilter.setAttribute('values',(colorWhite[0]- colorBlack[0])+' 0 0 0 '+ colorBlack[0] +' '+ (colorWhite[1]- colorBlack[1]) +' 0 0 0 '+ colorBlack[1] +' '+ (colorWhite[2]- colorBlack[2]) +' 0 0 0 '+ colorBlack[2] +' 0 0 0 ' + opacity + ' 0'); + } + }; + function SVGProLevelsFilter(filter, filterManager) { + this.filterManager = filterManager; + var effectElements = this.filterManager.effectElements; + var feComponentTransfer = createNS('feComponentTransfer'); + var feFuncR, feFuncG, feFuncB; + + if (effectElements[10].p.k || effectElements[10].p.v !== 0 || effectElements[11].p.k || effectElements[11].p.v !== 1 || effectElements[12].p.k || effectElements[12].p.v !== 1 || effectElements[13].p.k || effectElements[13].p.v !== 0 || effectElements[14].p.k || effectElements[14].p.v !== 1) { + this.feFuncR = this.createFeFunc('feFuncR', feComponentTransfer); + } + if (effectElements[17].p.k || effectElements[17].p.v !== 0 || effectElements[18].p.k || effectElements[18].p.v !== 1 || effectElements[19].p.k || effectElements[19].p.v !== 1 || effectElements[20].p.k || effectElements[20].p.v !== 0 || effectElements[21].p.k || effectElements[21].p.v !== 1) { + this.feFuncG = this.createFeFunc('feFuncG', feComponentTransfer); + } + if (effectElements[24].p.k || effectElements[24].p.v !== 0 || effectElements[25].p.k || effectElements[25].p.v !== 1 || effectElements[26].p.k || effectElements[26].p.v !== 1 || effectElements[27].p.k || effectElements[27].p.v !== 0 || effectElements[28].p.k || effectElements[28].p.v !== 1) { + this.feFuncB = this.createFeFunc('feFuncB', feComponentTransfer); + } + if (effectElements[31].p.k || effectElements[31].p.v !== 0 || effectElements[32].p.k || effectElements[32].p.v !== 1 || effectElements[33].p.k || effectElements[33].p.v !== 1 || effectElements[34].p.k || effectElements[34].p.v !== 0 || effectElements[35].p.k || effectElements[35].p.v !== 1) { + this.feFuncA = this.createFeFunc('feFuncA', feComponentTransfer); + } + + if (this.feFuncR || this.feFuncG || this.feFuncB || this.feFuncA) { + feComponentTransfer.setAttribute('color-interpolation-filters', 'sRGB'); + filter.appendChild(feComponentTransfer); + feComponentTransfer = createNS('feComponentTransfer'); + } + + if (effectElements[3].p.k || effectElements[3].p.v !== 0 || effectElements[4].p.k || effectElements[4].p.v !== 1 || effectElements[5].p.k || effectElements[5].p.v !== 1 || effectElements[6].p.k || effectElements[6].p.v !== 0 || effectElements[7].p.k || effectElements[7].p.v !== 1) { + + feComponentTransfer.setAttribute('color-interpolation-filters', 'sRGB'); + filter.appendChild(feComponentTransfer); + this.feFuncRComposed = this.createFeFunc('feFuncR', feComponentTransfer); + this.feFuncGComposed = this.createFeFunc('feFuncG', feComponentTransfer); + this.feFuncBComposed = this.createFeFunc('feFuncB', feComponentTransfer); + } + } + + SVGProLevelsFilter.prototype.createFeFunc = function (type, feComponentTransfer) { + var feFunc = createNS(type); + feFunc.setAttribute('type', 'table'); + feComponentTransfer.appendChild(feFunc); + return feFunc; + }; + + SVGProLevelsFilter.prototype.getTableValue = function (inputBlack, inputWhite, gamma, outputBlack, outputWhite) { + var cnt = 0; + var segments = 256; + var perc; + var min = Math.min(inputBlack, inputWhite); + var max = Math.max(inputBlack, inputWhite); + var table = Array.call(null, { length: segments }); + var colorValue; + var pos = 0; + var outputDelta = outputWhite - outputBlack; + var inputDelta = inputWhite - inputBlack; + while (cnt <= 256) { + perc = cnt / 256; + if (perc <= min) { + colorValue = inputDelta < 0 ? outputWhite : outputBlack; + } else if (perc >= max) { + colorValue = inputDelta < 0 ? outputBlack : outputWhite; + } else { + colorValue = (outputBlack + outputDelta * Math.pow((perc - inputBlack) / inputDelta, 1 / gamma)); + } + table[pos++] = colorValue; + cnt += 256 / (segments - 1); + } + return table.join(' '); + }; + + SVGProLevelsFilter.prototype.renderFrame = function (forceRender) { + if (forceRender || this.filterManager._mdf) { + var val, cnt, perc, bezier; + var effectElements = this.filterManager.effectElements; + if (this.feFuncRComposed && (forceRender || effectElements[3].p._mdf || effectElements[4].p._mdf || effectElements[5].p._mdf || effectElements[6].p._mdf || effectElements[7].p._mdf)) { + val = this.getTableValue(effectElements[3].p.v, effectElements[4].p.v, effectElements[5].p.v, effectElements[6].p.v, effectElements[7].p.v); + this.feFuncRComposed.setAttribute('tableValues', val); + this.feFuncGComposed.setAttribute('tableValues', val); + this.feFuncBComposed.setAttribute('tableValues', val); + } + + + if (this.feFuncR && (forceRender || effectElements[10].p._mdf || effectElements[11].p._mdf || effectElements[12].p._mdf || effectElements[13].p._mdf || effectElements[14].p._mdf)) { + val = this.getTableValue(effectElements[10].p.v, effectElements[11].p.v, effectElements[12].p.v, effectElements[13].p.v, effectElements[14].p.v); + this.feFuncR.setAttribute('tableValues', val); + } + + if (this.feFuncG && (forceRender || effectElements[17].p._mdf || effectElements[18].p._mdf || effectElements[19].p._mdf || effectElements[20].p._mdf || effectElements[21].p._mdf)) { + val = this.getTableValue(effectElements[17].p.v, effectElements[18].p.v, effectElements[19].p.v, effectElements[20].p.v, effectElements[21].p.v); + this.feFuncG.setAttribute('tableValues', val); + } + + if (this.feFuncB && (forceRender || effectElements[24].p._mdf || effectElements[25].p._mdf || effectElements[26].p._mdf || effectElements[27].p._mdf || effectElements[28].p._mdf)) { + val = this.getTableValue(effectElements[24].p.v, effectElements[25].p.v, effectElements[26].p.v, effectElements[27].p.v, effectElements[28].p.v); + this.feFuncB.setAttribute('tableValues', val); + } + + if (this.feFuncA && (forceRender || effectElements[31].p._mdf || effectElements[32].p._mdf || effectElements[33].p._mdf || effectElements[34].p._mdf || effectElements[35].p._mdf)) { + val = this.getTableValue(effectElements[31].p.v, effectElements[32].p.v, effectElements[33].p.v, effectElements[34].p.v, effectElements[35].p.v); + this.feFuncA.setAttribute('tableValues', val); + } + + } + }; + function SVGDropShadowEffect(filter, filterManager) { + var filterSize = filterManager.container.globalData.renderConfig.filterSize + filter.setAttribute('x', filterSize.x); + filter.setAttribute('y', filterSize.y); + filter.setAttribute('width', filterSize.width); + filter.setAttribute('height', filterSize.height); + this.filterManager = filterManager; + + var feGaussianBlur = createNS('feGaussianBlur'); + feGaussianBlur.setAttribute('in', 'SourceAlpha'); + feGaussianBlur.setAttribute('result', 'drop_shadow_1'); + feGaussianBlur.setAttribute('stdDeviation', '0'); + this.feGaussianBlur = feGaussianBlur; + filter.appendChild(feGaussianBlur); + + var feOffset = createNS('feOffset'); + feOffset.setAttribute('dx', '25'); + feOffset.setAttribute('dy', '0'); + feOffset.setAttribute('in', 'drop_shadow_1'); + feOffset.setAttribute('result', 'drop_shadow_2'); + this.feOffset = feOffset; + filter.appendChild(feOffset); + var feFlood = createNS('feFlood'); + feFlood.setAttribute('flood-color', '#00ff00'); + feFlood.setAttribute('flood-opacity', '1'); + feFlood.setAttribute('result', 'drop_shadow_3'); + this.feFlood = feFlood; + filter.appendChild(feFlood); + + var feComposite = createNS('feComposite'); + feComposite.setAttribute('in', 'drop_shadow_3'); + feComposite.setAttribute('in2', 'drop_shadow_2'); + feComposite.setAttribute('operator', 'in'); + feComposite.setAttribute('result', 'drop_shadow_4'); + filter.appendChild(feComposite); + + + var feMerge = createNS('feMerge'); + filter.appendChild(feMerge); + var feMergeNode; + feMergeNode = createNS('feMergeNode'); + feMerge.appendChild(feMergeNode); + feMergeNode = createNS('feMergeNode'); + feMergeNode.setAttribute('in', 'SourceGraphic'); + this.feMergeNode = feMergeNode; + this.feMerge = feMerge; + this.originalNodeAdded = false; + feMerge.appendChild(feMergeNode); + } + + SVGDropShadowEffect.prototype.renderFrame = function (forceRender) { + if (forceRender || this.filterManager._mdf) { + if (forceRender || this.filterManager.effectElements[4].p._mdf) { + this.feGaussianBlur.setAttribute('stdDeviation', this.filterManager.effectElements[4].p.v / 4); + } + if (forceRender || this.filterManager.effectElements[0].p._mdf) { + var col = this.filterManager.effectElements[0].p.v; + this.feFlood.setAttribute('flood-color', rgbToHex(Math.round(col[0] * 255), Math.round(col[1] * 255), Math.round(col[2] * 255))); + } + if (forceRender || this.filterManager.effectElements[1].p._mdf) { + this.feFlood.setAttribute('flood-opacity', this.filterManager.effectElements[1].p.v / 255); + } + if (forceRender || this.filterManager.effectElements[2].p._mdf || this.filterManager.effectElements[3].p._mdf) { + var distance = this.filterManager.effectElements[3].p.v; + var angle = (this.filterManager.effectElements[2].p.v - 90) * degToRads; + var x = distance * Math.cos(angle); + var y = distance * Math.sin(angle); + this.feOffset.setAttribute('dx', x); + this.feOffset.setAttribute('dy', y); + } + /*if(forceRender || this.filterManager.effectElements[5].p._mdf){ + if(this.filterManager.effectElements[5].p.v === 1 && this.originalNodeAdded) { + this.feMerge.removeChild(this.feMergeNode); + this.originalNodeAdded = false; + } else if(this.filterManager.effectElements[5].p.v === 0 && !this.originalNodeAdded) { + this.feMerge.appendChild(this.feMergeNode); + this.originalNodeAdded = true; + } + }*/ + } + }; + var _svgMatteSymbols = []; + + function SVGMatte3Effect(filterElem, filterManager, elem) { + this.initialized = false; + this.filterManager = filterManager; + this.filterElem = filterElem; + this.elem = elem; + elem.matteElement = createNS('g'); + elem.matteElement.appendChild(elem.layerElement); + elem.matteElement.appendChild(elem.transformedElement); + elem.baseElement = elem.matteElement; + } + + SVGMatte3Effect.prototype.findSymbol = function (mask) { + var i = 0, len = _svgMatteSymbols.length; + while (i < len) { + if (_svgMatteSymbols[i] === mask) { + return _svgMatteSymbols[i]; + } + i += 1; + } + return null; + }; + + SVGMatte3Effect.prototype.replaceInParent = function (mask, symbolId) { + var parentNode = mask.layerElement.parentNode; + if (!parentNode) { + return; + } + var children = parentNode.children; + var i = 0, len = children.length; + while (i < len) { + if (children[i] === mask.layerElement) { + break; + } + i += 1; + } + var nextChild; + if (i <= len - 2) { + nextChild = children[i + 1]; + } + var useElem = createNS('use'); + useElem.setAttribute('href', '#' + symbolId); + if (nextChild) { + parentNode.insertBefore(useElem, nextChild); + } else { + parentNode.appendChild(useElem); + } + }; + + SVGMatte3Effect.prototype.setElementAsMask = function (elem, mask) { + if (!this.findSymbol(mask)) { + var symbolId = createElementID(); + var masker = createNS('mask'); + masker.setAttribute('id', mask.layerId); + masker.setAttribute('mask-type', 'alpha'); + _svgMatteSymbols.push(mask); + var defs = elem.globalData.defs; + defs.appendChild(masker); + var symbol = createNS('symbol'); + symbol.setAttribute('id', symbolId); + this.replaceInParent(mask, symbolId); + symbol.appendChild(mask.layerElement); + defs.appendChild(symbol); + var useElem = createNS('use'); + useElem.setAttribute('href', '#' + symbolId); + masker.appendChild(useElem); + mask.data.hd = false; + mask.show(); + } + elem.setMatte(mask.layerId); + }; + + SVGMatte3Effect.prototype.initialize = function () { + var ind = this.filterManager.effectElements[0].p.v; + var elements = this.elem.comp.elements; + var i = 0, len = elements.length; + while (i < len) { + if (elements[i] && elements[i].data.ind === ind) { + this.setElementAsMask(this.elem, elements[i]); + } + i += 1; + } + this.initialized = true; + }; + + SVGMatte3Effect.prototype.renderFrame = function () { + if (!this.initialized) { + this.initialize(); + } + }; + function SVGEffects(elem) { + var i, len = elem.data.ef ? elem.data.ef.length : 0; + var filId = createElementID(); + var fil = filtersFactory.createFilter(filId); + var count = 0; + this.filters = []; + var filterManager; + for (i = 0; i < len; i += 1) { + filterManager = null; + if (elem.data.ef[i].ty === 20) { + count += 1; + filterManager = new SVGTintFilter(fil, elem.effectsManager.effectElements[i]); + } else if (elem.data.ef[i].ty === 21) { + count += 1; + filterManager = new SVGFillFilter(fil, elem.effectsManager.effectElements[i]); + } else if (elem.data.ef[i].ty === 22) { + filterManager = new SVGStrokeEffect(elem, elem.effectsManager.effectElements[i]); + } else if (elem.data.ef[i].ty === 23) { + count += 1; + filterManager = new SVGTritoneFilter(fil, elem.effectsManager.effectElements[i]); + } else if (elem.data.ef[i].ty === 24) { + count += 1; + filterManager = new SVGProLevelsFilter(fil, elem.effectsManager.effectElements[i]); + } else if (elem.data.ef[i].ty === 25) { + count += 1; + filterManager = new SVGDropShadowEffect(fil, elem.effectsManager.effectElements[i]); + } else if (elem.data.ef[i].ty === 28) { + //count += 1; + filterManager = new SVGMatte3Effect(fil, elem.effectsManager.effectElements[i], elem); + } else if (elem.data.ef[i].ty === 29) { + count += 1; + filterManager = new SVGGaussianBlurEffect(fil, elem.effectsManager.effectElements[i]); + } + if (filterManager) { + this.filters.push(filterManager); + } + } + if (count) { + elem.globalData.defs.appendChild(fil); + elem.layerElement.setAttribute('filter', 'url(' + locationHref + '#' + filId + ')'); + } + if (this.filters.length) { + elem.addRenderableComponent(this); + } + } + + SVGEffects.prototype.renderFrame = function (_isFirstFrame) { + var i, len = this.filters.length; + for (i = 0; i < len; i += 1) { + this.filters[i].renderFrame(_isFirstFrame); + } + }; + function CVContextData() { + this.saved = []; + this.cArrPos = 0; + this.cTr = new Matrix(); + this.cO = 1; + var i, len = 15; + this.savedOp = createTypedArray('float32', len); + for (i = 0; i < len; i += 1) { + this.saved[i] = createTypedArray('float32', 16); + } + this._length = len; + } + + CVContextData.prototype.duplicate = function () { + var newLength = this._length * 2; + var currentSavedOp = this.savedOp; + this.savedOp = createTypedArray('float32', newLength); + this.savedOp.set(currentSavedOp); + var i = 0; + for (i = this._length; i < newLength; i += 1) { + this.saved[i] = createTypedArray('float32', 16); + } + this._length = newLength; + }; + + CVContextData.prototype.reset = function () { + this.cArrPos = 0; + this.cTr.reset(); + this.cO = 1; + }; + function CVBaseElement() { + } + + CVBaseElement.prototype = { + createElements: function () { }, + initRendererElement: function () { }, + createContainerElements: function () { + this.canvasContext = this.globalData.canvasContext; + this.renderableEffectsManager = new CVEffects(this); + }, + createContent: function () { }, + setBlendMode: function () { + var globalData = this.globalData; + if (globalData.blendMode !== this.data.bm) { + globalData.blendMode = this.data.bm; + var blendModeValue = getBlendMode(this.data.bm); + globalData.canvasContext.globalCompositeOperation = blendModeValue; + } + }, + createRenderableComponents: function () { + this.maskManager = new CVMaskElement(this.data, this); + }, + hideElement: function () { + if (!this.hidden && (!this.isInRange || this.isTransparent)) { + this.hidden = true; + } + }, + showElement: function () { + if (this.isInRange && !this.isTransparent) { + this.hidden = false; + this._isFirstFrame = true; + this.maskManager._isFirstFrame = true; + } + }, + renderFrame: function () { + if (this.hidden || this.data.hd) { + return; + } + this.renderTransform(); + this.renderRenderable(); + this.setBlendMode(); + var forceRealStack = this.data.ty === 0; + this.globalData.renderer.save(forceRealStack); + this.globalData.renderer.ctxTransform(this.finalTransform.mat.props); + this.globalData.renderer.ctxOpacity(this.finalTransform.mProp.o.v); + this.renderInnerContent(); + this.globalData.renderer.restore(forceRealStack); + if (this.maskManager.hasMasks) { + this.globalData.renderer.restore(true); + } + if (this._isFirstFrame) { + this._isFirstFrame = false; + } + }, + destroy: function () { + this.canvasContext = null; + this.data = null; + this.globalData = null; + this.maskManager.destroy(); + }, + mHelper: new Matrix() + }; + CVBaseElement.prototype.hide = CVBaseElement.prototype.hideElement; + CVBaseElement.prototype.show = CVBaseElement.prototype.showElement; + + function CVImageElement(data, globalData, comp) { + this.assetData = globalData.getAssetData(data.refId); + this.img = globalData.imageLoader.getImage(this.assetData); + this.initElement(data, globalData, comp); + } + extendPrototype([BaseElement, TransformElement, CVBaseElement, HierarchyElement, FrameElement, RenderableElement], CVImageElement); + + CVImageElement.prototype.initElement = SVGShapeElement.prototype.initElement; + CVImageElement.prototype.prepareFrame = IImageElement.prototype.prepareFrame; + + CVImageElement.prototype.createContent = function () { + + if (this.img.width && (this.assetData.w !== this.img.width || this.assetData.h !== this.img.height)) { + var canvas = createTag('canvas'); + canvas.width = this.assetData.w; + canvas.height = this.assetData.h; + var ctx = canvas.getContext('2d'); + + var imgW = this.img.width; + var imgH = this.img.height; + var imgRel = imgW / imgH; + var canvasRel = this.assetData.w / this.assetData.h; + var widthCrop, heightCrop; + var par = this.assetData.pr || this.globalData.renderConfig.imagePreserveAspectRatio; + if ((imgRel > canvasRel && par === 'xMidYMid slice') || (imgRel < canvasRel && par !== 'xMidYMid slice')) { + heightCrop = imgH; + widthCrop = heightCrop * canvasRel; + } else { + widthCrop = imgW; + heightCrop = widthCrop / canvasRel; + } + ctx.drawImage(this.img, (imgW - widthCrop) / 2, (imgH - heightCrop) / 2, widthCrop, heightCrop, 0, 0, this.assetData.w, this.assetData.h); + this.img = canvas; + } + + }; + + CVImageElement.prototype.renderInnerContent = function (parentMatrix) { + this.canvasContext.drawImage(this.img, 0, 0); + }; + + CVImageElement.prototype.destroy = function () { + this.img = null; + }; + function CVCompElement(data, globalData, comp) { + this.completeLayers = false; + this.layers = data.layers; + this.pendingElements = []; + this.elements = createSizedArray(this.layers.length); + this.initElement(data, globalData, comp); + this.tm = data.tm ? PropertyFactory.getProp(this, data.tm, 0, globalData.frameRate, this) : { _placeholder: true }; + } + + extendPrototype([CanvasRenderer, ICompElement, CVBaseElement], CVCompElement); + + CVCompElement.prototype.renderInnerContent = function () { + var ctx = this.canvasContext; + ctx.beginPath(); + ctx.moveTo(0, 0); + ctx.lineTo(this.data.w, 0); + ctx.lineTo(this.data.w, this.data.h); + ctx.lineTo(0, this.data.h); + ctx.lineTo(0, 0); + ctx.clip(); + var i, len = this.layers.length; + for (i = len - 1; i >= 0; i -= 1) { + if (this.completeLayers || this.elements[i]) { + this.elements[i].renderFrame(); + } + } + }; + + CVCompElement.prototype.destroy = function () { + var i, len = this.layers.length; + for (i = len - 1; i >= 0; i -= 1) { + if (this.elements[i]) { + this.elements[i].destroy(); + } + } + this.layers = null; + this.elements = null; + }; + + function CVMaskElement(data, element) { + this.data = data; + this.element = element; + this.masksProperties = this.data.masksProperties || []; + this.viewData = createSizedArray(this.masksProperties.length); + var i, len = this.masksProperties.length, hasMasks = false; + for (i = 0; i < len; i++) { + if (this.masksProperties[i].mode !== 'n') { + hasMasks = true; + } + this.viewData[i] = ShapePropertyFactory.getShapeProp(this.element, this.masksProperties[i], 3); + } + this.hasMasks = hasMasks; + if (hasMasks) { + this.element.addRenderableComponent(this); + } + } + + CVMaskElement.prototype.renderFrame = function () { + if (!this.hasMasks) { + return; + } + var transform = this.element.finalTransform.mat; + var ctx = this.element.canvasContext; + var i, len = this.masksProperties.length; + var pt, pts, data; + ctx.beginPath(); + for (i = 0; i < len; i++) { + if (this.masksProperties[i].mode !== 'n') { + if (this.masksProperties[i].inv) { + ctx.moveTo(0, 0); + ctx.lineTo(this.element.globalData.compSize.w, 0); + ctx.lineTo(this.element.globalData.compSize.w, this.element.globalData.compSize.h); + ctx.lineTo(0, this.element.globalData.compSize.h); + ctx.lineTo(0, 0); + } + data = this.viewData[i].v; + pt = transform.applyToPointArray(data.v[0][0], data.v[0][1], 0); + ctx.moveTo(pt[0], pt[1]); + var j, jLen = data._length; + for (j = 1; j < jLen; j++) { + pts = transform.applyToTriplePoints(data.o[j - 1], data.i[j], data.v[j]); + ctx.bezierCurveTo(pts[0], pts[1], pts[2], pts[3], pts[4], pts[5]); + } + pts = transform.applyToTriplePoints(data.o[j - 1], data.i[0], data.v[0]); + ctx.bezierCurveTo(pts[0], pts[1], pts[2], pts[3], pts[4], pts[5]); + } + } + this.element.globalData.renderer.save(true); + ctx.clip(); + }; + + CVMaskElement.prototype.getMaskProperty = MaskElement.prototype.getMaskProperty; + + CVMaskElement.prototype.destroy = function () { + this.element = null; + }; + function CVShapeElement(data, globalData, comp) { + this.shapes = []; + this.shapesData = data.shapes; + this.stylesList = []; + this.itemsData = []; + this.prevViewData = []; + this.shapeModifiers = []; + this.processedElements = []; + this.transformsManager = new ShapeTransformManager(); + this.initElement(data, globalData, comp); + } + + extendPrototype([BaseElement, TransformElement, CVBaseElement, IShapeElement, HierarchyElement, FrameElement, RenderableElement], CVShapeElement); + + CVShapeElement.prototype.initElement = RenderableDOMElement.prototype.initElement; + + CVShapeElement.prototype.transformHelper = { opacity: 1, _opMdf: false }; + + CVShapeElement.prototype.dashResetter = []; + + CVShapeElement.prototype.createContent = function () { + this.searchShapes(this.shapesData, this.itemsData, this.prevViewData, true, []); + }; + + CVShapeElement.prototype.createStyleElement = function (data, transforms) { + var styleElem = { + data: data, + type: data.ty, + preTransforms: this.transformsManager.addTransformSequence(transforms), + transforms: [], + elements: [], + closed: data.hd === true + }; + var elementData = {}; + if (data.ty == 'fl' || data.ty == 'st') { + elementData.c = PropertyFactory.getProp(this, data.c, 1, 255, this); + if (!elementData.c.k) { + styleElem.co = 'rgb(' + bm_floor(elementData.c.v[0]) + ',' + bm_floor(elementData.c.v[1]) + ',' + bm_floor(elementData.c.v[2]) + ')'; + } + } else if (data.ty === 'gf' || data.ty === 'gs') { + elementData.s = PropertyFactory.getProp(this, data.s, 1, null, this); + elementData.e = PropertyFactory.getProp(this, data.e, 1, null, this); + elementData.h = PropertyFactory.getProp(this, data.h || { k: 0 }, 0, 0.01, this); + elementData.a = PropertyFactory.getProp(this, data.a || { k: 0 }, 0, degToRads, this); + elementData.g = new GradientProperty(this, data.g, this); + } + elementData.o = PropertyFactory.getProp(this, data.o, 0, 0.01, this); + if (data.ty == 'st' || data.ty == 'gs') { + styleElem.lc = this.lcEnum[data.lc] || 'round'; + styleElem.lj = this.ljEnum[data.lj] || 'round'; + if (data.lj == 1) { + styleElem.ml = data.ml; + } + elementData.w = PropertyFactory.getProp(this, data.w, 0, null, this); + if (!elementData.w.k) { + styleElem.wi = elementData.w.v; + } + if (data.d) { + var d = new DashProperty(this, data.d, 'canvas', this); + elementData.d = d; + if (!elementData.d.k) { + styleElem.da = elementData.d.dashArray; + styleElem.do = elementData.d.dashoffset[0]; + } + } + } else { + styleElem.r = data.r === 2 ? 'evenodd' : 'nonzero'; + } + this.stylesList.push(styleElem); + elementData.style = styleElem; + return elementData; + }; + + CVShapeElement.prototype.createGroupElement = function (data) { + var elementData = { + it: [], + prevViewData: [] + }; + return elementData; + }; + + CVShapeElement.prototype.createTransformElement = function (data) { + var elementData = { + transform: { + opacity: 1, + _opMdf: false, + key: this.transformsManager.getNewKey(), + op: PropertyFactory.getProp(this, data.o, 0, 0.01, this), + mProps: TransformPropertyFactory.getTransformProperty(this, data, this) + } + }; + return elementData; + }; + + CVShapeElement.prototype.createShapeElement = function (data) { + var elementData = new CVShapeData(this, data, this.stylesList, this.transformsManager); + + this.shapes.push(elementData); + this.addShapeToModifiers(elementData); + return elementData; + }; + + CVShapeElement.prototype.reloadShapes = function () { + this._isFirstFrame = true; + var i, len = this.itemsData.length; + for (i = 0; i < len; i += 1) { + this.prevViewData[i] = this.itemsData[i]; + } + this.searchShapes(this.shapesData, this.itemsData, this.prevViewData, true, []); + len = this.dynamicProperties.length; + for (i = 0; i < len; i += 1) { + this.dynamicProperties[i].getValue(); + } + this.renderModifiers(); + this.transformsManager.processSequences(this._isFirstFrame); + }; + + CVShapeElement.prototype.addTransformToStyleList = function (transform) { + var i, len = this.stylesList.length; + for (i = 0; i < len; i += 1) { + if (!this.stylesList[i].closed) { + this.stylesList[i].transforms.push(transform); + } + } + } + + CVShapeElement.prototype.removeTransformFromStyleList = function () { + var i, len = this.stylesList.length; + for (i = 0; i < len; i += 1) { + if (!this.stylesList[i].closed) { + this.stylesList[i].transforms.pop(); + } + } + } + + CVShapeElement.prototype.closeStyles = function (styles) { + var i, len = styles.length, j, jLen; + for (i = 0; i < len; i += 1) { + styles[i].closed = true; + } + } + + CVShapeElement.prototype.searchShapes = function (arr, itemsData, prevViewData, shouldRender, transforms) { + var i, len = arr.length - 1; + var j, jLen; + var ownStyles = [], ownModifiers = [], processedPos, modifier, currentTransform; + var ownTransforms = [].concat(transforms); + for (i = len; i >= 0; i -= 1) { + processedPos = this.searchProcessedElement(arr[i]); + if (!processedPos) { + arr[i]._shouldRender = shouldRender; + } else { + itemsData[i] = prevViewData[processedPos - 1]; + } + if (arr[i].ty == 'fl' || arr[i].ty == 'st' || arr[i].ty == 'gf' || arr[i].ty == 'gs') { + if (!processedPos) { + itemsData[i] = this.createStyleElement(arr[i], ownTransforms); + } else { + itemsData[i].style.closed = false; + } + + ownStyles.push(itemsData[i].style); + } else if (arr[i].ty == 'gr') { + if (!processedPos) { + itemsData[i] = this.createGroupElement(arr[i]); + } else { + jLen = itemsData[i].it.length; + for (j = 0; j < jLen; j += 1) { + itemsData[i].prevViewData[j] = itemsData[i].it[j]; + } + } + this.searchShapes(arr[i].it, itemsData[i].it, itemsData[i].prevViewData, shouldRender, ownTransforms); + } else if (arr[i].ty == 'tr') { + if (!processedPos) { + currentTransform = this.createTransformElement(arr[i]); + itemsData[i] = currentTransform; + } + ownTransforms.push(itemsData[i]); + this.addTransformToStyleList(itemsData[i]); + } else if (arr[i].ty == 'sh' || arr[i].ty == 'rc' || arr[i].ty == 'el' || arr[i].ty == 'sr') { + if (!processedPos) { + itemsData[i] = this.createShapeElement(arr[i]); + } + + } else if (arr[i].ty == 'tm' || arr[i].ty == 'rd') { + if (!processedPos) { + modifier = ShapeModifiers.getModifier(arr[i].ty); + modifier.init(this, arr[i]); + itemsData[i] = modifier; + this.shapeModifiers.push(modifier); + } else { + modifier = itemsData[i]; + modifier.closed = false; + } + ownModifiers.push(modifier); + } else if (arr[i].ty == 'rp') { + if (!processedPos) { + modifier = ShapeModifiers.getModifier(arr[i].ty); + itemsData[i] = modifier; + modifier.init(this, arr, i, itemsData); + this.shapeModifiers.push(modifier); + shouldRender = false; + } else { + modifier = itemsData[i]; + modifier.closed = true; + } + ownModifiers.push(modifier); + } + this.addProcessedElement(arr[i], i + 1); + } + this.removeTransformFromStyleList(); + this.closeStyles(ownStyles); + len = ownModifiers.length; + for (i = 0; i < len; i += 1) { + ownModifiers[i].closed = true; + } + }; + + CVShapeElement.prototype.renderInnerContent = function () { + this.transformHelper.opacity = 1; + this.transformHelper._opMdf = false; + this.renderModifiers(); + this.transformsManager.processSequences(this._isFirstFrame); + this.renderShape(this.transformHelper, this.shapesData, this.itemsData, true); + }; + + CVShapeElement.prototype.renderShapeTransform = function (parentTransform, groupTransform) { + var props, groupMatrix; + if (parentTransform._opMdf || groupTransform.op._mdf || this._isFirstFrame) { + groupTransform.opacity = parentTransform.opacity; + groupTransform.opacity *= groupTransform.op.v; + groupTransform._opMdf = true; + } + }; + + CVShapeElement.prototype.drawLayer = function () { + var i, len = this.stylesList.length; + var j, jLen, k, kLen, elems, nodes, renderer = this.globalData.renderer, ctx = this.globalData.canvasContext, type, currentStyle; + for (i = 0; i < len; i += 1) { + currentStyle = this.stylesList[i]; + type = currentStyle.type; + + //Skipping style when + //Stroke width equals 0 + //style should not be rendered (extra unused repeaters) + //current opacity equals 0 + //global opacity equals 0 + if (((type === 'st' || type === 'gs') && currentStyle.wi === 0) || !currentStyle.data._shouldRender || currentStyle.coOp === 0 || this.globalData.currentGlobalAlpha === 0) { + continue; + } + renderer.save(); + elems = currentStyle.elements; + if (type === 'st' || type === 'gs') { + ctx.strokeStyle = type === 'st' ? currentStyle.co : currentStyle.grd; + ctx.lineWidth = currentStyle.wi; + ctx.lineCap = currentStyle.lc; + ctx.lineJoin = currentStyle.lj; + ctx.miterLimit = currentStyle.ml || 0; + } else { + ctx.fillStyle = type === 'fl' ? currentStyle.co : currentStyle.grd; + } + renderer.ctxOpacity(currentStyle.coOp); + if (type !== 'st' && type !== 'gs') { + ctx.beginPath(); + } + renderer.ctxTransform(currentStyle.preTransforms.finalTransform.props); + jLen = elems.length; + for (j = 0; j < jLen; j += 1) { + if (type === 'st' || type === 'gs') { + ctx.beginPath(); + if (currentStyle.da) { + ctx.setLineDash(currentStyle.da); + ctx.lineDashOffset = currentStyle.do; + } + } + nodes = elems[j].trNodes; + kLen = nodes.length; + + for (k = 0; k < kLen; k += 1) { + if (nodes[k].t == 'm') { + ctx.moveTo(nodes[k].p[0], nodes[k].p[1]); + } else if (nodes[k].t == 'c') { + ctx.bezierCurveTo(nodes[k].pts[0], nodes[k].pts[1], nodes[k].pts[2], nodes[k].pts[3], nodes[k].pts[4], nodes[k].pts[5]); + } else { + ctx.closePath(); + } + } + if (type === 'st' || type === 'gs') { + ctx.stroke(); + if (currentStyle.da) { + ctx.setLineDash(this.dashResetter); + } + } + } + if (type !== 'st' && type !== 'gs') { + ctx.fill(currentStyle.r); + } + renderer.restore(); + } + }; + + CVShapeElement.prototype.renderShape = function (parentTransform, items, data, isMain) { + var i, len = items.length - 1; + var groupTransform; + groupTransform = parentTransform; + for (i = len; i >= 0; i -= 1) { + if (items[i].ty == 'tr') { + groupTransform = data[i].transform; + this.renderShapeTransform(parentTransform, groupTransform); + } else if (items[i].ty == 'sh' || items[i].ty == 'el' || items[i].ty == 'rc' || items[i].ty == 'sr') { + this.renderPath(items[i], data[i]); + } else if (items[i].ty == 'fl') { + this.renderFill(items[i], data[i], groupTransform); + } else if (items[i].ty == 'st') { + this.renderStroke(items[i], data[i], groupTransform); + } else if (items[i].ty == 'gf' || items[i].ty == 'gs') { + this.renderGradientFill(items[i], data[i], groupTransform); + } else if (items[i].ty == 'gr') { + this.renderShape(groupTransform, items[i].it, data[i].it); + } else if (items[i].ty == 'tm') { + // + } + } + if (isMain) { + this.drawLayer(); + } + + }; + + CVShapeElement.prototype.renderStyledShape = function (styledShape, shape) { + if (this._isFirstFrame || shape._mdf || styledShape.transforms._mdf) { + var shapeNodes = styledShape.trNodes; + var paths = shape.paths; + var i, len, j, jLen = paths._length; + shapeNodes.length = 0; + var groupTransformMat = styledShape.transforms.finalTransform; + for (j = 0; j < jLen; j += 1) { + var pathNodes = paths.shapes[j]; + if (pathNodes && pathNodes.v) { + len = pathNodes._length; + for (i = 1; i < len; i += 1) { + if (i === 1) { + shapeNodes.push({ + t: 'm', + p: groupTransformMat.applyToPointArray(pathNodes.v[0][0], pathNodes.v[0][1], 0) + }); + } + shapeNodes.push({ + t: 'c', + pts: groupTransformMat.applyToTriplePoints(pathNodes.o[i - 1], pathNodes.i[i], pathNodes.v[i]) + }); + } + if (len === 1) { + shapeNodes.push({ + t: 'm', + p: groupTransformMat.applyToPointArray(pathNodes.v[0][0], pathNodes.v[0][1], 0) + }); + } + if (pathNodes.c && len) { + shapeNodes.push({ + t: 'c', + pts: groupTransformMat.applyToTriplePoints(pathNodes.o[i - 1], pathNodes.i[0], pathNodes.v[0]) + }); + shapeNodes.push({ + t: 'z' + }); + } + } + } + styledShape.trNodes = shapeNodes; + } + } + + CVShapeElement.prototype.renderPath = function (pathData, itemData) { + if (pathData.hd !== true && pathData._shouldRender) { + var i, len = itemData.styledShapes.length; + for (i = 0; i < len; i += 1) { + this.renderStyledShape(itemData.styledShapes[i], itemData.sh); + } + } + }; + + CVShapeElement.prototype.renderFill = function (styleData, itemData, groupTransform) { + var styleElem = itemData.style; + + if (itemData.c._mdf || this._isFirstFrame) { + styleElem.co = 'rgb(' + + bm_floor(itemData.c.v[0]) + ',' + + bm_floor(itemData.c.v[1]) + ',' + + bm_floor(itemData.c.v[2]) + ')'; + } + if (itemData.o._mdf || groupTransform._opMdf || this._isFirstFrame) { + styleElem.coOp = itemData.o.v * groupTransform.opacity; + } + }; + + CVShapeElement.prototype.renderGradientFill = function (styleData, itemData, groupTransform) { + var styleElem = itemData.style; + if (!styleElem.grd || itemData.g._mdf || itemData.s._mdf || itemData.e._mdf || (styleData.t !== 1 && (itemData.h._mdf || itemData.a._mdf))) { + var ctx = this.globalData.canvasContext; + var grd; + var pt1 = itemData.s.v, pt2 = itemData.e.v; + if (styleData.t === 1) { + grd = ctx.createLinearGradient(pt1[0], pt1[1], pt2[0], pt2[1]); + } else { + var rad = Math.sqrt(Math.pow(pt1[0] - pt2[0], 2) + Math.pow(pt1[1] - pt2[1], 2)); + var ang = Math.atan2(pt2[1] - pt1[1], pt2[0] - pt1[0]); + + var percent = itemData.h.v >= 1 ? 0.99 : itemData.h.v <= -1 ? -0.99 : itemData.h.v; + var dist = rad * percent; + var x = Math.cos(ang + itemData.a.v) * dist + pt1[0]; + var y = Math.sin(ang + itemData.a.v) * dist + pt1[1]; + var grd = ctx.createRadialGradient(x, y, 0, pt1[0], pt1[1], rad); + } + + var i, len = styleData.g.p; + var cValues = itemData.g.c; + var opacity = 1; + + for (i = 0; i < len; i += 1) { + if (itemData.g._hasOpacity && itemData.g._collapsable) { + opacity = itemData.g.o[i * 2 + 1]; + } + grd.addColorStop(cValues[i * 4] / 100, 'rgba(' + cValues[i * 4 + 1] + ',' + cValues[i * 4 + 2] + ',' + cValues[i * 4 + 3] + ',' + opacity + ')'); + } + styleElem.grd = grd; + } + styleElem.coOp = itemData.o.v * groupTransform.opacity; + + }; + + CVShapeElement.prototype.renderStroke = function (styleData, itemData, groupTransform) { + var styleElem = itemData.style; + var d = itemData.d; + if (d && (d._mdf || this._isFirstFrame)) { + styleElem.da = d.dashArray; + styleElem.do = d.dashoffset[0]; + } + if (itemData.c._mdf || this._isFirstFrame) { + styleElem.co = 'rgb(' + bm_floor(itemData.c.v[0]) + ',' + bm_floor(itemData.c.v[1]) + ',' + bm_floor(itemData.c.v[2]) + ')'; + } + if (itemData.o._mdf || groupTransform._opMdf || this._isFirstFrame) { + styleElem.coOp = itemData.o.v * groupTransform.opacity; + } + if (itemData.w._mdf || this._isFirstFrame) { + styleElem.wi = itemData.w.v; + } + }; + + + CVShapeElement.prototype.destroy = function () { + this.shapesData = null; + this.globalData = null; + this.canvasContext = null; + this.stylesList.length = 0; + this.itemsData.length = 0; + }; + + + function CVSolidElement(data, globalData, comp) { + this.initElement(data, globalData, comp); + } + extendPrototype([BaseElement, TransformElement, CVBaseElement, HierarchyElement, FrameElement, RenderableElement], CVSolidElement); + + CVSolidElement.prototype.initElement = SVGShapeElement.prototype.initElement; + CVSolidElement.prototype.prepareFrame = IImageElement.prototype.prepareFrame; + + CVSolidElement.prototype.renderInnerContent = function () { + var ctx = this.canvasContext; + ctx.fillStyle = this.data.sc; + ctx.fillRect(0, 0, this.data.sw, this.data.sh); + // + }; + function CVTextElement(data, globalData, comp) { + this.textSpans = []; + this.yOffset = 0; + this.fillColorAnim = false; + this.strokeColorAnim = false; + this.strokeWidthAnim = false; + this.stroke = false; + this.fill = false; + this.justifyOffset = 0; + this.currentRender = null; + this.renderType = 'canvas'; + this.values = { + fill: 'rgba(0,0,0,0)', + stroke: 'rgba(0,0,0,0)', + sWidth: 0, + fValue: '' + }; + this.initElement(data, globalData, comp); + } + extendPrototype([BaseElement, TransformElement, CVBaseElement, HierarchyElement, FrameElement, RenderableElement, ITextElement], CVTextElement); + + CVTextElement.prototype.tHelper = createTag('canvas').getContext('2d'); + + CVTextElement.prototype.buildNewText = function () { + var documentData = this.textProperty.currentData; + this.renderedLetters = createSizedArray(documentData.l ? documentData.l.length : 0); + + var hasFill = false; + if (documentData.fc) { + hasFill = true; + this.values.fill = this.buildColor(documentData.fc); + } else { + this.values.fill = 'rgba(0,0,0,0)'; + } + this.fill = hasFill; + var hasStroke = false; + if (documentData.sc) { + hasStroke = true; + this.values.stroke = this.buildColor(documentData.sc); + this.values.sWidth = documentData.sw; + } + var fontData = this.globalData.fontManager.getFontByName(documentData.f); + var i, len; + var letters = documentData.l; + var matrixHelper = this.mHelper; + this.stroke = hasStroke; + this.values.fValue = documentData.finalSize + 'px ' + this.globalData.fontManager.getFontByName(documentData.f).fFamily; + len = documentData.finalText.length; + //this.tHelper.font = this.values.fValue; + var charData, shapeData, k, kLen, shapes, j, jLen, pathNodes, commands, pathArr, singleShape = this.data.singleShape; + var trackingOffset = documentData.tr / 1000 * documentData.finalSize; + var xPos = 0, yPos = 0, firstLine = true; + var cnt = 0; + for (i = 0; i < len; i += 1) { + charData = this.globalData.fontManager.getCharData(documentData.finalText[i], fontData.fStyle, this.globalData.fontManager.getFontByName(documentData.f).fFamily); + shapeData = charData && charData.data || {}; + matrixHelper.reset(); + if (singleShape && letters[i].n) { + xPos = -trackingOffset; + yPos += documentData.yOffset; + yPos += firstLine ? 1 : 0; + firstLine = false; + } + + shapes = shapeData.shapes ? shapeData.shapes[0].it : []; + jLen = shapes.length; + matrixHelper.scale(documentData.finalSize / 100, documentData.finalSize / 100); + if (singleShape) { + this.applyTextPropertiesToMatrix(documentData, matrixHelper, letters[i].line, xPos, yPos); + } + commands = createSizedArray(jLen); + for (j = 0; j < jLen; j += 1) { + kLen = shapes[j].ks.k.i.length; + pathNodes = shapes[j].ks.k; + pathArr = []; + for (k = 1; k < kLen; k += 1) { + if (k == 1) { + pathArr.push(matrixHelper.applyToX(pathNodes.v[0][0], pathNodes.v[0][1], 0), matrixHelper.applyToY(pathNodes.v[0][0], pathNodes.v[0][1], 0)); + } + pathArr.push(matrixHelper.applyToX(pathNodes.o[k - 1][0], pathNodes.o[k - 1][1], 0), matrixHelper.applyToY(pathNodes.o[k - 1][0], pathNodes.o[k - 1][1], 0), matrixHelper.applyToX(pathNodes.i[k][0], pathNodes.i[k][1], 0), matrixHelper.applyToY(pathNodes.i[k][0], pathNodes.i[k][1], 0), matrixHelper.applyToX(pathNodes.v[k][0], pathNodes.v[k][1], 0), matrixHelper.applyToY(pathNodes.v[k][0], pathNodes.v[k][1], 0)); + } + pathArr.push(matrixHelper.applyToX(pathNodes.o[k - 1][0], pathNodes.o[k - 1][1], 0), matrixHelper.applyToY(pathNodes.o[k - 1][0], pathNodes.o[k - 1][1], 0), matrixHelper.applyToX(pathNodes.i[0][0], pathNodes.i[0][1], 0), matrixHelper.applyToY(pathNodes.i[0][0], pathNodes.i[0][1], 0), matrixHelper.applyToX(pathNodes.v[0][0], pathNodes.v[0][1], 0), matrixHelper.applyToY(pathNodes.v[0][0], pathNodes.v[0][1], 0)); + commands[j] = pathArr; + } + if (singleShape) { + xPos += letters[i].l; + xPos += trackingOffset; + } + if (this.textSpans[cnt]) { + this.textSpans[cnt].elem = commands; + } else { + this.textSpans[cnt] = { elem: commands }; + } + cnt += 1; + } + }; + + CVTextElement.prototype.renderInnerContent = function () { + var ctx = this.canvasContext; + var finalMat = this.finalTransform.mat.props; + ctx.font = this.values.fValue; + ctx.lineCap = 'butt'; + ctx.lineJoin = 'miter'; + ctx.miterLimit = 4; + + if (!this.data.singleShape) { + this.textAnimator.getMeasures(this.textProperty.currentData, this.lettersChangedFlag); + } + + var i, len, j, jLen, k, kLen; + var renderedLetters = this.textAnimator.renderedLetters; + + var letters = this.textProperty.currentData.l; + + len = letters.length; + var renderedLetter; + var lastFill = null, lastStroke = null, lastStrokeW = null, commands, pathArr; + for (i = 0; i < len; i += 1) { + if (letters[i].n) { + continue; + } + renderedLetter = renderedLetters[i]; + if (renderedLetter) { + this.globalData.renderer.save(); + this.globalData.renderer.ctxTransform(renderedLetter.p); + this.globalData.renderer.ctxOpacity(renderedLetter.o); + } + if (this.fill) { + if (renderedLetter && renderedLetter.fc) { + if (lastFill !== renderedLetter.fc) { + lastFill = renderedLetter.fc; + ctx.fillStyle = renderedLetter.fc; + } + } else if (lastFill !== this.values.fill) { + lastFill = this.values.fill; + ctx.fillStyle = this.values.fill; + } + commands = this.textSpans[i].elem; + jLen = commands.length; + this.globalData.canvasContext.beginPath(); + for (j = 0; j < jLen; j += 1) { + pathArr = commands[j]; + kLen = pathArr.length; + this.globalData.canvasContext.moveTo(pathArr[0], pathArr[1]); + for (k = 2; k < kLen; k += 6) { + this.globalData.canvasContext.bezierCurveTo(pathArr[k], pathArr[k + 1], pathArr[k + 2], pathArr[k + 3], pathArr[k + 4], pathArr[k + 5]); + } + } + this.globalData.canvasContext.closePath(); + this.globalData.canvasContext.fill(); + ///ctx.fillText(this.textSpans[i].val,0,0); + } + if (this.stroke) { + if (renderedLetter && renderedLetter.sw) { + if (lastStrokeW !== renderedLetter.sw) { + lastStrokeW = renderedLetter.sw; + ctx.lineWidth = renderedLetter.sw; + } + } else if (lastStrokeW !== this.values.sWidth) { + lastStrokeW = this.values.sWidth; + ctx.lineWidth = this.values.sWidth; + } + if (renderedLetter && renderedLetter.sc) { + if (lastStroke !== renderedLetter.sc) { + lastStroke = renderedLetter.sc; + ctx.strokeStyle = renderedLetter.sc; + } + } else if (lastStroke !== this.values.stroke) { + lastStroke = this.values.stroke; + ctx.strokeStyle = this.values.stroke; + } + commands = this.textSpans[i].elem; + jLen = commands.length; + this.globalData.canvasContext.beginPath(); + for (j = 0; j < jLen; j += 1) { + pathArr = commands[j]; + kLen = pathArr.length; + this.globalData.canvasContext.moveTo(pathArr[0], pathArr[1]); + for (k = 2; k < kLen; k += 6) { + this.globalData.canvasContext.bezierCurveTo(pathArr[k], pathArr[k + 1], pathArr[k + 2], pathArr[k + 3], pathArr[k + 4], pathArr[k + 5]); + } + } + this.globalData.canvasContext.closePath(); + this.globalData.canvasContext.stroke(); + ///ctx.strokeText(letters[i].val,0,0); + } + if (renderedLetter) { + this.globalData.renderer.restore(); + } + } + }; + function CVEffects() { + + } + CVEffects.prototype.renderFrame = function () { }; + function HBaseElement(data, globalData, comp) { } + HBaseElement.prototype = { + checkBlendMode: function () { }, + initRendererElement: function () { + this.baseElement = createTag(this.data.tg || 'div'); + if (this.data.hasMask) { + this.svgElement = createNS('svg'); + this.layerElement = createNS('g'); + this.maskedElement = this.layerElement; + this.svgElement.appendChild(this.layerElement); + this.baseElement.appendChild(this.svgElement); + } else { + this.layerElement = this.baseElement; + } + styleDiv(this.baseElement); + }, + createContainerElements: function () { + this.renderableEffectsManager = new CVEffects(this); + this.transformedElement = this.baseElement; + this.maskedElement = this.layerElement; + if (this.data.ln) { + this.layerElement.setAttribute('id', this.data.ln); + } + if (this.data.cl) { + this.layerElement.setAttribute('class', this.data.cl); + } + if (this.data.bm !== 0) { + this.setBlendMode(); + } + }, + renderElement: function () { + if (this.finalTransform._matMdf) { + this.transformedElement.style.transform = this.transformedElement.style.webkitTransform = this.finalTransform.mat.toCSS(); + } + if (this.finalTransform._opMdf) { + this.transformedElement.style.opacity = this.finalTransform.mProp.o.v; + } + }, + renderFrame: function () { + //If it is exported as hidden (data.hd === true) no need to render + //If it is not visible no need to render + if (this.data.hd || this.hidden) { + return; + } + this.renderTransform(); + this.renderRenderable(); + this.renderElement(); + this.renderInnerContent(); + if (this._isFirstFrame) { + this._isFirstFrame = false; + } + }, + destroy: function () { + this.layerElement = null; + this.transformedElement = null; + if (this.matteElement) { + this.matteElement = null; + } + if (this.maskManager) { + this.maskManager.destroy(); + this.maskManager = null; + } + }, + createRenderableComponents: function () { + this.maskManager = new MaskElement(this.data, this, this.globalData); + }, + addEffects: function () { + }, + setMatte: function () { } + }; + HBaseElement.prototype.getBaseElement = SVGBaseElement.prototype.getBaseElement; + HBaseElement.prototype.destroyBaseElement = HBaseElement.prototype.destroy; + HBaseElement.prototype.buildElementParenting = HybridRenderer.prototype.buildElementParenting; + function HSolidElement(data, globalData, comp) { + this.initElement(data, globalData, comp); + } + extendPrototype([BaseElement, TransformElement, HBaseElement, HierarchyElement, FrameElement, RenderableDOMElement], HSolidElement); + + HSolidElement.prototype.createContent = function () { + var rect; + if (this.data.hasMask) { + rect = createNS('rect'); + rect.setAttribute('width', this.data.sw); + rect.setAttribute('height', this.data.sh); + rect.setAttribute('fill', this.data.sc); + this.svgElement.setAttribute('width', this.data.sw); + this.svgElement.setAttribute('height', this.data.sh); + } else { + rect = createTag('div'); + rect.style.width = this.data.sw + 'px'; + rect.style.height = this.data.sh + 'px'; + rect.style.backgroundColor = this.data.sc; + } + this.layerElement.appendChild(rect); + }; + + function HCompElement(data, globalData, comp) { + this.layers = data.layers; + this.supports3d = !data.hasMask; + this.completeLayers = false; + this.pendingElements = []; + this.elements = this.layers ? createSizedArray(this.layers.length) : []; + this.initElement(data, globalData, comp); + this.tm = data.tm ? PropertyFactory.getProp(this, data.tm, 0, globalData.frameRate, this) : { _placeholder: true }; + } + + extendPrototype([HybridRenderer, ICompElement, HBaseElement], HCompElement); + HCompElement.prototype._createBaseContainerElements = HCompElement.prototype.createContainerElements; + + HCompElement.prototype.createContainerElements = function () { + this._createBaseContainerElements(); + //divElement.style.clip = 'rect(0px, '+this.data.w+'px, '+this.data.h+'px, 0px)'; + if (this.data.hasMask) { + this.svgElement.setAttribute('width', this.data.w); + this.svgElement.setAttribute('height', this.data.h); + this.transformedElement = this.baseElement; + } else { + this.transformedElement = this.layerElement; + } + }; + + HCompElement.prototype.addTo3dContainer = function (elem, pos) { + var j = 0; + var nextElement; + while (j < pos) { + if (this.elements[j] && this.elements[j].getBaseElement) { + nextElement = this.elements[j].getBaseElement(); + } + j += 1; + } + if (nextElement) { + this.layerElement.insertBefore(elem, nextElement); + } else { + this.layerElement.appendChild(elem); + } + } + + function HShapeElement(data, globalData, comp) { + //List of drawable elements + this.shapes = []; + // Full shape data + this.shapesData = data.shapes; + //List of styles that will be applied to shapes + this.stylesList = []; + //List of modifiers that will be applied to shapes + this.shapeModifiers = []; + //List of items in shape tree + this.itemsData = []; + //List of items in previous shape tree + this.processedElements = []; + // List of animated components + this.animatedContents = []; + this.shapesContainer = createNS('g'); + this.initElement(data, globalData, comp); + //Moving any property that doesn't get too much access after initialization because of v8 way of handling more than 10 properties. + // List of elements that have been created + this.prevViewData = []; + this.currentBBox = { + x: 999999, + y: -999999, + h: 0, + w: 0 + }; + } + extendPrototype([BaseElement, TransformElement, HSolidElement, SVGShapeElement, HBaseElement, HierarchyElement, FrameElement, RenderableElement], HShapeElement); + HShapeElement.prototype._renderShapeFrame = HShapeElement.prototype.renderInnerContent; + + HShapeElement.prototype.createContent = function () { + var cont; + this.baseElement.style.fontSize = 0; + if (this.data.hasMask) { + this.layerElement.appendChild(this.shapesContainer); + cont = this.svgElement; + } else { + cont = createNS('svg'); + var size = this.comp.data ? this.comp.data : this.globalData.compSize; + cont.setAttribute('width', size.w); + cont.setAttribute('height', size.h); + cont.appendChild(this.shapesContainer); + this.layerElement.appendChild(cont); + } + + this.searchShapes(this.shapesData, this.itemsData, this.prevViewData, this.shapesContainer, 0, [], true); + this.filterUniqueShapes(); + this.shapeCont = cont; + }; + + HShapeElement.prototype.getTransformedPoint = function (transformers, point) { + var i, len = transformers.length; + for (i = 0; i < len; i += 1) { + point = transformers[i].mProps.v.applyToPointArray(point[0], point[1], 0); + } + return point; + } + + HShapeElement.prototype.calculateShapeBoundingBox = function (item, boundingBox) { + var shape = item.sh.v; + var transformers = item.transformers; + var i, len = shape._length, vPoint, oPoint, nextIPoint, nextVPoint, bounds; + if (len <= 1) { + return; + } + for (i = 0; i < len - 1; i += 1) { + vPoint = this.getTransformedPoint(transformers, shape.v[i]); + oPoint = this.getTransformedPoint(transformers, shape.o[i]); + nextIPoint = this.getTransformedPoint(transformers, shape.i[i + 1]); + nextVPoint = this.getTransformedPoint(transformers, shape.v[i + 1]); + this.checkBounds(vPoint, oPoint, nextIPoint, nextVPoint, boundingBox); + } + if (shape.c) { + vPoint = this.getTransformedPoint(transformers, shape.v[i]); + oPoint = this.getTransformedPoint(transformers, shape.o[i]); + nextIPoint = this.getTransformedPoint(transformers, shape.i[0]); + nextVPoint = this.getTransformedPoint(transformers, shape.v[0]); + this.checkBounds(vPoint, oPoint, nextIPoint, nextVPoint, boundingBox); + } + } + + HShapeElement.prototype.checkBounds = function (vPoint, oPoint, nextIPoint, nextVPoint, boundingBox) { + this.getBoundsOfCurve(vPoint, oPoint, nextIPoint, nextVPoint); + var bounds = this.shapeBoundingBox; + boundingBox.x = bm_min(bounds.left, boundingBox.x); + boundingBox.xMax = bm_max(bounds.right, boundingBox.xMax); + boundingBox.y = bm_min(bounds.top, boundingBox.y); + boundingBox.yMax = bm_max(bounds.bottom, boundingBox.yMax); + } + + HShapeElement.prototype.shapeBoundingBox = { + left: 0, + right: 0, + top: 0, + bottom: 0, + } + + HShapeElement.prototype.tempBoundingBox = { + x: 0, + xMax: 0, + y: 0, + yMax: 0, + width: 0, + height: 0 + } + + HShapeElement.prototype.getBoundsOfCurve = function (p0, p1, p2, p3) { + + var bounds = [[p0[0], p3[0]], [p0[1], p3[1]]]; + + for (var a, b, c, t, b2ac, t1, t2, i = 0; i < 2; ++i) { + + b = 6 * p0[i] - 12 * p1[i] + 6 * p2[i]; + a = -3 * p0[i] + 9 * p1[i] - 9 * p2[i] + 3 * p3[i]; + c = 3 * p1[i] - 3 * p0[i]; + + b = b | 0; + a = a | 0; + c = c | 0; + + if (a === 0) { + + if (b === 0) { + continue; + } + + t = -c / b; + + if (0 < t && t < 1) { + bounds[i].push(this.calculateF(t, p0, p1, p2, p3, i)); + } + continue; + } + + b2ac = b * b - 4 * c * a; + + if (b2ac < 0) { + continue; + } + + t1 = (-b + bm_sqrt(b2ac)) / (2 * a); + if (0 < t1 && t1 < 1) bounds[i].push(this.calculateF(t1, p0, p1, p2, p3, i)); + + t2 = (-b - bm_sqrt(b2ac)) / (2 * a); + if (0 < t2 && t2 < 1) bounds[i].push(this.calculateF(t2, p0, p1, p2, p3, i)); + + } + + this.shapeBoundingBox.left = bm_min.apply(null, bounds[0]); + this.shapeBoundingBox.top = bm_min.apply(null, bounds[1]); + this.shapeBoundingBox.right = bm_max.apply(null, bounds[0]); + this.shapeBoundingBox.bottom = bm_max.apply(null, bounds[1]); + }; + + HShapeElement.prototype.calculateF = function (t, p0, p1, p2, p3, i) { + return bm_pow(1 - t, 3) * p0[i] + + 3 * bm_pow(1 - t, 2) * t * p1[i] + + 3 * (1 - t) * bm_pow(t, 2) * p2[i] + + bm_pow(t, 3) * p3[i]; + } + + HShapeElement.prototype.calculateBoundingBox = function (itemsData, boundingBox) { + var i, len = itemsData.length, path; + for (i = 0; i < len; i += 1) { + if (itemsData[i] && itemsData[i].sh) { + this.calculateShapeBoundingBox(itemsData[i], boundingBox) + } else if (itemsData[i] && itemsData[i].it) { + this.calculateBoundingBox(itemsData[i].it, boundingBox) + } + } + } + + HShapeElement.prototype.currentBoxContains = function (box) { + return this.currentBBox.x <= box.x + && this.currentBBox.y <= box.y + && this.currentBBox.width + this.currentBBox.x >= box.x + box.width + && this.currentBBox.height + this.currentBBox.y >= box.y + box.height + } + + HShapeElement.prototype.renderInnerContent = function () { + this._renderShapeFrame(); + + if (!this.hidden && (this._isFirstFrame || this._mdf)) { + var tempBoundingBox = this.tempBoundingBox; + var max = 999999; + tempBoundingBox.x = max; + tempBoundingBox.xMax = -max; + tempBoundingBox.y = max; + tempBoundingBox.yMax = -max; + this.calculateBoundingBox(this.itemsData, tempBoundingBox); + tempBoundingBox.width = tempBoundingBox.xMax < tempBoundingBox.x ? 0 : tempBoundingBox.xMax - tempBoundingBox.x; + tempBoundingBox.height = tempBoundingBox.yMax < tempBoundingBox.y ? 0 : tempBoundingBox.yMax - tempBoundingBox.y; + //var tempBoundingBox = this.shapeCont.getBBox(); + if (this.currentBoxContains(tempBoundingBox)) { + return; + } + var changed = false; + if (this.currentBBox.w !== tempBoundingBox.width) { + this.currentBBox.w = tempBoundingBox.width; + this.shapeCont.setAttribute('width', tempBoundingBox.width); + changed = true; + } + if (this.currentBBox.h !== tempBoundingBox.height) { + this.currentBBox.h = tempBoundingBox.height; + this.shapeCont.setAttribute('height', tempBoundingBox.height); + changed = true; + } + if (changed || this.currentBBox.x !== tempBoundingBox.x || this.currentBBox.y !== tempBoundingBox.y) { + this.currentBBox.w = tempBoundingBox.width; + this.currentBBox.h = tempBoundingBox.height; + this.currentBBox.x = tempBoundingBox.x; + this.currentBBox.y = tempBoundingBox.y; + + this.shapeCont.setAttribute('viewBox', this.currentBBox.x + ' ' + this.currentBBox.y + ' ' + this.currentBBox.w + ' ' + this.currentBBox.h); + this.shapeCont.style.transform = this.shapeCont.style.webkitTransform = 'translate(' + this.currentBBox.x + 'px,' + this.currentBBox.y + 'px)'; + } + } + + }; + function HTextElement(data, globalData, comp) { + this.textSpans = []; + this.textPaths = []; + this.currentBBox = { + x: 999999, + y: -999999, + h: 0, + w: 0 + }; + this.renderType = 'svg'; + this.isMasked = false; + this.initElement(data, globalData, comp); + + } + extendPrototype([BaseElement, TransformElement, HBaseElement, HierarchyElement, FrameElement, RenderableDOMElement, ITextElement], HTextElement); + + HTextElement.prototype.createContent = function () { + this.isMasked = this.checkMasks(); + if (this.isMasked) { + this.renderType = 'svg'; + this.compW = this.comp.data.w; + this.compH = this.comp.data.h; + this.svgElement.setAttribute('width', this.compW); + this.svgElement.setAttribute('height', this.compH); + var g = createNS('g'); + this.maskedElement.appendChild(g); + this.innerElem = g; + } else { + this.renderType = 'html'; + this.innerElem = this.layerElement; + } + + this.checkParenting(); + + }; + + HTextElement.prototype.buildNewText = function () { + var documentData = this.textProperty.currentData; + this.renderedLetters = createSizedArray(documentData.l ? documentData.l.length : 0); + var innerElemStyle = this.innerElem.style; + innerElemStyle.color = innerElemStyle.fill = documentData.fc ? this.buildColor(documentData.fc) : 'rgba(0,0,0,0)'; + if (documentData.sc) { + innerElemStyle.stroke = this.buildColor(documentData.sc); + innerElemStyle.strokeWidth = documentData.sw + 'px'; + } + var fontData = this.globalData.fontManager.getFontByName(documentData.f); + if (!this.globalData.fontManager.chars) { + innerElemStyle.fontSize = documentData.finalSize + 'px'; + innerElemStyle.lineHeight = documentData.finalSize + 'px'; + if (fontData.fClass) { + this.innerElem.className = fontData.fClass; + } else { + innerElemStyle.fontFamily = fontData.fFamily; + var fWeight = documentData.fWeight, fStyle = documentData.fStyle; + innerElemStyle.fontStyle = fStyle; + innerElemStyle.fontWeight = fWeight; + } + } + var i, len; + + var letters = documentData.l; + len = letters.length; + var tSpan, tParent, tCont; + var matrixHelper = this.mHelper; + var shapes, shapeStr = ''; + var cnt = 0; + for (i = 0; i < len; i += 1) { + if (this.globalData.fontManager.chars) { + if (!this.textPaths[cnt]) { + tSpan = createNS('path'); + tSpan.setAttribute('stroke-linecap', 'butt'); + tSpan.setAttribute('stroke-linejoin', 'round'); + tSpan.setAttribute('stroke-miterlimit', '4'); + } else { + tSpan = this.textPaths[cnt]; + } + if (!this.isMasked) { + if (this.textSpans[cnt]) { + tParent = this.textSpans[cnt]; + tCont = tParent.children[0]; + } else { + + tParent = createTag('div'); + tParent.style.lineHeight = 0; + tCont = createNS('svg'); + tCont.appendChild(tSpan); + styleDiv(tParent); + } + } + } else { + if (!this.isMasked) { + if (this.textSpans[cnt]) { + tParent = this.textSpans[cnt]; + tSpan = this.textPaths[cnt]; + } else { + tParent = createTag('span'); + styleDiv(tParent); + tSpan = createTag('span'); + styleDiv(tSpan); + tParent.appendChild(tSpan); + } + } else { + tSpan = this.textPaths[cnt] ? this.textPaths[cnt] : createNS('text'); + } + } + //tSpan.setAttribute('visibility', 'hidden'); + if (this.globalData.fontManager.chars) { + var charData = this.globalData.fontManager.getCharData(documentData.finalText[i], fontData.fStyle, this.globalData.fontManager.getFontByName(documentData.f).fFamily); + var shapeData; + if (charData) { + shapeData = charData.data; + } else { + shapeData = null; + } + matrixHelper.reset(); + if (shapeData && shapeData.shapes) { + shapes = shapeData.shapes[0].it; + matrixHelper.scale(documentData.finalSize / 100, documentData.finalSize / 100); + shapeStr = this.createPathShape(matrixHelper, shapes); + tSpan.setAttribute('d', shapeStr); + } + if (!this.isMasked) { + this.innerElem.appendChild(tParent); + if (shapeData && shapeData.shapes) { + + //document.body.appendChild is needed to get exact measure of shape + document.body.appendChild(tCont); + var boundingBox = tCont.getBBox(); + tCont.setAttribute('width', boundingBox.width + 2); + tCont.setAttribute('height', boundingBox.height + 2); + tCont.setAttribute('viewBox', (boundingBox.x - 1) + ' ' + (boundingBox.y - 1) + ' ' + (boundingBox.width + 2) + ' ' + (boundingBox.height + 2)); + tCont.style.transform = tCont.style.webkitTransform = 'translate(' + (boundingBox.x - 1) + 'px,' + (boundingBox.y - 1) + 'px)'; + + letters[i].yOffset = boundingBox.y - 1; + + } else { + tCont.setAttribute('width', 1); + tCont.setAttribute('height', 1); + } + tParent.appendChild(tCont); + } else { + this.innerElem.appendChild(tSpan); + } + } else { + tSpan.textContent = letters[i].val; + tSpan.setAttributeNS("http://www.w3.org/XML/1998/namespace", "xml:space", "preserve"); + if (!this.isMasked) { + this.innerElem.appendChild(tParent); + // + tSpan.style.transform = tSpan.style.webkitTransform = 'translate3d(0,' + -documentData.finalSize / 1.2 + 'px,0)'; + } else { + this.innerElem.appendChild(tSpan); + } + } + // + if (!this.isMasked) { + this.textSpans[cnt] = tParent; + } else { + this.textSpans[cnt] = tSpan; + } + this.textSpans[cnt].style.display = 'block'; + this.textPaths[cnt] = tSpan; + cnt += 1; + } + while (cnt < this.textSpans.length) { + this.textSpans[cnt].style.display = 'none'; + cnt += 1; + } + }; + + HTextElement.prototype.renderInnerContent = function () { + + if (this.data.singleShape) { + if (!this._isFirstFrame && !this.lettersChangedFlag) { + return; + } else { + // Todo Benchmark if using this is better than getBBox + if (this.isMasked && this.finalTransform._matMdf) { + this.svgElement.setAttribute('viewBox', -this.finalTransform.mProp.p.v[0] + ' ' + -this.finalTransform.mProp.p.v[1] + ' ' + this.compW + ' ' + this.compH); + this.svgElement.style.transform = this.svgElement.style.webkitTransform = 'translate(' + -this.finalTransform.mProp.p.v[0] + 'px,' + -this.finalTransform.mProp.p.v[1] + 'px)'; + } + } + } + + this.textAnimator.getMeasures(this.textProperty.currentData, this.lettersChangedFlag); + if (!this.lettersChangedFlag && !this.textAnimator.lettersChangedFlag) { + return; + } + var i, len, count = 0; + var renderedLetters = this.textAnimator.renderedLetters; + + var letters = this.textProperty.currentData.l; + + len = letters.length; + var renderedLetter, textSpan, textPath; + for (i = 0; i < len; i += 1) { + if (letters[i].n) { + count += 1; + continue; + } + textSpan = this.textSpans[i]; + textPath = this.textPaths[i]; + renderedLetter = renderedLetters[count]; + count += 1; + if (renderedLetter._mdf.m) { + if (!this.isMasked) { + textSpan.style.transform = textSpan.style.webkitTransform = renderedLetter.m; + } else { + textSpan.setAttribute('transform', renderedLetter.m); + } + } + ////textSpan.setAttribute('opacity',renderedLetter.o); + textSpan.style.opacity = renderedLetter.o; + if (renderedLetter.sw && renderedLetter._mdf.sw) { + textPath.setAttribute('stroke-width', renderedLetter.sw); + } + if (renderedLetter.sc && renderedLetter._mdf.sc) { + textPath.setAttribute('stroke', renderedLetter.sc); + } + if (renderedLetter.fc && renderedLetter._mdf.fc) { + textPath.setAttribute('fill', renderedLetter.fc); + textPath.style.color = renderedLetter.fc; + } + } + + if (this.innerElem.getBBox && !this.hidden && (this._isFirstFrame || this._mdf)) { + var boundingBox = this.innerElem.getBBox(); + + if (this.currentBBox.w !== boundingBox.width) { + this.currentBBox.w = boundingBox.width; + this.svgElement.setAttribute('width', boundingBox.width); + } + if (this.currentBBox.h !== boundingBox.height) { + this.currentBBox.h = boundingBox.height; + this.svgElement.setAttribute('height', boundingBox.height); + } + + var margin = 1; + if (this.currentBBox.w !== (boundingBox.width + margin * 2) || this.currentBBox.h !== (boundingBox.height + margin * 2) || this.currentBBox.x !== (boundingBox.x - margin) || this.currentBBox.y !== (boundingBox.y - margin)) { + this.currentBBox.w = boundingBox.width + margin * 2; + this.currentBBox.h = boundingBox.height + margin * 2; + this.currentBBox.x = boundingBox.x - margin; + this.currentBBox.y = boundingBox.y - margin; + + this.svgElement.setAttribute('viewBox', this.currentBBox.x + ' ' + this.currentBBox.y + ' ' + this.currentBBox.w + ' ' + this.currentBBox.h); + this.svgElement.style.transform = this.svgElement.style.webkitTransform = 'translate(' + this.currentBBox.x + 'px,' + this.currentBBox.y + 'px)'; + } + } + }; + function HImageElement(data, globalData, comp) { + this.assetData = globalData.getAssetData(data.refId); + this.initElement(data, globalData, comp); + } + + extendPrototype([BaseElement, TransformElement, HBaseElement, HSolidElement, HierarchyElement, FrameElement, RenderableElement], HImageElement); + + + HImageElement.prototype.createContent = function () { + var assetPath = this.globalData.getAssetsPath(this.assetData); + var img = new Image(); + + if (this.data.hasMask) { + this.imageElem = createNS('image'); + this.imageElem.setAttribute('width', this.assetData.w + "px"); + this.imageElem.setAttribute('height', this.assetData.h + "px"); + this.imageElem.setAttributeNS('http://www.w3.org/1999/xlink', 'href', assetPath); + this.layerElement.appendChild(this.imageElem); + this.baseElement.setAttribute('width', this.assetData.w); + this.baseElement.setAttribute('height', this.assetData.h); + } else { + this.layerElement.appendChild(img); + } + img.src = assetPath; + if (this.data.ln) { + this.baseElement.setAttribute('id', this.data.ln); + } + }; + function HCameraElement(data, globalData, comp) { + this.initFrame(); + this.initBaseData(data, globalData, comp); + this.initHierarchy(); + var getProp = PropertyFactory.getProp; + this.pe = getProp(this, data.pe, 0, 0, this); + if (data.ks.p.s) { + this.px = getProp(this, data.ks.p.x, 1, 0, this); + this.py = getProp(this, data.ks.p.y, 1, 0, this); + this.pz = getProp(this, data.ks.p.z, 1, 0, this); + } else { + this.p = getProp(this, data.ks.p, 1, 0, this); + } + if (data.ks.a) { + this.a = getProp(this, data.ks.a, 1, 0, this); + } + if (data.ks.or.k.length && data.ks.or.k[0].to) { + var i, len = data.ks.or.k.length; + for (i = 0; i < len; i += 1) { + data.ks.or.k[i].to = null; + data.ks.or.k[i].ti = null; + } + } + this.or = getProp(this, data.ks.or, 1, degToRads, this); + this.or.sh = true; + this.rx = getProp(this, data.ks.rx, 0, degToRads, this); + this.ry = getProp(this, data.ks.ry, 0, degToRads, this); + this.rz = getProp(this, data.ks.rz, 0, degToRads, this); + this.mat = new Matrix(); + this._prevMat = new Matrix(); + this._isFirstFrame = true; + + // TODO: find a better way to make the HCamera element to be compatible with the LayerInterface and TransformInterface. + this.finalTransform = { + mProp: this + }; + } + extendPrototype([BaseElement, FrameElement, HierarchyElement], HCameraElement); + + HCameraElement.prototype.setup = function () { + var i, len = this.comp.threeDElements.length, comp; + for (i = 0; i < len; i += 1) { + //[perspectiveElem,container] + comp = this.comp.threeDElements[i]; + if (comp.type === '3d') { + comp.perspectiveElem.style.perspective = comp.perspectiveElem.style.webkitPerspective = this.pe.v + 'px'; + comp.container.style.transformOrigin = comp.container.style.mozTransformOrigin = comp.container.style.webkitTransformOrigin = "0px 0px 0px"; + comp.perspectiveElem.style.transform = comp.perspectiveElem.style.webkitTransform = 'matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1)'; + } + } + }; + + HCameraElement.prototype.createElements = function () { + }; + + HCameraElement.prototype.hide = function () { + }; + + HCameraElement.prototype.renderFrame = function () { + var _mdf = this._isFirstFrame; + var i, len; + if (this.hierarchy) { + len = this.hierarchy.length; + for (i = 0; i < len; i += 1) { + _mdf = this.hierarchy[i].finalTransform.mProp._mdf || _mdf; + } + } + if (_mdf || this.pe._mdf || (this.p && this.p._mdf) || (this.px && (this.px._mdf || this.py._mdf || this.pz._mdf)) || this.rx._mdf || this.ry._mdf || this.rz._mdf || this.or._mdf || (this.a && this.a._mdf)) { + this.mat.reset(); + + if (this.hierarchy) { + var mat; + len = this.hierarchy.length - 1; + for (i = len; i >= 0; i -= 1) { + var mTransf = this.hierarchy[i].finalTransform.mProp; + this.mat.translate(-mTransf.p.v[0], -mTransf.p.v[1], mTransf.p.v[2]); + this.mat.rotateX(-mTransf.or.v[0]).rotateY(-mTransf.or.v[1]).rotateZ(mTransf.or.v[2]); + this.mat.rotateX(-mTransf.rx.v).rotateY(-mTransf.ry.v).rotateZ(mTransf.rz.v); + this.mat.scale(1 / mTransf.s.v[0], 1 / mTransf.s.v[1], 1 / mTransf.s.v[2]); + this.mat.translate(mTransf.a.v[0], mTransf.a.v[1], mTransf.a.v[2]); + } + } + if (this.p) { + this.mat.translate(-this.p.v[0], -this.p.v[1], this.p.v[2]); + } else { + this.mat.translate(-this.px.v, -this.py.v, this.pz.v); + } + if (this.a) { + var diffVector + if (this.p) { + diffVector = [this.p.v[0] - this.a.v[0], this.p.v[1] - this.a.v[1], this.p.v[2] - this.a.v[2]]; + } else { + diffVector = [this.px.v - this.a.v[0], this.py.v - this.a.v[1], this.pz.v - this.a.v[2]]; + } + var mag = Math.sqrt(Math.pow(diffVector[0], 2) + Math.pow(diffVector[1], 2) + Math.pow(diffVector[2], 2)); + //var lookDir = getNormalizedPoint(getDiffVector(this.a.v,this.p.v)); + var lookDir = [diffVector[0] / mag, diffVector[1] / mag, diffVector[2] / mag]; + var lookLengthOnXZ = Math.sqrt(lookDir[2] * lookDir[2] + lookDir[0] * lookDir[0]); + var m_rotationX = (Math.atan2(lookDir[1], lookLengthOnXZ)); + var m_rotationY = (Math.atan2(lookDir[0], -lookDir[2])); + this.mat.rotateY(m_rotationY).rotateX(-m_rotationX); + + } + this.mat.rotateX(-this.rx.v).rotateY(-this.ry.v).rotateZ(this.rz.v); + this.mat.rotateX(-this.or.v[0]).rotateY(-this.or.v[1]).rotateZ(this.or.v[2]); + this.mat.translate(this.globalData.compSize.w / 2, this.globalData.compSize.h / 2, 0); + this.mat.translate(0, 0, this.pe.v); + + + + + var hasMatrixChanged = !this._prevMat.equals(this.mat); + if ((hasMatrixChanged || this.pe._mdf) && this.comp.threeDElements) { + len = this.comp.threeDElements.length; + var comp; + for (i = 0; i < len; i += 1) { + comp = this.comp.threeDElements[i]; + if (comp.type === '3d') { + if (hasMatrixChanged) { + comp.container.style.transform = comp.container.style.webkitTransform = this.mat.toCSS(); + } + if (this.pe._mdf) { + comp.perspectiveElem.style.perspective = comp.perspectiveElem.style.webkitPerspective = this.pe.v + 'px'; + } + } + } + this.mat.clone(this._prevMat); + } + } + this._isFirstFrame = false; + }; + + HCameraElement.prototype.prepareFrame = function (num) { + this.prepareProperties(num, true); + }; + + HCameraElement.prototype.destroy = function () { + }; + HCameraElement.prototype.getBaseElement = function () { return null; }; + function HEffects() { + } + HEffects.prototype.renderFrame = function () { }; + var animationManager = (function () { + var moduleOb = {}; + var registeredAnimations = []; + var initTime = 0; + var len = 0; + var playingAnimationsNum = 0; + var _stopped = true; + var _isFrozen = false; + + function removeElement(ev) { + var i = 0; + var animItem = ev.target; + while (i < len) { + if (registeredAnimations[i].animation === animItem) { + registeredAnimations.splice(i, 1); + i -= 1; + len -= 1; + if (!animItem.isPaused) { + subtractPlayingCount(); + } + } + i += 1; + } + } + + function registerAnimation(element, animationData) { + if (!element) { + return null; + } + var i = 0; + while (i < len) { + if (registeredAnimations[i].elem == element && registeredAnimations[i].elem !== null) { + return registeredAnimations[i].animation; + } + i += 1; + } + var animItem = new AnimationItem(); + setupAnimation(animItem, element); + animItem.setData(element, animationData); + return animItem; + } + + function getRegisteredAnimations() { + var i, len = registeredAnimations.length; + var animations = []; + for (i = 0; i < len; i += 1) { + animations.push(registeredAnimations[i].animation); + } + return animations; + } + + function addPlayingCount() { + playingAnimationsNum += 1; + activate(); + } + + function subtractPlayingCount() { + playingAnimationsNum -= 1; + } + + function setupAnimation(animItem, element) { + animItem.addEventListener('destroy', removeElement); + animItem.addEventListener('_active', addPlayingCount); + animItem.addEventListener('_idle', subtractPlayingCount); + registeredAnimations.push({ elem: element, animation: animItem }); + len += 1; + } + + function loadAnimation(params) { + var animItem = new AnimationItem(); + setupAnimation(animItem, null); + animItem.setParams(params); + return animItem; + } + + + function setSpeed(val, animation) { + var i; + for (i = 0; i < len; i += 1) { + registeredAnimations[i].animation.setSpeed(val, animation); + } + } + + function setDirection(val, animation) { + var i; + for (i = 0; i < len; i += 1) { + registeredAnimations[i].animation.setDirection(val, animation); + } + } + + function play(animation) { + var i; + for (i = 0; i < len; i += 1) { + registeredAnimations[i].animation.play(animation); + } + } + function resume(nowTime) { + var elapsedTime = nowTime - initTime; + var i; + for (i = 0; i < len; i += 1) { + registeredAnimations[i].animation.advanceTime(elapsedTime); + } + initTime = nowTime; + if (playingAnimationsNum && !_isFrozen) { + window.requestAnimationFrame(resume); + } else { + _stopped = true; + } + } + + function first(nowTime) { + initTime = nowTime; + window.requestAnimationFrame(resume); + } + + function pause(animation) { + var i; + for (i = 0; i < len; i += 1) { + registeredAnimations[i].animation.pause(animation); + } + } + + function goToAndStop(value, isFrame, animation) { + var i; + for (i = 0; i < len; i += 1) { + registeredAnimations[i].animation.goToAndStop(value, isFrame, animation); + } + } + + function stop(animation) { + var i; + for (i = 0; i < len; i += 1) { + registeredAnimations[i].animation.stop(animation); + } + } + + function togglePause(animation) { + var i; + for (i = 0; i < len; i += 1) { + registeredAnimations[i].animation.togglePause(animation); + } + } + + function destroy(animation) { + var i; + for (i = (len - 1); i >= 0; i -= 1) { + registeredAnimations[i].animation.destroy(animation); + } + } + + function searchAnimations(animationData, standalone, renderer) { + var animElements = [].concat([].slice.call(document.getElementsByClassName('lottie')), + [].slice.call(document.getElementsByClassName('bodymovin'))); + var i, len = animElements.length; + for (i = 0; i < len; i += 1) { + if (renderer) { + animElements[i].setAttribute('data-bm-type', renderer); + } + registerAnimation(animElements[i], animationData); + } + if (standalone && len === 0) { + if (!renderer) { + renderer = 'svg'; + } + var body = document.getElementsByTagName('body')[0]; + body.innerHTML = ''; + var div = createTag('div'); + div.style.width = '100%'; + div.style.height = '100%'; + div.setAttribute('data-bm-type', renderer); + body.appendChild(div); + registerAnimation(div, animationData); + } + } + + function resize() { + var i; + for (i = 0; i < len; i += 1) { + registeredAnimations[i].animation.resize(); + } + } + + function activate() { + if (!_isFrozen && playingAnimationsNum) { + if (_stopped) { + window.requestAnimationFrame(first); + _stopped = false; + } + } + } + + function freeze() { + _isFrozen = true; + } + + function unfreeze() { + _isFrozen = false; + activate(); + } + + moduleOb.registerAnimation = registerAnimation; + moduleOb.loadAnimation = loadAnimation; + moduleOb.setSpeed = setSpeed; + moduleOb.setDirection = setDirection; + moduleOb.play = play; + moduleOb.pause = pause; + moduleOb.stop = stop; + moduleOb.togglePause = togglePause; + moduleOb.searchAnimations = searchAnimations; + moduleOb.resize = resize; + //moduleOb.start = start; + moduleOb.goToAndStop = goToAndStop; + moduleOb.destroy = destroy; + moduleOb.freeze = freeze; + moduleOb.unfreeze = unfreeze; + moduleOb.getRegisteredAnimations = getRegisteredAnimations; + return moduleOb; + }()); + + var AnimationItem = function () { + this._cbs = []; + this.name = ''; + this.path = ''; + this.isLoaded = false; + this.currentFrame = 0; + this.currentRawFrame = 0; + this.firstFrame = 0; + this.totalFrames = 0; + this.frameRate = 0; + this.frameMult = 0; + this.playSpeed = 1; + this.playDirection = 1; + this.playCount = 0; + this.animationData = {}; + this.assets = []; + this.isPaused = true; + this.autoplay = false; + this.loop = true; + this.renderer = null; + this.animationID = createElementID(); + this.assetsPath = ''; + this.timeCompleted = 0; + this.segmentPos = 0; + this.subframeEnabled = subframeEnabled; + this.segments = []; + this._idle = true; + this._completedLoop = false; + this.projectInterface = ProjectInterface(); + this.imagePreloader = new ImagePreloader(); + }; + + extendPrototype([BaseEvent], AnimationItem); + + AnimationItem.prototype.setParams = function (params) { + if (params.context) { + this.context = params.context; + } + if (params.wrapper || params.container) { + this.wrapper = params.wrapper || params.container; + } + var animType = params.animType ? params.animType : params.renderer ? params.renderer : 'svg'; + switch (animType) { + case 'canvas': + this.renderer = new CanvasRenderer(this, params.rendererSettings); + break; + case 'svg': + this.renderer = new SVGRenderer(this, params.rendererSettings); + break; + default: + this.renderer = new HybridRenderer(this, params.rendererSettings); + break; + } + this.renderer.setProjectInterface(this.projectInterface); + this.animType = animType; + + if (params.loop === '' || params.loop === null) { + } else if (params.loop === false) { + this.loop = false; + } else if (params.loop === true) { + this.loop = true; + } else { + this.loop = parseInt(params.loop); + } + this.autoplay = 'autoplay' in params ? params.autoplay : true; + this.name = params.name ? params.name : ''; + this.autoloadSegments = params.hasOwnProperty('autoloadSegments') ? params.autoloadSegments : true; + this.assetsPath = params.assetsPath; + this.initialSegment = params.initialSegment; + if (params.animationData) { + this.configAnimation(params.animationData); + } else if (params.path) { + + if (params.path.lastIndexOf('\\') !== -1) { + this.path = params.path.substr(0, params.path.lastIndexOf('\\') + 1); + } else { + this.path = params.path.substr(0, params.path.lastIndexOf('/') + 1); + } + this.fileName = params.path.substr(params.path.lastIndexOf('/') + 1); + this.fileName = this.fileName.substr(0, this.fileName.lastIndexOf('.json')); + + assetLoader.load(params.path, this.configAnimation.bind(this), function () { + this.trigger('data_failed'); + }.bind(this)); + } + + }; + + AnimationItem.prototype.setData = function (wrapper, animationData) { + var params = { + wrapper: wrapper, + animationData: animationData ? (typeof animationData === "object") ? animationData : JSON.parse(animationData) : null + }; + var wrapperAttributes = wrapper.attributes; + + params.path = wrapperAttributes.getNamedItem('data-animation-path') ? wrapperAttributes.getNamedItem('data-animation-path').value : wrapperAttributes.getNamedItem('data-bm-path') ? wrapperAttributes.getNamedItem('data-bm-path').value : wrapperAttributes.getNamedItem('bm-path') ? wrapperAttributes.getNamedItem('bm-path').value : ''; + params.animType = wrapperAttributes.getNamedItem('data-anim-type') ? wrapperAttributes.getNamedItem('data-anim-type').value : wrapperAttributes.getNamedItem('data-bm-type') ? wrapperAttributes.getNamedItem('data-bm-type').value : wrapperAttributes.getNamedItem('bm-type') ? wrapperAttributes.getNamedItem('bm-type').value : wrapperAttributes.getNamedItem('data-bm-renderer') ? wrapperAttributes.getNamedItem('data-bm-renderer').value : wrapperAttributes.getNamedItem('bm-renderer') ? wrapperAttributes.getNamedItem('bm-renderer').value : 'canvas'; + + var loop = wrapperAttributes.getNamedItem('data-anim-loop') ? wrapperAttributes.getNamedItem('data-anim-loop').value : wrapperAttributes.getNamedItem('data-bm-loop') ? wrapperAttributes.getNamedItem('data-bm-loop').value : wrapperAttributes.getNamedItem('bm-loop') ? wrapperAttributes.getNamedItem('bm-loop').value : ''; + if (loop === '') { + } else if (loop === 'false') { + params.loop = false; + } else if (loop === 'true') { + params.loop = true; + } else { + params.loop = parseInt(loop); + } + var autoplay = wrapperAttributes.getNamedItem('data-anim-autoplay') ? wrapperAttributes.getNamedItem('data-anim-autoplay').value : wrapperAttributes.getNamedItem('data-bm-autoplay') ? wrapperAttributes.getNamedItem('data-bm-autoplay').value : wrapperAttributes.getNamedItem('bm-autoplay') ? wrapperAttributes.getNamedItem('bm-autoplay').value : true; + params.autoplay = autoplay !== "false"; + + params.name = wrapperAttributes.getNamedItem('data-name') ? wrapperAttributes.getNamedItem('data-name').value : wrapperAttributes.getNamedItem('data-bm-name') ? wrapperAttributes.getNamedItem('data-bm-name').value : wrapperAttributes.getNamedItem('bm-name') ? wrapperAttributes.getNamedItem('bm-name').value : ''; + var prerender = wrapperAttributes.getNamedItem('data-anim-prerender') ? wrapperAttributes.getNamedItem('data-anim-prerender').value : wrapperAttributes.getNamedItem('data-bm-prerender') ? wrapperAttributes.getNamedItem('data-bm-prerender').value : wrapperAttributes.getNamedItem('bm-prerender') ? wrapperAttributes.getNamedItem('bm-prerender').value : ''; + + if (prerender === 'false') { + params.prerender = false; + } + this.setParams(params); + }; + + AnimationItem.prototype.includeLayers = function (data) { + if (data.op > this.animationData.op) { + this.animationData.op = data.op; + this.totalFrames = Math.floor(data.op - this.animationData.ip); + } + var layers = this.animationData.layers; + var i, len = layers.length; + var newLayers = data.layers; + var j, jLen = newLayers.length; + for (j = 0; j < jLen; j += 1) { + i = 0; + while (i < len) { + if (layers[i].id == newLayers[j].id) { + layers[i] = newLayers[j]; + break; + } + i += 1; + } + } + if (data.chars || data.fonts) { + this.renderer.globalData.fontManager.addChars(data.chars); + this.renderer.globalData.fontManager.addFonts(data.fonts, this.renderer.globalData.defs); + } + if (data.assets) { + len = data.assets.length; + for (i = 0; i < len; i += 1) { + this.animationData.assets.push(data.assets[i]); + } + } + this.animationData.__complete = false; + dataManager.completeData(this.animationData, this.renderer.globalData.fontManager); + this.renderer.includeLayers(data.layers); + if (expressionsPlugin) { + expressionsPlugin.initExpressions(this); + } + this.loadNextSegment(); + }; + + AnimationItem.prototype.loadNextSegment = function () { + var segments = this.animationData.segments; + if (!segments || segments.length === 0 || !this.autoloadSegments) { + this.trigger('data_ready'); + this.timeCompleted = this.totalFrames; + return; + } + var segment = segments.shift(); + this.timeCompleted = segment.time * this.frameRate; + var segmentPath = this.path + this.fileName + '_' + this.segmentPos + '.json'; + this.segmentPos += 1; + assetLoader.load(segmentPath, this.includeLayers.bind(this), function () { + this.trigger('data_failed'); + }.bind(this)); + }; + + AnimationItem.prototype.loadSegments = function () { + var segments = this.animationData.segments; + if (!segments) { + this.timeCompleted = this.totalFrames; + } + this.loadNextSegment(); + }; + + AnimationItem.prototype.imagesLoaded = function () { + this.trigger('loaded_images'); + this.checkLoaded() + } + + AnimationItem.prototype.preloadImages = function () { + this.imagePreloader.setAssetsPath(this.assetsPath); + this.imagePreloader.setPath(this.path); + this.imagePreloader.loadAssets(this.animationData.assets, this.imagesLoaded.bind(this)); + } + + AnimationItem.prototype.configAnimation = function (animData) { + if (!this.renderer) { + return; + } + try { + this.animationData = animData; + + if (this.initialSegment) { + this.totalFrames = Math.floor(this.initialSegment[1] - this.initialSegment[0]); + this.firstFrame = Math.round(this.initialSegment[0]); + } else { + this.totalFrames = Math.floor(this.animationData.op - this.animationData.ip); + this.firstFrame = Math.round(this.animationData.ip); + } + this.renderer.configAnimation(animData); + if (!animData.assets) { + animData.assets = []; + } + + this.assets = this.animationData.assets; + this.frameRate = this.animationData.fr; + this.frameMult = this.animationData.fr / 1000; + this.renderer.searchExtraCompositions(animData.assets); + this.trigger('config_ready'); + this.preloadImages(); + this.loadSegments(); + this.updaFrameModifier(); + this.waitForFontsLoaded(); + } catch (error) { + this.triggerConfigError(error); + } + }; + + AnimationItem.prototype.waitForFontsLoaded = function () { + if (!this.renderer) { + return; + } + if (this.renderer.globalData.fontManager.loaded()) { + this.checkLoaded(); + } else { + setTimeout(this.waitForFontsLoaded.bind(this), 20); + } + } + + AnimationItem.prototype.checkLoaded = function () { + if (!this.isLoaded && this.renderer.globalData.fontManager.loaded() && (this.imagePreloader.loaded() || this.renderer.rendererType !== 'canvas')) { + this.isLoaded = true; + dataManager.completeData(this.animationData, this.renderer.globalData.fontManager); + if (expressionsPlugin) { + expressionsPlugin.initExpressions(this); + } + this.renderer.initItems(); + setTimeout(function () { + this.trigger('DOMLoaded'); + }.bind(this), 0); + this.gotoFrame(); + if (this.autoplay) { + this.play(); + } + } + }; + + AnimationItem.prototype.resize = function () { + this.renderer.updateContainerSize(); + }; + + AnimationItem.prototype.setSubframe = function (flag) { + this.subframeEnabled = flag ? true : false; + }; + + AnimationItem.prototype.gotoFrame = function () { + this.currentFrame = this.subframeEnabled ? this.currentRawFrame : ~~this.currentRawFrame; + + if (this.timeCompleted !== this.totalFrames && this.currentFrame > this.timeCompleted) { + this.currentFrame = this.timeCompleted; + } + this.trigger('enterFrame'); + this.renderFrame(); + }; + + AnimationItem.prototype.renderFrame = function () { + if (this.isLoaded === false) { + return; + } + try { + this.renderer.renderFrame(this.currentFrame + this.firstFrame); + } catch (error) { + this.triggerRenderFrameError(error); + } + }; + + AnimationItem.prototype.play = function (name) { + if (name && this.name != name) { + return; + } + if (this.isPaused === true) { + this.isPaused = false; + if (this._idle) { + this._idle = false; + this.trigger('_active'); + } + } + }; + + AnimationItem.prototype.pause = function (name) { + if (name && this.name != name) { + return; + } + if (this.isPaused === false) { + this.isPaused = true; + this._idle = true; + this.trigger('_idle'); + } + }; + + AnimationItem.prototype.togglePause = function (name) { + if (name && this.name != name) { + return; + } + if (this.isPaused === true) { + this.play(); + } else { + this.pause(); + } + }; + + AnimationItem.prototype.stop = function (name) { + if (name && this.name != name) { + return; + } + this.pause(); + this.playCount = 0; + this._completedLoop = false; + this.setCurrentRawFrameValue(0); + }; + + AnimationItem.prototype.goToAndStop = function (value, isFrame, name) { + if (name && this.name != name) { + return; + } + if (isFrame) { + this.setCurrentRawFrameValue(value); + } else { + this.setCurrentRawFrameValue(value * this.frameModifier); + } + this.pause(); + }; + + AnimationItem.prototype.goToAndPlay = function (value, isFrame, name) { + this.goToAndStop(value, isFrame, name); + this.play(); + }; + + AnimationItem.prototype.advanceTime = function (value) { + if (this.isPaused === true || this.isLoaded === false) { + return; + } + var nextValue = this.currentRawFrame + value * this.frameModifier; + var _isComplete = false; + // Checking if nextValue > totalFrames - 1 for addressing non looping and looping animations. + // If animation won't loop, it should stop at totalFrames - 1. If it will loop it should complete the last frame and then loop. + if (nextValue >= this.totalFrames - 1 && this.frameModifier > 0) { + if (!this.loop || this.playCount === this.loop) { + if (!this.checkSegments(nextValue > this.totalFrames ? nextValue % this.totalFrames : 0)) { + _isComplete = true; + nextValue = this.totalFrames - 1; + } + } else if (nextValue >= this.totalFrames) { + this.playCount += 1; + if (!this.checkSegments(nextValue % this.totalFrames)) { + this.setCurrentRawFrameValue(nextValue % this.totalFrames); + this._completedLoop = true; + this.trigger('loopComplete'); + } + } else { + this.setCurrentRawFrameValue(nextValue); + } + } else if (nextValue < 0) { + if (!this.checkSegments(nextValue % this.totalFrames)) { + if (this.loop && !(this.playCount-- <= 0 && this.loop !== true)) { + this.setCurrentRawFrameValue(this.totalFrames + (nextValue % this.totalFrames)); + if (!this._completedLoop) { + this._completedLoop = true; + } else { + this.trigger('loopComplete'); + } + } else { + _isComplete = true; + nextValue = 0; + } + } + } else { + this.setCurrentRawFrameValue(nextValue); + } + if (_isComplete) { + this.setCurrentRawFrameValue(nextValue); + this.pause(); + this.trigger('complete'); + } + }; + + AnimationItem.prototype.adjustSegment = function (arr, offset) { + this.playCount = 0; + if (arr[1] < arr[0]) { + if (this.frameModifier > 0) { + if (this.playSpeed < 0) { + this.setSpeed(-this.playSpeed); + } else { + this.setDirection(-1); + } + } + this.timeCompleted = this.totalFrames = arr[0] - arr[1]; + this.firstFrame = arr[1]; + this.setCurrentRawFrameValue(this.totalFrames - 0.001 - offset); + } else if (arr[1] > arr[0]) { + if (this.frameModifier < 0) { + if (this.playSpeed < 0) { + this.setSpeed(-this.playSpeed); + } else { + this.setDirection(1); + } + } + this.timeCompleted = this.totalFrames = arr[1] - arr[0]; + this.firstFrame = arr[0]; + this.setCurrentRawFrameValue(0.001 + offset); + } + this.trigger('segmentStart'); + }; + AnimationItem.prototype.setSegment = function (init, end) { + var pendingFrame = -1; + if (this.isPaused) { + if (this.currentRawFrame + this.firstFrame < init) { + pendingFrame = init; + } else if (this.currentRawFrame + this.firstFrame > end) { + pendingFrame = end - init; + } + } + + this.firstFrame = init; + this.timeCompleted = this.totalFrames = end - init; + if (pendingFrame !== -1) { + this.goToAndStop(pendingFrame, true); + } + }; + + AnimationItem.prototype.playSegments = function (arr, forceFlag) { + if (forceFlag) { + this.segments.length = 0; + } + if (typeof arr[0] === 'object') { + var i, len = arr.length; + for (i = 0; i < len; i += 1) { + this.segments.push(arr[i]); + } + } else { + this.segments.push(arr); + } + if (this.segments.length && forceFlag) { + this.adjustSegment(this.segments.shift(), 0); + } + if (this.isPaused) { + this.play(); + } + }; + + AnimationItem.prototype.resetSegments = function (forceFlag) { + this.segments.length = 0; + this.segments.push([this.animationData.ip, this.animationData.op]); + //this.segments.push([this.animationData.ip*this.frameRate,Math.floor(this.animationData.op - this.animationData.ip+this.animationData.ip*this.frameRate)]); + if (forceFlag) { + this.checkSegments(0); + } + }; + AnimationItem.prototype.checkSegments = function (offset) { + if (this.segments.length) { + this.adjustSegment(this.segments.shift(), offset); + return true; + } + return false; + }; + + AnimationItem.prototype.destroy = function (name) { + if ((name && this.name != name) || !this.renderer) { + return; + } + this.renderer.destroy(); + this.imagePreloader.destroy(); + this.trigger('destroy'); + this._cbs = null; + this.onEnterFrame = this.onLoopComplete = this.onComplete = this.onSegmentStart = this.onDestroy = null; + this.renderer = null; + }; + + AnimationItem.prototype.setCurrentRawFrameValue = function (value) { + this.currentRawFrame = value; + this.gotoFrame(); + }; + + AnimationItem.prototype.setSpeed = function (val) { + this.playSpeed = val; + this.updaFrameModifier(); + }; + + AnimationItem.prototype.setDirection = function (val) { + this.playDirection = val < 0 ? -1 : 1; + this.updaFrameModifier(); + }; + + AnimationItem.prototype.updaFrameModifier = function () { + this.frameModifier = this.frameMult * this.playSpeed * this.playDirection; + }; + + AnimationItem.prototype.getPath = function () { + return this.path; + }; + + AnimationItem.prototype.getAssetsPath = function (assetData) { + var path = ''; + if (assetData.e) { + path = assetData.p; + } else if (this.assetsPath) { + var imagePath = assetData.p; + if (imagePath.indexOf('images/') !== -1) { + imagePath = imagePath.split('/')[1]; + } + path = this.assetsPath + imagePath; + } else { + path = this.path; + path += assetData.u ? assetData.u : ''; + path += assetData.p; + } + return path; + }; + + AnimationItem.prototype.getAssetData = function (id) { + var i = 0, len = this.assets.length; + while (i < len) { + if (id == this.assets[i].id) { + return this.assets[i]; + } + i += 1; + } + }; + + AnimationItem.prototype.hide = function () { + this.renderer.hide(); + }; + + AnimationItem.prototype.show = function () { + this.renderer.show(); + }; + + AnimationItem.prototype.getDuration = function (isFrame) { + return isFrame ? this.totalFrames : this.totalFrames / this.frameRate; + }; + + AnimationItem.prototype.trigger = function (name) { + if (this._cbs && this._cbs[name]) { + switch (name) { + case 'enterFrame': + this.triggerEvent(name, new BMEnterFrameEvent(name, this.currentFrame, this.totalFrames, this.frameModifier)); + break; + case 'loopComplete': + this.triggerEvent(name, new BMCompleteLoopEvent(name, this.loop, this.playCount, this.frameMult)); + break; + case 'complete': + this.triggerEvent(name, new BMCompleteEvent(name, this.frameMult)); + break; + case 'segmentStart': + this.triggerEvent(name, new BMSegmentStartEvent(name, this.firstFrame, this.totalFrames)); + break; + case 'destroy': + this.triggerEvent(name, new BMDestroyEvent(name, this)); + break; + default: + this.triggerEvent(name); + } + } + if (name === 'enterFrame' && this.onEnterFrame) { + this.onEnterFrame.call(this, new BMEnterFrameEvent(name, this.currentFrame, this.totalFrames, this.frameMult)); + } + if (name === 'loopComplete' && this.onLoopComplete) { + this.onLoopComplete.call(this, new BMCompleteLoopEvent(name, this.loop, this.playCount, this.frameMult)); + } + if (name === 'complete' && this.onComplete) { + this.onComplete.call(this, new BMCompleteEvent(name, this.frameMult)); + } + if (name === 'segmentStart' && this.onSegmentStart) { + this.onSegmentStart.call(this, new BMSegmentStartEvent(name, this.firstFrame, this.totalFrames)); + } + if (name === 'destroy' && this.onDestroy) { + this.onDestroy.call(this, new BMDestroyEvent(name, this)); + } + }; + + AnimationItem.prototype.triggerRenderFrameError = function (nativeError) { + + var error = new BMRenderFrameErrorEvent(nativeError, this.currentFrame); + this.triggerEvent('error', error); + + if (this.onError) { + this.onError.call(this, error); + } + } + + AnimationItem.prototype.triggerConfigError = function (nativeError) { + + var error = new BMConfigErrorEvent(nativeError, this.currentFrame); + this.triggerEvent('error', error); + + if (this.onError) { + this.onError.call(this, error); + } + } + var Expressions = (function () { + var ob = {}; + ob.initExpressions = initExpressions; + + + function initExpressions(animation) { + + var stackCount = 0; + var registers = []; + + function pushExpression() { + stackCount += 1; + } + + function popExpression() { + stackCount -= 1; + if (stackCount === 0) { + releaseInstances(); + } + } + + function registerExpressionProperty(expression) { + if (registers.indexOf(expression) === -1) { + registers.push(expression) + } + } + + function releaseInstances() { + var i, len = registers.length; + for (i = 0; i < len; i += 1) { + registers[i].release(); + } + registers.length = 0; + } + + animation.renderer.compInterface = CompExpressionInterface(animation.renderer); + animation.renderer.globalData.projectInterface.registerComposition(animation.renderer); + animation.renderer.globalData.pushExpression = pushExpression; + animation.renderer.globalData.popExpression = popExpression; + animation.renderer.globalData.registerExpressionProperty = registerExpressionProperty; + } + return ob; + }()); + + expressionsPlugin = Expressions; + + var ExpressionManager = (function () { + 'use strict'; + var ob = {}; + var Math = BMMath; + var window = null; + var document = null; + + function $bm_isInstanceOfArray(arr) { + return arr.constructor === Array || arr.constructor === Float32Array; + } + + function isNumerable(tOfV, v) { + return tOfV === 'number' || tOfV === 'boolean' || tOfV === 'string' || v instanceof Number; + } + + function $bm_neg(a) { + var tOfA = typeof a; + if (tOfA === 'number' || tOfA === 'boolean' || a instanceof Number) { + return -a; + } + if ($bm_isInstanceOfArray(a)) { + var i, lenA = a.length; + var retArr = []; + for (i = 0; i < lenA; i += 1) { + retArr[i] = -a[i]; + } + return retArr; + } + if (a.propType) { + return a.v; + } + } + + var easeInBez = BezierFactory.getBezierEasing(0.333, 0, .833, .833, 'easeIn').get; + var easeOutBez = BezierFactory.getBezierEasing(0.167, 0.167, .667, 1, 'easeOut').get; + var easeInOutBez = BezierFactory.getBezierEasing(.33, 0, .667, 1, 'easeInOut').get; + + function sum(a, b) { + var tOfA = typeof a; + var tOfB = typeof b; + if (tOfA === 'string' || tOfB === 'string') { + return a + b; + } + if (isNumerable(tOfA, a) && isNumerable(tOfB, b)) { + return a + b; + } + if ($bm_isInstanceOfArray(a) && isNumerable(tOfB, b)) { + a = a.slice(0); + a[0] = a[0] + b; + return a; + } + if (isNumerable(tOfA, a) && $bm_isInstanceOfArray(b)) { + b = b.slice(0); + b[0] = a + b[0]; + return b; + } + if ($bm_isInstanceOfArray(a) && $bm_isInstanceOfArray(b)) { + + var i = 0, lenA = a.length, lenB = b.length; + var retArr = []; + while (i < lenA || i < lenB) { + if ((typeof a[i] === 'number' || a[i] instanceof Number) && (typeof b[i] === 'number' || b[i] instanceof Number)) { + retArr[i] = a[i] + b[i]; + } else { + retArr[i] = b[i] === undefined ? a[i] : a[i] || b[i]; + } + i += 1; + } + return retArr; + } + return 0; + } + var add = sum; + + function sub(a, b) { + var tOfA = typeof a; + var tOfB = typeof b; + if (isNumerable(tOfA, a) && isNumerable(tOfB, b)) { + if (tOfA === 'string') { + a = parseInt(a); + } + if (tOfB === 'string') { + b = parseInt(b); + } + return a - b; + } + if ($bm_isInstanceOfArray(a) && isNumerable(tOfB, b)) { + a = a.slice(0); + a[0] = a[0] - b; + return a; + } + if (isNumerable(tOfA, a) && $bm_isInstanceOfArray(b)) { + b = b.slice(0); + b[0] = a - b[0]; + return b; + } + if ($bm_isInstanceOfArray(a) && $bm_isInstanceOfArray(b)) { + var i = 0, lenA = a.length, lenB = b.length; + var retArr = []; + while (i < lenA || i < lenB) { + if ((typeof a[i] === 'number' || a[i] instanceof Number) && (typeof b[i] === 'number' || b[i] instanceof Number)) { + retArr[i] = a[i] - b[i]; + } else { + retArr[i] = b[i] === undefined ? a[i] : a[i] || b[i]; + } + i += 1; + } + return retArr; + } + return 0; + } + + function mul(a, b) { + var tOfA = typeof a; + var tOfB = typeof b; + var arr; + if (isNumerable(tOfA, a) && isNumerable(tOfB, b)) { + return a * b; + } + + var i, len; + if ($bm_isInstanceOfArray(a) && isNumerable(tOfB, b)) { + len = a.length; + arr = createTypedArray('float32', len); + for (i = 0; i < len; i += 1) { + arr[i] = a[i] * b; + } + return arr; + } + if (isNumerable(tOfA, a) && $bm_isInstanceOfArray(b)) { + len = b.length; + arr = createTypedArray('float32', len); + for (i = 0; i < len; i += 1) { + arr[i] = a * b[i]; + } + return arr; + } + return 0; + } + + function div(a, b) { + var tOfA = typeof a; + var tOfB = typeof b; + var arr; + if (isNumerable(tOfA, a) && isNumerable(tOfB, b)) { + return a / b; + } + var i, len; + if ($bm_isInstanceOfArray(a) && isNumerable(tOfB, b)) { + len = a.length; + arr = createTypedArray('float32', len); + for (i = 0; i < len; i += 1) { + arr[i] = a[i] / b; + } + return arr; + } + if (isNumerable(tOfA, a) && $bm_isInstanceOfArray(b)) { + len = b.length; + arr = createTypedArray('float32', len); + for (i = 0; i < len; i += 1) { + arr[i] = a / b[i]; + } + return arr; + } + return 0; + } + function mod(a, b) { + if (typeof a === 'string') { + a = parseInt(a); + } + if (typeof b === 'string') { + b = parseInt(b); + } + return a % b; + } + var $bm_sum = sum; + var $bm_sub = sub; + var $bm_mul = mul; + var $bm_div = div; + var $bm_mod = mod; + + function clamp(num, min, max) { + if (min > max) { + var mm = max; + max = min; + min = mm; + } + return Math.min(Math.max(num, min), max); + } + + function radiansToDegrees(val) { + return val / degToRads; + } + var radians_to_degrees = radiansToDegrees; + + function degreesToRadians(val) { + return val * degToRads; + } + var degrees_to_radians = radiansToDegrees; + + var helperLengthArray = [0, 0, 0, 0, 0, 0]; + + function length(arr1, arr2) { + if (typeof arr1 === 'number' || arr1 instanceof Number) { + arr2 = arr2 || 0; + return Math.abs(arr1 - arr2); + } + if (!arr2) { + arr2 = helperLengthArray; + } + var i, len = Math.min(arr1.length, arr2.length); + var addedLength = 0; + for (i = 0; i < len; i += 1) { + addedLength += Math.pow(arr2[i] - arr1[i], 2); + } + return Math.sqrt(addedLength); + } + + function normalize(vec) { + return div(vec, length(vec)); + } + + function rgbToHsl(val) { + var r = val[0]; var g = val[1]; var b = val[2]; + var max = Math.max(r, g, b), min = Math.min(r, g, b); + var h, s, l = (max + min) / 2; + + if (max == min) { + h = s = 0; // achromatic + } else { + var d = max - min; + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + switch (max) { + case r: h = (g - b) / d + (g < b ? 6 : 0); break; + case g: h = (b - r) / d + 2; break; + case b: h = (r - g) / d + 4; break; + } + h /= 6; + } + + return [h, s, l, val[3]]; + } + + function hue2rgb(p, q, t) { + if (t < 0) t += 1; + if (t > 1) t -= 1; + if (t < 1 / 6) return p + (q - p) * 6 * t; + if (t < 1 / 2) return q; + if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; + return p; + } + + function hslToRgb(val) { + var h = val[0]; + var s = val[1]; + var l = val[2]; + + var r, g, b; + + if (s === 0) { + r = g = b = l; // achromatic + } else { + + var q = l < 0.5 ? l * (1 + s) : l + s - l * s; + var p = 2 * l - q; + r = hue2rgb(p, q, h + 1 / 3); + g = hue2rgb(p, q, h); + b = hue2rgb(p, q, h - 1 / 3); + } + + return [r, g, b, val[3]]; + } + + function linear(t, tMin, tMax, value1, value2) { + if (value1 === undefined || value2 === undefined) { + value1 = tMin; + value2 = tMax; + tMin = 0; + tMax = 1; + } + if (tMax < tMin) { + var _tMin = tMax; + tMax = tMin; + tMin = _tMin; + } + if (t <= tMin) { + return value1; + } else if (t >= tMax) { + return value2; + } + var perc = tMax === tMin ? 0 : (t - tMin) / (tMax - tMin); + if (!value1.length) { + return value1 + (value2 - value1) * perc; + } + var i, len = value1.length; + var arr = createTypedArray('float32', len); + for (i = 0; i < len; i += 1) { + arr[i] = value1[i] + (value2[i] - value1[i]) * perc; + } + return arr; + } + function random(min, max) { + if (max === undefined) { + if (min === undefined) { + min = 0; + max = 1; + } else { + max = min; + min = undefined; + } + } + if (max.length) { + var i, len = max.length; + if (!min) { + min = createTypedArray('float32', len); + } + var arr = createTypedArray('float32', len); + var rnd = BMMath.random(); + for (i = 0; i < len; i += 1) { + arr[i] = min[i] + rnd * (max[i] - min[i]); + } + return arr; + } + if (min === undefined) { + min = 0; + } + var rndm = BMMath.random(); + return min + rndm * (max - min); + } + + function createPath(points, inTangents, outTangents, closed) { + var i, len = points.length; + var path = shape_pool.newElement(); + path.setPathData(!!closed, len); + var arrPlaceholder = [0, 0], inVertexPoint, outVertexPoint; + for (i = 0; i < len; i += 1) { + inVertexPoint = (inTangents && inTangents[i]) ? inTangents[i] : arrPlaceholder; + outVertexPoint = (outTangents && outTangents[i]) ? outTangents[i] : arrPlaceholder; + path.setTripleAt(points[i][0], points[i][1], outVertexPoint[0] + points[i][0], outVertexPoint[1] + points[i][1], inVertexPoint[0] + points[i][0], inVertexPoint[1] + points[i][1], i, true); + } + return path; + } + + function initiateExpression(elem, data, property) { + var val = data.x; + var needsVelocity = /velocity(?![\w\d])/.test(val); + var _needsRandom = val.indexOf('random') !== -1; + var elemType = elem.data.ty; + var transform, $bm_transform, content, effect; + var thisProperty = property; + thisProperty.valueAtTime = thisProperty.getValueAtTime; + Object.defineProperty(thisProperty, 'value', { + get: function () { + return thisProperty.v + } + }) + elem.comp.frameDuration = 1 / elem.comp.globalData.frameRate; + elem.comp.displayStartTime = 0; + var inPoint = elem.data.ip / elem.comp.globalData.frameRate; + var outPoint = elem.data.op / elem.comp.globalData.frameRate; + var width = elem.data.sw ? elem.data.sw : 0; + var height = elem.data.sh ? elem.data.sh : 0; + var name = elem.data.nm; + var loopIn, loop_in, loopOut, loop_out, smooth; + var toWorld, fromWorld, fromComp, toComp, fromCompToSurface, position, rotation, anchorPoint, scale, thisLayer, thisComp, mask, valueAtTime, velocityAtTime; + var __expression_functions = []; + if (data.xf) { + var i, len = data.xf.length; + for (i = 0; i < len; i += 1) { + __expression_functions[i] = eval('(function(){ return ' + data.xf[i] + '}())'); + } + } + + var scoped_bm_rt; + var expression_function = eval('[function _expression_function(){' + val + ';scoped_bm_rt=$bm_rt}' + ']')[0]; + var numKeys = property.kf ? data.k.length : 0; + + var active = !this.data || this.data.hd !== true; + + var wiggle = function wiggle(freq, amp) { + var i, j, len = this.pv.length ? this.pv.length : 1; + var addedAmps = createTypedArray('float32', len); + freq = 5; + var iterations = Math.floor(time * freq); + i = 0; + j = 0; + while (i < iterations) { + //var rnd = BMMath.random(); + for (j = 0; j < len; j += 1) { + addedAmps[j] += -amp + amp * 2 * BMMath.random(); + //addedAmps[j] += -amp + amp*2*rnd; + } + i += 1; + } + //var rnd2 = BMMath.random(); + var periods = time * freq; + var perc = periods - Math.floor(periods); + var arr = createTypedArray('float32', len); + if (len > 1) { + for (j = 0; j < len; j += 1) { + arr[j] = this.pv[j] + addedAmps[j] + (-amp + amp * 2 * BMMath.random()) * perc; + //arr[j] = this.pv[j] + addedAmps[j] + (-amp + amp*2*rnd)*perc; + //arr[i] = this.pv[i] + addedAmp + amp1*perc + amp2*(1-perc); + } + return arr; + } else { + return this.pv + addedAmps[0] + (-amp + amp * 2 * BMMath.random()) * perc; + } + }.bind(this); + + if (thisProperty.loopIn) { + loopIn = thisProperty.loopIn.bind(thisProperty); + loop_in = loopIn; + } + + if (thisProperty.loopOut) { + loopOut = thisProperty.loopOut.bind(thisProperty); + loop_out = loopOut; + } + + if (thisProperty.smooth) { + smooth = thisProperty.smooth.bind(thisProperty); + } + + function loopInDuration(type, duration) { + return loopIn(type, duration, true); + } + + function loopOutDuration(type, duration) { + return loopOut(type, duration, true); + } + + if (this.getValueAtTime) { + valueAtTime = this.getValueAtTime.bind(this); + } + + if (this.getVelocityAtTime) { + velocityAtTime = this.getVelocityAtTime.bind(this); + } + + var comp = elem.comp.globalData.projectInterface.bind(elem.comp.globalData.projectInterface); + + function lookAt(elem1, elem2) { + var fVec = [elem2[0] - elem1[0], elem2[1] - elem1[1], elem2[2] - elem1[2]]; + var pitch = Math.atan2(fVec[0], Math.sqrt(fVec[1] * fVec[1] + fVec[2] * fVec[2])) / degToRads; + var yaw = -Math.atan2(fVec[1], fVec[2]) / degToRads; + return [yaw, pitch, 0]; + } + + function easeOut(t, tMin, tMax, val1, val2) { + return applyEase(easeOutBez, t, tMin, tMax, val1, val2); + } + + function easeIn(t, tMin, tMax, val1, val2) { + return applyEase(easeInBez, t, tMin, tMax, val1, val2); + } + + function ease(t, tMin, tMax, val1, val2) { + return applyEase(easeInOutBez, t, tMin, tMax, val1, val2); + } + + function applyEase(fn, t, tMin, tMax, val1, val2) { + if (val1 === undefined) { + val1 = tMin; + val2 = tMax; + } else { + t = (t - tMin) / (tMax - tMin); + } + t = t > 1 ? 1 : t < 0 ? 0 : t; + var mult = fn(t); + if ($bm_isInstanceOfArray(val1)) { + var i, len = val1.length; + var arr = createTypedArray('float32', len); + for (i = 0; i < len; i += 1) { + arr[i] = (val2[i] - val1[i]) * mult + val1[i]; + } + return arr; + } else { + return (val2 - val1) * mult + val1; + } + } + + function nearestKey(time) { + var i, len = data.k.length, index, keyTime; + if (!data.k.length || typeof (data.k[0]) === 'number') { + index = 0; + keyTime = 0; + } else { + index = -1; + time *= elem.comp.globalData.frameRate; + if (time < data.k[0].t) { + index = 1; + keyTime = data.k[0].t; + } else { + for (i = 0; i < len - 1; i += 1) { + if (time === data.k[i].t) { + index = i + 1; + keyTime = data.k[i].t; + break; + } else if (time > data.k[i].t && time < data.k[i + 1].t) { + if (time - data.k[i].t > data.k[i + 1].t - time) { + index = i + 2; + keyTime = data.k[i + 1].t; + } else { + index = i + 1; + keyTime = data.k[i].t; + } + break; + } + } + if (index === -1) { + index = i + 1; + keyTime = data.k[i].t; + } + } + + } + var ob = {}; + ob.index = index; + ob.time = keyTime / elem.comp.globalData.frameRate; + return ob; + } + + function key(ind) { + var ob, i, len; + if (!data.k.length || typeof (data.k[0]) === 'number') { + throw new Error('The property has no keyframe at index ' + ind); + } + ind -= 1; + ob = { + time: data.k[ind].t / elem.comp.globalData.frameRate, + value: [] + }; + var arr = data.k[ind].hasOwnProperty('s') ? data.k[ind].s : data.k[ind - 1].e; + + len = arr.length; + for (i = 0; i < len; i += 1) { + ob[i] = arr[i]; + ob.value[i] = arr[i] + } + return ob; + } + + function framesToTime(frames, fps) { + if (!fps) { + fps = elem.comp.globalData.frameRate; + } + return frames / fps; + } + + function timeToFrames(t, fps) { + if (!t && t !== 0) { + t = time; + } + if (!fps) { + fps = elem.comp.globalData.frameRate; + } + return t * fps; + } + + function seedRandom(seed) { + BMMath.seedrandom(randSeed + seed); + } + + function sourceRectAtTime() { + return elem.sourceRectAtTime(); + } + + function substring(init, end) { + if (typeof value === 'string') { + if (end === undefined) { + return value.substring(init) + } + return value.substring(init, end) + } + return ''; + } + + function substr(init, end) { + if (typeof value === 'string') { + if (end === undefined) { + return value.substr(init) + } + return value.substr(init, end) + } + return ''; + } + + function posterizeTime(framesPerSecond) { + time = framesPerSecond === 0 ? 0 : Math.floor(time * framesPerSecond) / framesPerSecond + value = valueAtTime(time) + } + + var time, velocity, value, text, textIndex, textTotal, selectorValue; + var index = elem.data.ind; + var hasParent = !!(elem.hierarchy && elem.hierarchy.length); + var parent; + var randSeed = Math.floor(Math.random() * 1000000); + var globalData = elem.globalData; + function executeExpression(_value) { + // globalData.pushExpression(); + value = _value; + if (_needsRandom) { + seedRandom(randSeed); + } + if (this.frameExpressionId === elem.globalData.frameId && this.propType !== 'textSelector') { + return value; + } + if (this.propType === 'textSelector') { + textIndex = this.textIndex; + textTotal = this.textTotal; + selectorValue = this.selectorValue; + } + if (!thisLayer) { + text = elem.layerInterface.text; + thisLayer = elem.layerInterface; + thisComp = elem.comp.compInterface; + toWorld = thisLayer.toWorld.bind(thisLayer); + fromWorld = thisLayer.fromWorld.bind(thisLayer); + fromComp = thisLayer.fromComp.bind(thisLayer); + toComp = thisLayer.toComp.bind(thisLayer); + mask = thisLayer.mask ? thisLayer.mask.bind(thisLayer) : null; + fromCompToSurface = fromComp; + } + if (!transform) { + transform = elem.layerInterface("ADBE Transform Group"); + $bm_transform = transform; + if (transform) { + anchorPoint = transform.anchorPoint; + /*position = transform.position; + rotation = transform.rotation; + scale = transform.scale;*/ + } + } + + if (elemType === 4 && !content) { + content = thisLayer("ADBE Root Vectors Group"); + } + if (!effect) { + effect = thisLayer(4); + } + hasParent = !!(elem.hierarchy && elem.hierarchy.length); + if (hasParent && !parent) { + parent = elem.hierarchy[0].layerInterface; + } + time = this.comp.renderedFrame / this.comp.globalData.frameRate; + if (needsVelocity) { + velocity = velocityAtTime(time); + } + expression_function(); + this.frameExpressionId = elem.globalData.frameId; + + + //TODO: Check if it's possible to return on ShapeInterface the .v value + if (scoped_bm_rt.propType === "shape") { + scoped_bm_rt = scoped_bm_rt.v; + } + // globalData.popExpression(); + return scoped_bm_rt; + } + return executeExpression; + } + + ob.initiateExpression = initiateExpression; + return ob; + }()); + var expressionHelpers = (function () { + + function searchExpressions(elem, data, prop) { + if (data.x) { + prop.k = true; + prop.x = true; + prop.initiateExpression = ExpressionManager.initiateExpression; + prop.effectsSequence.push(prop.initiateExpression(elem, data, prop).bind(prop)); + } + } + + function getValueAtTime(frameNum) { + frameNum *= this.elem.globalData.frameRate; + frameNum -= this.offsetTime; + if (frameNum !== this._cachingAtTime.lastFrame) { + this._cachingAtTime.lastIndex = this._cachingAtTime.lastFrame < frameNum ? this._cachingAtTime.lastIndex : 0; + this._cachingAtTime.value = this.interpolateValue(frameNum, this._cachingAtTime); + this._cachingAtTime.lastFrame = frameNum; + } + return this._cachingAtTime.value; + + } + + function getSpeedAtTime(frameNum) { + var delta = -0.01; + var v1 = this.getValueAtTime(frameNum); + var v2 = this.getValueAtTime(frameNum + delta); + var speed = 0; + if (v1.length) { + var i; + for (i = 0; i < v1.length; i += 1) { + speed += Math.pow(v2[i] - v1[i], 2); + } + speed = Math.sqrt(speed) * 100; + } else { + speed = 0; + } + return speed; + } + + function getVelocityAtTime(frameNum) { + if (this.vel !== undefined) { + return this.vel; + } + var delta = -0.001; + //frameNum += this.elem.data.st; + var v1 = this.getValueAtTime(frameNum); + var v2 = this.getValueAtTime(frameNum + delta); + var velocity; + if (v1.length) { + velocity = createTypedArray('float32', v1.length); + var i; + for (i = 0; i < v1.length; i += 1) { + //removing frameRate + //if needed, don't add it here + //velocity[i] = this.elem.globalData.frameRate*((v2[i] - v1[i])/delta); + velocity[i] = (v2[i] - v1[i]) / delta; + } + } else { + velocity = (v2 - v1) / delta; + } + return velocity; + } + + function getStaticValueAtTime() { + return this.pv; + } + + function setGroupProperty(propertyGroup) { + this.propertyGroup = propertyGroup; + } + + return { + searchExpressions: searchExpressions, + getSpeedAtTime: getSpeedAtTime, + getVelocityAtTime: getVelocityAtTime, + getValueAtTime: getValueAtTime, + getStaticValueAtTime: getStaticValueAtTime, + setGroupProperty: setGroupProperty, + } + }()); + (function addPropertyDecorator() { + + function loopOut(type, duration, durationFlag) { + if (!this.k || !this.keyframes) { + return this.pv; + } + type = type ? type.toLowerCase() : ''; + var currentFrame = this.comp.renderedFrame; + var keyframes = this.keyframes; + var lastKeyFrame = keyframes[keyframes.length - 1].t; + if (currentFrame <= lastKeyFrame) { + return this.pv; + } else { + var cycleDuration, firstKeyFrame; + if (!durationFlag) { + if (!duration || duration > keyframes.length - 1) { + duration = keyframes.length - 1; + } + firstKeyFrame = keyframes[keyframes.length - 1 - duration].t; + cycleDuration = lastKeyFrame - firstKeyFrame; + } else { + if (!duration) { + cycleDuration = Math.max(0, lastKeyFrame - this.elem.data.ip); + } else { + cycleDuration = Math.abs(lastKeyFrame - elem.comp.globalData.frameRate * duration); + } + firstKeyFrame = lastKeyFrame - cycleDuration; + } + var i, len, ret; + if (type === 'pingpong') { + var iterations = Math.floor((currentFrame - firstKeyFrame) / cycleDuration); + if (iterations % 2 !== 0) { + return this.getValueAtTime(((cycleDuration - (currentFrame - firstKeyFrame) % cycleDuration + firstKeyFrame)) / this.comp.globalData.frameRate, 0); + } + } else if (type === 'offset') { + var initV = this.getValueAtTime(firstKeyFrame / this.comp.globalData.frameRate, 0); + var endV = this.getValueAtTime(lastKeyFrame / this.comp.globalData.frameRate, 0); + var current = this.getValueAtTime(((currentFrame - firstKeyFrame) % cycleDuration + firstKeyFrame) / this.comp.globalData.frameRate, 0); + var repeats = Math.floor((currentFrame - firstKeyFrame) / cycleDuration); + if (this.pv.length) { + ret = new Array(initV.length); + len = ret.length; + for (i = 0; i < len; i += 1) { + ret[i] = (endV[i] - initV[i]) * repeats + current[i]; + } + return ret; + } + return (endV - initV) * repeats + current; + } else if (type === 'continue') { + var lastValue = this.getValueAtTime(lastKeyFrame / this.comp.globalData.frameRate, 0); + var nextLastValue = this.getValueAtTime((lastKeyFrame - 0.001) / this.comp.globalData.frameRate, 0); + if (this.pv.length) { + ret = new Array(lastValue.length); + len = ret.length; + for (i = 0; i < len; i += 1) { + ret[i] = lastValue[i] + (lastValue[i] - nextLastValue[i]) * ((currentFrame - lastKeyFrame) / this.comp.globalData.frameRate) / 0.0005; + } + return ret; + } + return lastValue + (lastValue - nextLastValue) * (((currentFrame - lastKeyFrame)) / 0.001); + } + return this.getValueAtTime((((currentFrame - firstKeyFrame) % cycleDuration + firstKeyFrame)) / this.comp.globalData.frameRate, 0); + } + } + + function loopIn(type, duration, durationFlag) { + if (!this.k) { + return this.pv; + } + type = type ? type.toLowerCase() : ''; + var currentFrame = this.comp.renderedFrame; + var keyframes = this.keyframes; + var firstKeyFrame = keyframes[0].t; + if (currentFrame >= firstKeyFrame) { + return this.pv; + } else { + var cycleDuration, lastKeyFrame; + if (!durationFlag) { + if (!duration || duration > keyframes.length - 1) { + duration = keyframes.length - 1; + } + lastKeyFrame = keyframes[duration].t; + cycleDuration = lastKeyFrame - firstKeyFrame; + } else { + if (!duration) { + cycleDuration = Math.max(0, this.elem.data.op - firstKeyFrame); + } else { + cycleDuration = Math.abs(elem.comp.globalData.frameRate * duration); + } + lastKeyFrame = firstKeyFrame + cycleDuration; + } + var i, len, ret; + if (type === 'pingpong') { + var iterations = Math.floor((firstKeyFrame - currentFrame) / cycleDuration); + if (iterations % 2 === 0) { + return this.getValueAtTime((((firstKeyFrame - currentFrame) % cycleDuration + firstKeyFrame)) / this.comp.globalData.frameRate, 0); + } + } else if (type === 'offset') { + var initV = this.getValueAtTime(firstKeyFrame / this.comp.globalData.frameRate, 0); + var endV = this.getValueAtTime(lastKeyFrame / this.comp.globalData.frameRate, 0); + var current = this.getValueAtTime((cycleDuration - (firstKeyFrame - currentFrame) % cycleDuration + firstKeyFrame) / this.comp.globalData.frameRate, 0); + var repeats = Math.floor((firstKeyFrame - currentFrame) / cycleDuration) + 1; + if (this.pv.length) { + ret = new Array(initV.length); + len = ret.length; + for (i = 0; i < len; i += 1) { + ret[i] = current[i] - (endV[i] - initV[i]) * repeats; + } + return ret; + } + return current - (endV - initV) * repeats; + } else if (type === 'continue') { + var firstValue = this.getValueAtTime(firstKeyFrame / this.comp.globalData.frameRate, 0); + var nextFirstValue = this.getValueAtTime((firstKeyFrame + 0.001) / this.comp.globalData.frameRate, 0); + if (this.pv.length) { + ret = new Array(firstValue.length); + len = ret.length; + for (i = 0; i < len; i += 1) { + ret[i] = firstValue[i] + (firstValue[i] - nextFirstValue[i]) * (firstKeyFrame - currentFrame) / 0.001; + } + return ret; + } + return firstValue + (firstValue - nextFirstValue) * (firstKeyFrame - currentFrame) / 0.001; + } + return this.getValueAtTime(((cycleDuration - (firstKeyFrame - currentFrame) % cycleDuration + firstKeyFrame)) / this.comp.globalData.frameRate, 0); + } + } + + function smooth(width, samples) { + if (!this.k) { + return this.pv; + } + width = (width || 0.4) * 0.5; + samples = Math.floor(samples || 5); + if (samples <= 1) { + return this.pv; + } + var currentTime = this.comp.renderedFrame / this.comp.globalData.frameRate; + var initFrame = currentTime - width; + var endFrame = currentTime + width; + var sampleFrequency = samples > 1 ? (endFrame - initFrame) / (samples - 1) : 1; + var i = 0, j = 0; + var value; + if (this.pv.length) { + value = createTypedArray('float32', this.pv.length); + } else { + value = 0; + } + var sampleValue; + while (i < samples) { + sampleValue = this.getValueAtTime(initFrame + i * sampleFrequency); + if (this.pv.length) { + for (j = 0; j < this.pv.length; j += 1) { + value[j] += sampleValue[j]; + } + } else { + value += sampleValue; + } + i += 1; + } + if (this.pv.length) { + for (j = 0; j < this.pv.length; j += 1) { + value[j] /= samples; + } + } else { + value /= samples; + } + return value; + } + + function getValueAtTime(frameNum) { + frameNum *= this.elem.globalData.frameRate; + frameNum -= this.offsetTime; + if (frameNum !== this._cachingAtTime.lastFrame) { + this._cachingAtTime.lastIndex = this._cachingAtTime.lastFrame < frameNum ? this._cachingAtTime.lastIndex : 0; + this._cachingAtTime.value = this.interpolateValue(frameNum, this._cachingAtTime); + this._cachingAtTime.lastFrame = frameNum; + } + return this._cachingAtTime.value; + + } + + function getTransformValueAtTime(time) { + console.warn('Transform at time not supported'); + } + + function getTransformStaticValueAtTime(time) { + + } + + var getTransformProperty = TransformPropertyFactory.getTransformProperty; + TransformPropertyFactory.getTransformProperty = function (elem, data, container) { + var prop = getTransformProperty(elem, data, container); + if (prop.dynamicProperties.length) { + prop.getValueAtTime = getTransformValueAtTime.bind(prop); + } else { + prop.getValueAtTime = getTransformStaticValueAtTime.bind(prop); + } + prop.setGroupProperty = expressionHelpers.setGroupProperty; + return prop; + }; + + var propertyGetProp = PropertyFactory.getProp; + PropertyFactory.getProp = function (elem, data, type, mult, container) { + var prop = propertyGetProp(elem, data, type, mult, container); + //prop.getVelocityAtTime = getVelocityAtTime; + //prop.loopOut = loopOut; + //prop.loopIn = loopIn; + if (prop.kf) { + prop.getValueAtTime = expressionHelpers.getValueAtTime.bind(prop); + } else { + prop.getValueAtTime = expressionHelpers.getStaticValueAtTime.bind(prop); + } + prop.setGroupProperty = expressionHelpers.setGroupProperty; + prop.loopOut = loopOut; + prop.loopIn = loopIn; + prop.smooth = smooth; + prop.getVelocityAtTime = expressionHelpers.getVelocityAtTime.bind(prop); + prop.getSpeedAtTime = expressionHelpers.getSpeedAtTime.bind(prop); + prop.numKeys = data.a === 1 ? data.k.length : 0; + prop.propertyIndex = data.ix; + var value = 0; + if (type !== 0) { + value = createTypedArray('float32', data.a === 1 ? data.k[0].s.length : data.k.length); + } + prop._cachingAtTime = { + lastFrame: initialDefaultFrame, + lastIndex: 0, + value: value + }; + expressionHelpers.searchExpressions(elem, data, prop); + if (prop.k) { + container.addDynamicProperty(prop); + } + + return prop; + }; + + function getShapeValueAtTime(frameNum) { + //For now this caching object is created only when needed instead of creating it when the shape is initialized. + if (!this._cachingAtTime) { + this._cachingAtTime = { + shapeValue: shape_pool.clone(this.pv), + lastIndex: 0, + lastTime: initialDefaultFrame + }; + } + + frameNum *= this.elem.globalData.frameRate; + frameNum -= this.offsetTime; + if (frameNum !== this._cachingAtTime.lastTime) { + this._cachingAtTime.lastIndex = this._cachingAtTime.lastTime < frameNum ? this._caching.lastIndex : 0; + this._cachingAtTime.lastTime = frameNum; + this.interpolateShape(frameNum, this._cachingAtTime.shapeValue, this._cachingAtTime); + } + return this._cachingAtTime.shapeValue; + } + + var ShapePropertyConstructorFunction = ShapePropertyFactory.getConstructorFunction(); + var KeyframedShapePropertyConstructorFunction = ShapePropertyFactory.getKeyframedConstructorFunction(); + + function ShapeExpressions() { } + ShapeExpressions.prototype = { + vertices: function (prop, time) { + if (this.k) { + this.getValue(); + } + var shapePath = this.v; + if (time !== undefined) { + shapePath = this.getValueAtTime(time, 0); + } + var i, len = shapePath._length; + var vertices = shapePath[prop]; + var points = shapePath.v; + var arr = createSizedArray(len); + for (i = 0; i < len; i += 1) { + if (prop === 'i' || prop === 'o') { + arr[i] = [vertices[i][0] - points[i][0], vertices[i][1] - points[i][1]]; + } else { + arr[i] = [vertices[i][0], vertices[i][1]]; + } + + } + return arr; + }, + points: function (time) { + return this.vertices('v', time); + }, + inTangents: function (time) { + return this.vertices('i', time); + }, + outTangents: function (time) { + return this.vertices('o', time); + }, + isClosed: function () { + return this.v.c; + }, + pointOnPath: function (perc, time) { + var shapePath = this.v; + if (time !== undefined) { + shapePath = this.getValueAtTime(time, 0); + } + if (!this._segmentsLength) { + this._segmentsLength = bez.getSegmentsLength(shapePath); + } + + var segmentsLength = this._segmentsLength; + var lengths = segmentsLength.lengths; + var lengthPos = segmentsLength.totalLength * perc; + var i = 0, len = lengths.length; + var j = 0, jLen; + var accumulatedLength = 0, pt; + while (i < len) { + if (accumulatedLength + lengths[i].addedLength > lengthPos) { + var initIndex = i; + var endIndex = (shapePath.c && i === len - 1) ? 0 : i + 1; + var segmentPerc = (lengthPos - accumulatedLength) / lengths[i].addedLength; + pt = bez.getPointInSegment(shapePath.v[initIndex], shapePath.v[endIndex], shapePath.o[initIndex], shapePath.i[endIndex], segmentPerc, lengths[i]); + break; + } else { + accumulatedLength += lengths[i].addedLength; + } + i += 1; + } + if (!pt) { + pt = shapePath.c ? [shapePath.v[0][0], shapePath.v[0][1]] : [shapePath.v[shapePath._length - 1][0], shapePath.v[shapePath._length - 1][1]]; + } + return pt; + }, + vectorOnPath: function (perc, time, vectorType) { + //perc doesn't use triple equality because it can be a Number object as well as a primitive. + perc = perc == 1 ? this.v.c ? 0 : 0.999 : perc; + var pt1 = this.pointOnPath(perc, time); + var pt2 = this.pointOnPath(perc + 0.001, time); + var xLength = pt2[0] - pt1[0]; + var yLength = pt2[1] - pt1[1]; + var magnitude = Math.sqrt(Math.pow(xLength, 2) + Math.pow(yLength, 2)); + if (magnitude === 0) { + return [0, 0]; + } + var unitVector = vectorType === 'tangent' ? [xLength / magnitude, yLength / magnitude] : [-yLength / magnitude, xLength / magnitude]; + return unitVector; + }, + tangentOnPath: function (perc, time) { + return this.vectorOnPath(perc, time, 'tangent'); + }, + normalOnPath: function (perc, time) { + return this.vectorOnPath(perc, time, 'normal'); + }, + setGroupProperty: expressionHelpers.setGroupProperty, + getValueAtTime: expressionHelpers.getStaticValueAtTime + }; + extendPrototype([ShapeExpressions], ShapePropertyConstructorFunction); + extendPrototype([ShapeExpressions], KeyframedShapePropertyConstructorFunction); + KeyframedShapePropertyConstructorFunction.prototype.getValueAtTime = getShapeValueAtTime; + KeyframedShapePropertyConstructorFunction.prototype.initiateExpression = ExpressionManager.initiateExpression; + + var propertyGetShapeProp = ShapePropertyFactory.getShapeProp; + ShapePropertyFactory.getShapeProp = function (elem, data, type, arr, trims) { + var prop = propertyGetShapeProp(elem, data, type, arr, trims); + prop.propertyIndex = data.ix; + prop.lock = false; + if (type === 3) { + expressionHelpers.searchExpressions(elem, data.pt, prop); + } else if (type === 4) { + expressionHelpers.searchExpressions(elem, data.ks, prop); + } + if (prop.k) { + elem.addDynamicProperty(prop); + } + return prop; + }; + }()); + (function addDecorator() { + + function searchExpressions() { + if (this.data.d.x) { + this.calculateExpression = ExpressionManager.initiateExpression.bind(this)(this.elem, this.data.d, this); + this.addEffect(this.getExpressionValue.bind(this)); + return true; + } + } + + TextProperty.prototype.getExpressionValue = function (currentValue, text) { + var newValue = this.calculateExpression(text); + if (currentValue.t !== newValue) { + var newData = {}; + this.copyData(newData, currentValue); + newData.t = newValue.toString(); + newData.__complete = false; + return newData; + } + return currentValue; + } + + TextProperty.prototype.searchProperty = function () { + + var isKeyframed = this.searchKeyframes(); + var hasExpressions = this.searchExpressions(); + this.kf = isKeyframed || hasExpressions; + return this.kf; + }; + + TextProperty.prototype.searchExpressions = searchExpressions; + + }()); + var ShapeExpressionInterface = (function () { + + function iterateElements(shapes, view, propertyGroup) { + var arr = []; + var i, len = shapes ? shapes.length : 0; + for (i = 0; i < len; i += 1) { + if (shapes[i].ty == 'gr') { + arr.push(groupInterfaceFactory(shapes[i], view[i], propertyGroup)); + } else if (shapes[i].ty == 'fl') { + arr.push(fillInterfaceFactory(shapes[i], view[i], propertyGroup)); + } else if (shapes[i].ty == 'st') { + arr.push(strokeInterfaceFactory(shapes[i], view[i], propertyGroup)); + } else if (shapes[i].ty == 'tm') { + arr.push(trimInterfaceFactory(shapes[i], view[i], propertyGroup)); + } else if (shapes[i].ty == 'tr') { + //arr.push(transformInterfaceFactory(shapes[i],view[i],propertyGroup)); + } else if (shapes[i].ty == 'el') { + arr.push(ellipseInterfaceFactory(shapes[i], view[i], propertyGroup)); + } else if (shapes[i].ty == 'sr') { + arr.push(starInterfaceFactory(shapes[i], view[i], propertyGroup)); + } else if (shapes[i].ty == 'sh') { + arr.push(pathInterfaceFactory(shapes[i], view[i], propertyGroup)); + } else if (shapes[i].ty == 'rc') { + arr.push(rectInterfaceFactory(shapes[i], view[i], propertyGroup)); + } else if (shapes[i].ty == 'rd') { + arr.push(roundedInterfaceFactory(shapes[i], view[i], propertyGroup)); + } else if (shapes[i].ty == 'rp') { + arr.push(repeaterInterfaceFactory(shapes[i], view[i], propertyGroup)); + } + } + return arr; + } + + function contentsInterfaceFactory(shape, view, propertyGroup) { + var interfaces; + var interfaceFunction = function _interfaceFunction(value) { + var i = 0, len = interfaces.length; + while (i < len) { + if (interfaces[i]._name === value || interfaces[i].mn === value || interfaces[i].propertyIndex === value || interfaces[i].ix === value || interfaces[i].ind === value) { + return interfaces[i]; + } + i += 1; + } + if (typeof value === 'number') { + return interfaces[value - 1]; + } + }; + interfaceFunction.propertyGroup = function (val) { + if (val === 1) { + return interfaceFunction; + } else { + return propertyGroup(val - 1); + } + }; + interfaces = iterateElements(shape.it, view.it, interfaceFunction.propertyGroup); + interfaceFunction.numProperties = interfaces.length; + interfaceFunction.propertyIndex = shape.cix; + interfaceFunction._name = shape.nm; + + return interfaceFunction; + } + + function groupInterfaceFactory(shape, view, propertyGroup) { + var interfaceFunction = function _interfaceFunction(value) { + switch (value) { + case 'ADBE Vectors Group': + case 'Contents': + case 2: + return interfaceFunction.content; + //Not necessary for now. Keeping them here in case a new case appears + //case 'ADBE Vector Transform Group': + //case 3: + default: + return interfaceFunction.transform; + } + }; + interfaceFunction.propertyGroup = function (val) { + if (val === 1) { + return interfaceFunction; + } else { + return propertyGroup(val - 1); + } + }; + var content = contentsInterfaceFactory(shape, view, interfaceFunction.propertyGroup); + var transformInterface = transformInterfaceFactory(shape.it[shape.it.length - 1], view.it[view.it.length - 1], interfaceFunction.propertyGroup); + interfaceFunction.content = content; + interfaceFunction.transform = transformInterface; + Object.defineProperty(interfaceFunction, '_name', { + get: function () { + return shape.nm; + } + }); + //interfaceFunction.content = interfaceFunction; + interfaceFunction.numProperties = shape.np; + interfaceFunction.propertyIndex = shape.ix; + interfaceFunction.nm = shape.nm; + interfaceFunction.mn = shape.mn; + return interfaceFunction; + } + + function fillInterfaceFactory(shape, view, propertyGroup) { + function interfaceFunction(val) { + if (val === 'Color' || val === 'color') { + return interfaceFunction.color; + } else if (val === 'Opacity' || val === 'opacity') { + return interfaceFunction.opacity; + } + } + Object.defineProperties(interfaceFunction, { + 'color': { + get: ExpressionPropertyInterface(view.c) + }, + 'opacity': { + get: ExpressionPropertyInterface(view.o) + }, + '_name': { value: shape.nm }, + 'mn': { value: shape.mn } + }); + + view.c.setGroupProperty(propertyGroup); + view.o.setGroupProperty(propertyGroup); + return interfaceFunction; + } + + function strokeInterfaceFactory(shape, view, propertyGroup) { + function _propertyGroup(val) { + if (val === 1) { + return ob; + } else { + return propertyGroup(val - 1); + } + } + function _dashPropertyGroup(val) { + if (val === 1) { + return dashOb; + } else { + return _propertyGroup(val - 1); + } + } + function addPropertyToDashOb(i) { + Object.defineProperty(dashOb, shape.d[i].nm, { + get: ExpressionPropertyInterface(view.d.dataProps[i].p) + }); + } + var i, len = shape.d ? shape.d.length : 0; + var dashOb = {}; + for (i = 0; i < len; i += 1) { + addPropertyToDashOb(i); + view.d.dataProps[i].p.setGroupProperty(_dashPropertyGroup); + } + + function interfaceFunction(val) { + if (val === 'Color' || val === 'color') { + return interfaceFunction.color; + } else if (val === 'Opacity' || val === 'opacity') { + return interfaceFunction.opacity; + } else if (val === 'Stroke Width' || val === 'stroke width') { + return interfaceFunction.strokeWidth; + } + } + Object.defineProperties(interfaceFunction, { + 'color': { + get: ExpressionPropertyInterface(view.c) + }, + 'opacity': { + get: ExpressionPropertyInterface(view.o) + }, + 'strokeWidth': { + get: ExpressionPropertyInterface(view.w) + }, + 'dash': { + get: function () { + return dashOb; + } + }, + '_name': { value: shape.nm }, + 'mn': { value: shape.mn } + }); + + view.c.setGroupProperty(_propertyGroup); + view.o.setGroupProperty(_propertyGroup); + view.w.setGroupProperty(_propertyGroup); + return interfaceFunction; + } + + function trimInterfaceFactory(shape, view, propertyGroup) { + function _propertyGroup(val) { + if (val == 1) { + return interfaceFunction; + } else { + return propertyGroup(--val); + } + } + interfaceFunction.propertyIndex = shape.ix; + + view.s.setGroupProperty(_propertyGroup); + view.e.setGroupProperty(_propertyGroup); + view.o.setGroupProperty(_propertyGroup); + + function interfaceFunction(val) { + if (val === shape.e.ix || val === 'End' || val === 'end') { + return interfaceFunction.end; + } + if (val === shape.s.ix) { + return interfaceFunction.start; + } + if (val === shape.o.ix) { + return interfaceFunction.offset; + } + } + interfaceFunction.propertyIndex = shape.ix; + interfaceFunction.propertyGroup = propertyGroup; + + Object.defineProperties(interfaceFunction, { + 'start': { + get: ExpressionPropertyInterface(view.s) + }, + 'end': { + get: ExpressionPropertyInterface(view.e) + }, + 'offset': { + get: ExpressionPropertyInterface(view.o) + }, + '_name': { value: shape.nm } + }); + interfaceFunction.mn = shape.mn; + return interfaceFunction; + } + + function transformInterfaceFactory(shape, view, propertyGroup) { + function _propertyGroup(val) { + if (val == 1) { + return interfaceFunction; + } else { + return propertyGroup(--val); + } + } + view.transform.mProps.o.setGroupProperty(_propertyGroup); + view.transform.mProps.p.setGroupProperty(_propertyGroup); + view.transform.mProps.a.setGroupProperty(_propertyGroup); + view.transform.mProps.s.setGroupProperty(_propertyGroup); + view.transform.mProps.r.setGroupProperty(_propertyGroup); + if (view.transform.mProps.sk) { + view.transform.mProps.sk.setGroupProperty(_propertyGroup); + view.transform.mProps.sa.setGroupProperty(_propertyGroup); + } + view.transform.op.setGroupProperty(_propertyGroup); + + function interfaceFunction(value) { + if (shape.a.ix === value || value === 'Anchor Point') { + return interfaceFunction.anchorPoint; + } + if (shape.o.ix === value || value === 'Opacity') { + return interfaceFunction.opacity; + } + if (shape.p.ix === value || value === 'Position') { + return interfaceFunction.position; + } + if (shape.r.ix === value || value === 'Rotation' || value === 'ADBE Vector Rotation') { + return interfaceFunction.rotation; + } + if (shape.s.ix === value || value === 'Scale') { + return interfaceFunction.scale; + } + if (shape.sk && shape.sk.ix === value || value === 'Skew') { + return interfaceFunction.skew; + } + if (shape.sa && shape.sa.ix === value || value === 'Skew Axis') { + return interfaceFunction.skewAxis; + } + + } + Object.defineProperties(interfaceFunction, { + 'opacity': { + get: ExpressionPropertyInterface(view.transform.mProps.o) + }, + 'position': { + get: ExpressionPropertyInterface(view.transform.mProps.p) + }, + 'anchorPoint': { + get: ExpressionPropertyInterface(view.transform.mProps.a) + }, + 'scale': { + get: ExpressionPropertyInterface(view.transform.mProps.s) + }, + 'rotation': { + get: ExpressionPropertyInterface(view.transform.mProps.r) + }, + 'skew': { + get: ExpressionPropertyInterface(view.transform.mProps.sk) + }, + 'skewAxis': { + get: ExpressionPropertyInterface(view.transform.mProps.sa) + }, + '_name': { value: shape.nm } + }); + interfaceFunction.ty = 'tr'; + interfaceFunction.mn = shape.mn; + interfaceFunction.propertyGroup = propertyGroup; + return interfaceFunction; + } + + function ellipseInterfaceFactory(shape, view, propertyGroup) { + function _propertyGroup(val) { + if (val == 1) { + return interfaceFunction; + } else { + return propertyGroup(--val); + } + } + interfaceFunction.propertyIndex = shape.ix; + var prop = view.sh.ty === 'tm' ? view.sh.prop : view.sh; + prop.s.setGroupProperty(_propertyGroup); + prop.p.setGroupProperty(_propertyGroup); + function interfaceFunction(value) { + if (shape.p.ix === value) { + return interfaceFunction.position; + } + if (shape.s.ix === value) { + return interfaceFunction.size; + } + } + + Object.defineProperties(interfaceFunction, { + 'size': { + get: ExpressionPropertyInterface(prop.s) + }, + 'position': { + get: ExpressionPropertyInterface(prop.p) + }, + '_name': { value: shape.nm } + }); + interfaceFunction.mn = shape.mn; + return interfaceFunction; + } + + function starInterfaceFactory(shape, view, propertyGroup) { + function _propertyGroup(val) { + if (val == 1) { + return interfaceFunction; + } else { + return propertyGroup(--val); + } + } + var prop = view.sh.ty === 'tm' ? view.sh.prop : view.sh; + interfaceFunction.propertyIndex = shape.ix; + prop.or.setGroupProperty(_propertyGroup); + prop.os.setGroupProperty(_propertyGroup); + prop.pt.setGroupProperty(_propertyGroup); + prop.p.setGroupProperty(_propertyGroup); + prop.r.setGroupProperty(_propertyGroup); + if (shape.ir) { + prop.ir.setGroupProperty(_propertyGroup); + prop.is.setGroupProperty(_propertyGroup); + } + + function interfaceFunction(value) { + if (shape.p.ix === value) { + return interfaceFunction.position; + } + if (shape.r.ix === value) { + return interfaceFunction.rotation; + } + if (shape.pt.ix === value) { + return interfaceFunction.points; + } + if (shape.or.ix === value || 'ADBE Vector Star Outer Radius' === value) { + return interfaceFunction.outerRadius; + } + if (shape.os.ix === value) { + return interfaceFunction.outerRoundness; + } + if (shape.ir && (shape.ir.ix === value || 'ADBE Vector Star Inner Radius' === value)) { + return interfaceFunction.innerRadius; + } + if (shape.is && shape.is.ix === value) { + return interfaceFunction.innerRoundness; + } + + } + + Object.defineProperties(interfaceFunction, { + 'position': { + get: ExpressionPropertyInterface(prop.p) + }, + 'rotation': { + get: ExpressionPropertyInterface(prop.r) + }, + 'points': { + get: ExpressionPropertyInterface(prop.pt) + }, + 'outerRadius': { + get: ExpressionPropertyInterface(prop.or) + }, + 'outerRoundness': { + get: ExpressionPropertyInterface(prop.os) + }, + 'innerRadius': { + get: ExpressionPropertyInterface(prop.ir) + }, + 'innerRoundness': { + get: ExpressionPropertyInterface(prop.is) + }, + '_name': { value: shape.nm } + }); + interfaceFunction.mn = shape.mn; + return interfaceFunction; + } + + function rectInterfaceFactory(shape, view, propertyGroup) { + function _propertyGroup(val) { + if (val == 1) { + return interfaceFunction; + } else { + return propertyGroup(--val); + } + } + var prop = view.sh.ty === 'tm' ? view.sh.prop : view.sh; + interfaceFunction.propertyIndex = shape.ix; + prop.p.setGroupProperty(_propertyGroup); + prop.s.setGroupProperty(_propertyGroup); + prop.r.setGroupProperty(_propertyGroup); + + function interfaceFunction(value) { + if (shape.p.ix === value) { + return interfaceFunction.position; + } + if (shape.r.ix === value) { + return interfaceFunction.roundness; + } + if (shape.s.ix === value || value === 'Size' || value === 'ADBE Vector Rect Size') { + return interfaceFunction.size; + } + + } + Object.defineProperties(interfaceFunction, { + 'position': { + get: ExpressionPropertyInterface(prop.p) + }, + 'roundness': { + get: ExpressionPropertyInterface(prop.r) + }, + 'size': { + get: ExpressionPropertyInterface(prop.s) + }, + '_name': { value: shape.nm } + }); + interfaceFunction.mn = shape.mn; + return interfaceFunction; + } + + function roundedInterfaceFactory(shape, view, propertyGroup) { + function _propertyGroup(val) { + if (val == 1) { + return interfaceFunction; + } else { + return propertyGroup(--val); + } + } + var prop = view; + interfaceFunction.propertyIndex = shape.ix; + prop.rd.setGroupProperty(_propertyGroup); + + function interfaceFunction(value) { + if (shape.r.ix === value || 'Round Corners 1' === value) { + return interfaceFunction.radius; + } + + } + Object.defineProperties(interfaceFunction, { + 'radius': { + get: ExpressionPropertyInterface(prop.rd) + }, + '_name': { value: shape.nm } + }); + interfaceFunction.mn = shape.mn; + return interfaceFunction; + } + + function repeaterInterfaceFactory(shape, view, propertyGroup) { + function _propertyGroup(val) { + if (val == 1) { + return interfaceFunction; + } else { + return propertyGroup(--val); + } + } + var prop = view; + interfaceFunction.propertyIndex = shape.ix; + prop.c.setGroupProperty(_propertyGroup); + prop.o.setGroupProperty(_propertyGroup); + + function interfaceFunction(value) { + if (shape.c.ix === value || 'Copies' === value) { + return interfaceFunction.copies; + } else if (shape.o.ix === value || 'Offset' === value) { + return interfaceFunction.offset; + } + + } + Object.defineProperties(interfaceFunction, { + 'copies': { + get: ExpressionPropertyInterface(prop.c) + }, + 'offset': { + get: ExpressionPropertyInterface(prop.o) + }, + '_name': { value: shape.nm } + }); + interfaceFunction.mn = shape.mn; + return interfaceFunction; + } + + function pathInterfaceFactory(shape, view, propertyGroup) { + var prop = view.sh; + function _propertyGroup(val) { + if (val == 1) { + return interfaceFunction; + } else { + return propertyGroup(--val); + } + } + prop.setGroupProperty(_propertyGroup); + + function interfaceFunction(val) { + if (val === 'Shape' || val === 'shape' || val === 'Path' || val === 'path' || val === 'ADBE Vector Shape' || val === 2) { + return interfaceFunction.path; + } + } + Object.defineProperties(interfaceFunction, { + 'path': { + get: function () { + if (prop.k) { + prop.getValue(); + } + return prop; + } + }, + 'shape': { + get: function () { + if (prop.k) { + prop.getValue(); + } + return prop; + } + }, + '_name': { value: shape.nm }, + 'ix': { value: shape.ix }, + 'propertyIndex': { value: shape.ix }, + 'mn': { value: shape.mn } + }); + return interfaceFunction; + } + + return function (shapes, view, propertyGroup) { + var interfaces; + function _interfaceFunction(value) { + if (typeof value === 'number') { + return interfaces[value - 1]; + } else { + var i = 0, len = interfaces.length; + while (i < len) { + if (interfaces[i]._name === value) { + return interfaces[i]; + } + i += 1; + } + } + } + _interfaceFunction.propertyGroup = propertyGroup; + interfaces = iterateElements(shapes, view, _interfaceFunction); + _interfaceFunction.numProperties = interfaces.length; + return _interfaceFunction; + }; + }()); + + var TextExpressionInterface = (function () { + return function (elem) { + var _prevValue, _sourceText; + function _thisLayerFunction() { + } + Object.defineProperty(_thisLayerFunction, "sourceText", { + get: function () { + elem.textProperty.getValue() + var stringValue = elem.textProperty.currentData.t; + if (stringValue !== _prevValue) { + elem.textProperty.currentData.t = _prevValue; + _sourceText = new String(stringValue); + //If stringValue is an empty string, eval returns undefined, so it has to be returned as a String primitive + _sourceText.value = stringValue ? stringValue : new String(stringValue); + } + return _sourceText; + } + }); + return _thisLayerFunction; + }; + }()); + var LayerExpressionInterface = (function () { + function toWorld(arr, time) { + var toWorldMat = new Matrix(); + toWorldMat.reset(); + var transformMat; + if (time) { + //Todo implement value at time on transform properties + //transformMat = this._elem.finalTransform.mProp.getValueAtTime(time); + transformMat = this._elem.finalTransform.mProp; + } else { + transformMat = this._elem.finalTransform.mProp; + } + transformMat.applyToMatrix(toWorldMat); + if (this._elem.hierarchy && this._elem.hierarchy.length) { + var i, len = this._elem.hierarchy.length; + for (i = 0; i < len; i += 1) { + this._elem.hierarchy[i].finalTransform.mProp.applyToMatrix(toWorldMat); + } + return toWorldMat.applyToPointArray(arr[0], arr[1], arr[2] || 0); + } + return toWorldMat.applyToPointArray(arr[0], arr[1], arr[2] || 0); + } + function fromWorld(arr, time) { + var toWorldMat = new Matrix(); + toWorldMat.reset(); + var transformMat; + if (time) { + //Todo implement value at time on transform properties + //transformMat = this._elem.finalTransform.mProp.getValueAtTime(time); + transformMat = this._elem.finalTransform.mProp; + } else { + transformMat = this._elem.finalTransform.mProp; + } + transformMat.applyToMatrix(toWorldMat); + if (this._elem.hierarchy && this._elem.hierarchy.length) { + var i, len = this._elem.hierarchy.length; + for (i = 0; i < len; i += 1) { + this._elem.hierarchy[i].finalTransform.mProp.applyToMatrix(toWorldMat); + } + return toWorldMat.inversePoint(arr); + } + return toWorldMat.inversePoint(arr); + } + function fromComp(arr) { + var toWorldMat = new Matrix(); + toWorldMat.reset(); + this._elem.finalTransform.mProp.applyToMatrix(toWorldMat); + if (this._elem.hierarchy && this._elem.hierarchy.length) { + var i, len = this._elem.hierarchy.length; + for (i = 0; i < len; i += 1) { + this._elem.hierarchy[i].finalTransform.mProp.applyToMatrix(toWorldMat); + } + return toWorldMat.inversePoint(arr); + } + return toWorldMat.inversePoint(arr); + } + + function sampleImage() { + return [1, 1, 1, 1]; + } + + + return function (elem) { + + var transformInterface; + + function _registerMaskInterface(maskManager) { + _thisLayerFunction.mask = new MaskManagerInterface(maskManager, elem); + } + function _registerEffectsInterface(effects) { + _thisLayerFunction.effect = effects; + } + + function _thisLayerFunction(name) { + switch (name) { + case "ADBE Root Vectors Group": + case "Contents": + case 2: + return _thisLayerFunction.shapeInterface; + case 1: + case 6: + case "Transform": + case "transform": + case "ADBE Transform Group": + return transformInterface; + case 4: + case "ADBE Effect Parade": + case "effects": + case "Effects": + return _thisLayerFunction.effect; + } + } + _thisLayerFunction.toWorld = toWorld; + _thisLayerFunction.fromWorld = fromWorld; + _thisLayerFunction.toComp = toWorld; + _thisLayerFunction.fromComp = fromComp; + _thisLayerFunction.sampleImage = sampleImage; + _thisLayerFunction.sourceRectAtTime = elem.sourceRectAtTime.bind(elem); + _thisLayerFunction._elem = elem; + transformInterface = TransformExpressionInterface(elem.finalTransform.mProp); + var anchorPointDescriptor = getDescriptor(transformInterface, 'anchorPoint'); + Object.defineProperties(_thisLayerFunction, { + hasParent: { + get: function () { + return elem.hierarchy.length; + } + }, + parent: { + get: function () { + return elem.hierarchy[0].layerInterface; + } + }, + rotation: getDescriptor(transformInterface, 'rotation'), + scale: getDescriptor(transformInterface, 'scale'), + position: getDescriptor(transformInterface, 'position'), + opacity: getDescriptor(transformInterface, 'opacity'), + anchorPoint: anchorPointDescriptor, + anchor_point: anchorPointDescriptor, + transform: { + get: function () { + return transformInterface; + } + }, + active: { + get: function () { + return elem.isInRange; + } + } + }); + + _thisLayerFunction.startTime = elem.data.st; + _thisLayerFunction.index = elem.data.ind; + _thisLayerFunction.source = elem.data.refId; + _thisLayerFunction.height = elem.data.ty === 0 ? elem.data.h : 100; + _thisLayerFunction.width = elem.data.ty === 0 ? elem.data.w : 100; + _thisLayerFunction.inPoint = elem.data.ip / elem.comp.globalData.frameRate; + _thisLayerFunction.outPoint = elem.data.op / elem.comp.globalData.frameRate; + _thisLayerFunction._name = elem.data.nm; + + _thisLayerFunction.registerMaskInterface = _registerMaskInterface; + _thisLayerFunction.registerEffectsInterface = _registerEffectsInterface; + return _thisLayerFunction; + }; + }()); + + var CompExpressionInterface = (function () { + return function (comp) { + function _thisLayerFunction(name) { + var i = 0, len = comp.layers.length; + while (i < len) { + if (comp.layers[i].nm === name || comp.layers[i].ind === name) { + return comp.elements[i].layerInterface; + } + i += 1; + } + return null; + //return {active:false}; + } + Object.defineProperty(_thisLayerFunction, "_name", { value: comp.data.nm }); + _thisLayerFunction.layer = _thisLayerFunction; + _thisLayerFunction.pixelAspect = 1; + _thisLayerFunction.height = comp.data.h || comp.globalData.compSize.h; + _thisLayerFunction.width = comp.data.w || comp.globalData.compSize.w; + _thisLayerFunction.pixelAspect = 1; + _thisLayerFunction.frameDuration = 1 / comp.globalData.frameRate; + _thisLayerFunction.displayStartTime = 0; + _thisLayerFunction.numLayers = comp.layers.length; + return _thisLayerFunction; + }; + }()); + var TransformExpressionInterface = (function () { + return function (transform) { + function _thisFunction(name) { + switch (name) { + case "scale": + case "Scale": + case "ADBE Scale": + case 6: + return _thisFunction.scale; + case "rotation": + case "Rotation": + case "ADBE Rotation": + case "ADBE Rotate Z": + case 10: + return _thisFunction.rotation; + case "ADBE Rotate X": + return _thisFunction.xRotation; + case "ADBE Rotate Y": + return _thisFunction.yRotation; + case "position": + case "Position": + case "ADBE Position": + case 2: + return _thisFunction.position; + case 'ADBE Position_0': + return _thisFunction.xPosition; + case 'ADBE Position_1': + return _thisFunction.yPosition; + case 'ADBE Position_2': + return _thisFunction.zPosition; + case "anchorPoint": + case "AnchorPoint": + case "Anchor Point": + case "ADBE AnchorPoint": + case 1: + return _thisFunction.anchorPoint; + case "opacity": + case "Opacity": + case 11: + return _thisFunction.opacity; + } + } + + Object.defineProperty(_thisFunction, "rotation", { + get: ExpressionPropertyInterface(transform.r || transform.rz) + }); + + Object.defineProperty(_thisFunction, "zRotation", { + get: ExpressionPropertyInterface(transform.rz || transform.r) + }); + + Object.defineProperty(_thisFunction, "xRotation", { + get: ExpressionPropertyInterface(transform.rx) + }); + + Object.defineProperty(_thisFunction, "yRotation", { + get: ExpressionPropertyInterface(transform.ry) + }); + Object.defineProperty(_thisFunction, "scale", { + get: ExpressionPropertyInterface(transform.s) + }); + + if (transform.p) { + var _transformFactory = ExpressionPropertyInterface(transform.p); + } + Object.defineProperty(_thisFunction, "position", { + get: function () { + if (transform.p) { + return _transformFactory(); + } else { + return [transform.px.v, transform.py.v, transform.pz ? transform.pz.v : 0]; + } + } + }); + + Object.defineProperty(_thisFunction, "xPosition", { + get: ExpressionPropertyInterface(transform.px) + }); + + Object.defineProperty(_thisFunction, "yPosition", { + get: ExpressionPropertyInterface(transform.py) + }); + + Object.defineProperty(_thisFunction, "zPosition", { + get: ExpressionPropertyInterface(transform.pz) + }); + + Object.defineProperty(_thisFunction, "anchorPoint", { + get: ExpressionPropertyInterface(transform.a) + }); + + Object.defineProperty(_thisFunction, "opacity", { + get: ExpressionPropertyInterface(transform.o) + }); + + Object.defineProperty(_thisFunction, "skew", { + get: ExpressionPropertyInterface(transform.sk) + }); + + Object.defineProperty(_thisFunction, "skewAxis", { + get: ExpressionPropertyInterface(transform.sa) + }); + + Object.defineProperty(_thisFunction, "orientation", { + get: ExpressionPropertyInterface(transform.or) + }); + + return _thisFunction; + }; + }()); + var ProjectInterface = (function () { + + function registerComposition(comp) { + this.compositions.push(comp); + } + + return function () { + function _thisProjectFunction(name) { + var i = 0, len = this.compositions.length; + while (i < len) { + if (this.compositions[i].data && this.compositions[i].data.nm === name) { + if (this.compositions[i].prepareFrame && this.compositions[i].data.xt) { + this.compositions[i].prepareFrame(this.currentFrame); + } + return this.compositions[i].compInterface; + } + i += 1; + } + } + + _thisProjectFunction.compositions = []; + _thisProjectFunction.currentFrame = 0; + + _thisProjectFunction.registerComposition = registerComposition; + + + + return _thisProjectFunction; + }; + }()); + var EffectsExpressionInterface = (function () { + var ob = { + createEffectsInterface: createEffectsInterface + }; + + function createEffectsInterface(elem, propertyGroup) { + if (elem.effectsManager) { + + var effectElements = []; + var effectsData = elem.data.ef; + var i, len = elem.effectsManager.effectElements.length; + for (i = 0; i < len; i += 1) { + effectElements.push(createGroupInterface(effectsData[i], elem.effectsManager.effectElements[i], propertyGroup, elem)); + } + + return function (name) { + var effects = elem.data.ef || [], i = 0, len = effects.length; + while (i < len) { + if (name === effects[i].nm || name === effects[i].mn || name === effects[i].ix) { + return effectElements[i]; + } + i += 1; + } + }; + } + } + + function createGroupInterface(data, elements, propertyGroup, elem) { + var effectElements = []; + var i, len = data.ef.length; + for (i = 0; i < len; i += 1) { + if (data.ef[i].ty === 5) { + effectElements.push(createGroupInterface(data.ef[i], elements.effectElements[i], elements.effectElements[i].propertyGroup, elem)); + } else { + effectElements.push(createValueInterface(elements.effectElements[i], data.ef[i].ty, elem, _propertyGroup)); + } + } + + function _propertyGroup(val) { + if (val === 1) { + return groupInterface; + } else { + return propertyGroup(val - 1); + } + } + + var groupInterface = function (name) { + var effects = data.ef, i = 0, len = effects.length; + while (i < len) { + if (name === effects[i].nm || name === effects[i].mn || name === effects[i].ix) { + if (effects[i].ty === 5) { + return effectElements[i]; + } else { + return effectElements[i](); + } + } + i += 1; + } + return effectElements[0](); + }; + + groupInterface.propertyGroup = _propertyGroup; + + if (data.mn === 'ADBE Color Control') { + Object.defineProperty(groupInterface, 'color', { + get: function () { + return effectElements[0](); + } + }); + } + Object.defineProperty(groupInterface, 'numProperties', { + get: function () { + return data.np; + } + }); + groupInterface.active = groupInterface.enabled = data.en !== 0; + return groupInterface; + } + + function createValueInterface(element, type, elem, propertyGroup) { + var expressionProperty = ExpressionPropertyInterface(element.p); + function interfaceFunction() { + if (type === 10) { + return elem.comp.compInterface(element.p.v); + } + return expressionProperty(); + } + + if (element.p.setGroupProperty) { + element.p.setGroupProperty(propertyGroup); + } + + return interfaceFunction; + } + + return ob; + + }()); + var MaskManagerInterface = (function () { + + function MaskInterface(mask, data) { + this._mask = mask; + this._data = data; + } + Object.defineProperty(MaskInterface.prototype, 'maskPath', { + get: function () { + if (this._mask.prop.k) { + this._mask.prop.getValue(); + } + return this._mask.prop; + } + }); + Object.defineProperty(MaskInterface.prototype, 'maskOpacity', { + get: function () { + if (this._mask.op.k) { + this._mask.op.getValue(); + } + return this._mask.op.v * 100; + } + }); + + var MaskManager = function (maskManager, elem) { + var _maskManager = maskManager; + var _elem = elem; + var _masksInterfaces = createSizedArray(maskManager.viewData.length); + var i, len = maskManager.viewData.length; + for (i = 0; i < len; i += 1) { + _masksInterfaces[i] = new MaskInterface(maskManager.viewData[i], maskManager.masksProperties[i]); + } + + var maskFunction = function (name) { + i = 0; + while (i < len) { + if (maskManager.masksProperties[i].nm === name) { + return _masksInterfaces[i]; + } + i += 1; + } + }; + return maskFunction; + }; + return MaskManager; + }()); + + var ExpressionPropertyInterface = (function () { + + var defaultUnidimensionalValue = { pv: 0, v: 0, mult: 1 } + var defaultMultidimensionalValue = { pv: [0, 0, 0], v: [0, 0, 0], mult: 1 } + + function completeProperty(expressionValue, property, type) { + Object.defineProperty(expressionValue, 'velocity', { + get: function () { + return property.getVelocityAtTime(property.comp.currentFrame); + } + }); + expressionValue.numKeys = property.keyframes ? property.keyframes.length : 0; + expressionValue.key = function (pos) { + if (!expressionValue.numKeys) { + return 0; + } else { + var value = ''; + if ('s' in property.keyframes[pos - 1]) { + value = property.keyframes[pos - 1].s; + } else if ('e' in property.keyframes[pos - 2]) { + value = property.keyframes[pos - 2].e; + } else { + value = property.keyframes[pos - 2].s; + } + var valueProp = type === 'unidimensional' ? new Number(value) : Object.assign({}, value); + valueProp.time = property.keyframes[pos - 1].t / property.elem.comp.globalData.frameRate; + return valueProp; + } + }; + expressionValue.valueAtTime = property.getValueAtTime; + expressionValue.speedAtTime = property.getSpeedAtTime; + expressionValue.velocityAtTime = property.getVelocityAtTime; + expressionValue.propertyGroup = property.propertyGroup; + } + + function UnidimensionalPropertyInterface(property) { + if (!property || !('pv' in property)) { + property = defaultUnidimensionalValue; + } + var mult = 1 / property.mult; + var val = property.pv * mult; + var expressionValue = new Number(val); + expressionValue.value = val; + completeProperty(expressionValue, property, 'unidimensional'); + + return function () { + if (property.k) { + property.getValue(); + } + val = property.v * mult; + if (expressionValue.value !== val) { + expressionValue = new Number(val); + expressionValue.value = val; + completeProperty(expressionValue, property, 'unidimensional'); + } + return expressionValue; + } + } + + function MultidimensionalPropertyInterface(property) { + if (!property || !('pv' in property)) { + property = defaultMultidimensionalValue; + } + var mult = 1 / property.mult; + var len = property.pv.length; + var expressionValue = createTypedArray('float32', len); + var arrValue = createTypedArray('float32', len); + expressionValue.value = arrValue; + completeProperty(expressionValue, property, 'multidimensional'); + + return function () { + if (property.k) { + property.getValue(); + } + for (var i = 0; i < len; i += 1) { + expressionValue[i] = arrValue[i] = property.v[i] * mult; + } + return expressionValue; + } + } + + //TODO: try to avoid using this getter + function defaultGetter() { + return defaultUnidimensionalValue; + } + + return function (property) { + if (!property) { + return defaultGetter; + } else if (property.propType === 'unidimensional') { + return UnidimensionalPropertyInterface(property); + } else { + return MultidimensionalPropertyInterface(property); + } + } + }()); + + (function () { + + var TextExpressionSelectorProp = (function () { + + function getValueProxy(index, total) { + this.textIndex = index + 1; + this.textTotal = total; + this.v = this.getValue() * this.mult; + return this.v; + } + + return function TextExpressionSelectorProp(elem, data) { + this.pv = 1; + this.comp = elem.comp; + this.elem = elem; + this.mult = 0.01; + this.propType = 'textSelector'; + this.textTotal = data.totalChars; + this.selectorValue = 100; + this.lastValue = [1, 1, 1]; + this.k = true; + this.x = true; + this.getValue = ExpressionManager.initiateExpression.bind(this)(elem, data, this); + this.getMult = getValueProxy; + this.getVelocityAtTime = expressionHelpers.getVelocityAtTime; + if (this.kf) { + this.getValueAtTime = expressionHelpers.getValueAtTime.bind(this); + } else { + this.getValueAtTime = expressionHelpers.getStaticValueAtTime.bind(this); + } + this.setGroupProperty = expressionHelpers.setGroupProperty; + }; + }()); + + var propertyGetTextProp = TextSelectorProp.getTextSelectorProp; + TextSelectorProp.getTextSelectorProp = function (elem, data, arr) { + if (data.t === 1) { + return new TextExpressionSelectorProp(elem, data, arr); + } else { + return propertyGetTextProp(elem, data, arr); + } + }; + }()); + function SliderEffect(data, elem, container) { + this.p = PropertyFactory.getProp(elem, data.v, 0, 0, container); + } + function AngleEffect(data, elem, container) { + this.p = PropertyFactory.getProp(elem, data.v, 0, 0, container); + } + function ColorEffect(data, elem, container) { + this.p = PropertyFactory.getProp(elem, data.v, 1, 0, container); + } + function PointEffect(data, elem, container) { + this.p = PropertyFactory.getProp(elem, data.v, 1, 0, container); + } + function LayerIndexEffect(data, elem, container) { + this.p = PropertyFactory.getProp(elem, data.v, 0, 0, container); + } + function MaskIndexEffect(data, elem, container) { + this.p = PropertyFactory.getProp(elem, data.v, 0, 0, container); + } + function CheckboxEffect(data, elem, container) { + this.p = PropertyFactory.getProp(elem, data.v, 0, 0, container); + } + function NoValueEffect() { + this.p = {}; + } + function EffectsManager() { } + function EffectsManager(data, element) { + var effects = data.ef || []; + this.effectElements = []; + var i, len = effects.length; + var effectItem; + for (i = 0; i < len; i++) { + effectItem = new GroupEffect(effects[i], element); + this.effectElements.push(effectItem); + } + } + + function GroupEffect(data, element) { + this.init(data, element); + } + + extendPrototype([DynamicPropertyContainer], GroupEffect); + + GroupEffect.prototype.getValue = GroupEffect.prototype.iterateDynamicProperties; + + GroupEffect.prototype.init = function (data, element) { + this.data = data; + this.effectElements = []; + this.initDynamicPropertyContainer(element); + var i, len = this.data.ef.length; + var eff, effects = this.data.ef; + for (i = 0; i < len; i += 1) { + eff = null; + switch (effects[i].ty) { + case 0: + eff = new SliderEffect(effects[i], element, this); + break; + case 1: + eff = new AngleEffect(effects[i], element, this); + break; + case 2: + eff = new ColorEffect(effects[i], element, this); + break; + case 3: + eff = new PointEffect(effects[i], element, this); + break; + case 4: + case 7: + eff = new CheckboxEffect(effects[i], element, this); + break; + case 10: + eff = new LayerIndexEffect(effects[i], element, this); + break; + case 11: + eff = new MaskIndexEffect(effects[i], element, this); + break; + case 5: + eff = new EffectsManager(effects[i], element, this); + break; + //case 6: + default: + eff = new NoValueEffect(effects[i], element, this); + break; + } + if (eff) { + this.effectElements.push(eff); + } + } + }; + + var lottie = {}; + + var _isFrozen = false; + + function setLocationHref(href) { + locationHref = href; + } + + function searchAnimations() { + if (standalone === true) { + animationManager.searchAnimations(animationData, standalone, renderer); + } else { + animationManager.searchAnimations(); + } + } + + function setSubframeRendering(flag) { + subframeEnabled = flag; + } + + function loadAnimation(params) { + if (standalone === true) { + params.animationData = JSON.parse(animationData); + } + return animationManager.loadAnimation(params); + } + + function setQuality(value) { + if (typeof value === 'string') { + switch (value) { + case 'high': + defaultCurveSegments = 200; + break; + case 'medium': + defaultCurveSegments = 50; + break; + case 'low': + defaultCurveSegments = 10; + break; + } + } else if (!isNaN(value) && value > 1) { + defaultCurveSegments = value; + } + if (defaultCurveSegments >= 50) { + roundValues(false); + } else { + roundValues(true); + } + } + + function inBrowser() { + return typeof navigator !== 'undefined'; + } + + function installPlugin(type, plugin) { + if (type === 'expressions') { + expressionsPlugin = plugin; + } + } + + function getFactory(name) { + switch (name) { + case "propertyFactory": + return PropertyFactory; + case "shapePropertyFactory": + return ShapePropertyFactory; + case "matrix": + return Matrix; + } + } + + lottie.play = animationManager.play; + lottie.pause = animationManager.pause; + lottie.setLocationHref = setLocationHref; + lottie.togglePause = animationManager.togglePause; + lottie.setSpeed = animationManager.setSpeed; + lottie.setDirection = animationManager.setDirection; + lottie.stop = animationManager.stop; + lottie.searchAnimations = searchAnimations; + lottie.registerAnimation = animationManager.registerAnimation; + lottie.loadAnimation = loadAnimation; + lottie.setSubframeRendering = setSubframeRendering; + lottie.resize = animationManager.resize; + //lottie.start = start; + lottie.goToAndStop = animationManager.goToAndStop; + lottie.destroy = animationManager.destroy; + lottie.setQuality = setQuality; + lottie.inBrowser = inBrowser; + lottie.installPlugin = installPlugin; + lottie.freeze = animationManager.freeze; + lottie.unfreeze = animationManager.unfreeze; + lottie.getRegisteredAnimations = animationManager.getRegisteredAnimations; + lottie.__getFactory = getFactory; + lottie.version = '5.6.8'; + + function checkReady() { + if (document.readyState === "complete") { + clearInterval(readyStateCheckInterval); + searchAnimations(); + } + } + + function getQueryVariable(variable) { + var vars = queryString.split('&'); + for (var i = 0; i < vars.length; i++) { + var pair = vars[i].split('='); + if (decodeURIComponent(pair[0]) == variable) { + return decodeURIComponent(pair[1]); + } + } + } + var standalone = '__[STANDALONE]__'; + var animationData = '__[ANIMATIONDATA]__'; + var renderer = ''; + if (standalone) { + var scripts = document.getElementsByTagName('script'); + var index = scripts.length - 1; + var myScript = scripts[index] || { + src: '' + }; + var queryString = myScript.src.replace(/^[^\?]+\??/, ''); + renderer = getQueryVariable('renderer'); + } + var readyStateCheckInterval = setInterval(checkReady, 100); + + return lottie; +})); diff --git a/src/AddIns/Uno.UI.Lottie.Skia/WasmScripts/uno-lottie.d.ts b/src/AddIns/Uno.UI.Lottie.Skia/WasmScripts/uno-lottie.d.ts new file mode 100644 index 000000000000..e52cdd5382be --- /dev/null +++ b/src/AddIns/Uno.UI.Lottie.Skia/WasmScripts/uno-lottie.d.ts @@ -0,0 +1,36 @@ +declare const require: any; +declare const config: any; +declare namespace Uno.UI { + import AnimationData = Lottie.AnimationData; + interface LottieAnimationProperties { + elementId: number; + jsonPath?: string; + autoplay: boolean; + stretch: string; + rate: number; + } + interface RunningLottieAnimation { + animation: Lottie.AnimationItem; + properties: LottieAnimationProperties; + } + class Lottie { + private static _player; + private static _runningAnimations; + private static _numberOfFrames; + static setAnimationProperties(newProperties: LottieAnimationProperties, animationData?: AnimationData): string; + static stop(elementId: number): string; + static play(elementId: number, fromProgress: number, toProgress: number, looped: boolean): string; + static kill(elementId: number): string; + static pause(elementId: number): string; + static resume(elementId: number): string; + static setProgress(elementId: number, progress: number): string; + static getAnimationState(elementId: number): string; + private static needNewPlayerAnimation; + private static updateProperties; + private static createAnimation; + private static getStateString; + private static raiseState; + private static getPlayerConfig; + private static withPlayer; + } +} diff --git a/src/AddIns/Uno.UI.Lottie.Skia/WasmScripts/uno-lottie.js b/src/AddIns/Uno.UI.Lottie.Skia/WasmScripts/uno-lottie.js new file mode 100644 index 000000000000..c4be858846fa --- /dev/null +++ b/src/AddIns/Uno.UI.Lottie.Skia/WasmScripts/uno-lottie.js @@ -0,0 +1,189 @@ +var Uno; +(function (Uno) { + var UI; + (function (UI) { + class Lottie { + static setAnimationProperties(newProperties, animationData) { + const elementId = newProperties.elementId; + Lottie.withPlayer(p => { + let currentAnimation = Lottie._runningAnimations[elementId]; + if (!currentAnimation || Lottie.needNewPlayerAnimation(currentAnimation.properties, newProperties)) { + // Here we need a new player animation + // (some property changes required a new animation) + currentAnimation = Lottie.createAnimation(newProperties, animationData); + } + Lottie.updateProperties(currentAnimation, newProperties); + }); + return "ok"; + } + static stop(elementId) { + Lottie.withPlayer(p => { + const a = Lottie._runningAnimations[elementId].animation; + a.stop(); + Lottie.raiseState(a); + }); + return "ok"; + } + static play(elementId, fromProgress, toProgress, looped) { + Lottie.withPlayer(p => { + const a = Lottie._runningAnimations[elementId].animation; + a.loop = looped; + const fromFrame = fromProgress * Lottie._numberOfFrames; + const toFrame = toProgress * Lottie._numberOfFrames; + a.playSegments([fromFrame, toFrame], false); + Lottie.raiseState(a); + }); + return "ok"; + } + static kill(elementId) { + Lottie.withPlayer(p => { + Lottie._runningAnimations[elementId].animation.destroy(); + delete Lottie._runningAnimations[elementId]; + }); + return "ok"; + } + static pause(elementId) { + Lottie.withPlayer(p => { + const a = Lottie._runningAnimations[elementId].animation; + a.pause(); + Lottie.raiseState(a); + }); + return "ok"; + } + static resume(elementId) { + Lottie.withPlayer(p => { + const a = Lottie._runningAnimations[elementId].animation; + a.play(); + Lottie.raiseState(a); + }); + return "ok"; + } + static setProgress(elementId, progress) { + Lottie.withPlayer(p => { + const animation = Lottie._runningAnimations[elementId].animation; + const frames = animation.getDuration(true); + const frame = frames * progress; + animation.goToAndStop(frame, true); + Lottie.raiseState(animation); + }); + return "ok"; + } + static getAnimationState(elementId) { + const animation = Lottie._runningAnimations[elementId].animation; + const state = Lottie.getStateString(animation); + return state; + } + static needNewPlayerAnimation(current, newProperties) { + if (current.jsonPath !== newProperties.jsonPath) { + return true; + } + if (newProperties.stretch !== current.stretch) { + return true; + } + if (newProperties.autoplay !== current.autoplay) { + return true; + } + return false; + } + static updateProperties(runningAnimation, newProperties) { + const animation = runningAnimation.animation; + const runningProperties = runningAnimation.properties; + if (runningProperties == null || newProperties.rate != runningProperties.rate) { + animation.setSpeed(newProperties.rate); + } + runningAnimation.properties = newProperties; + } + static createAnimation(properties, animationData) { + const existingAnimation = Lottie._runningAnimations[properties.elementId]; + if (existingAnimation) { + // destroy any previous animation + existingAnimation.animation.destroy(); + existingAnimation.animation = null; + } + const config = Lottie.getPlayerConfig(properties, animationData); + const animation = Lottie._player.loadAnimation(config); + const runningAnimation = { + animation: animation, + properties: properties + }; + Lottie._runningAnimations[properties.elementId] = runningAnimation; + animation.addEventListener("complete", (e) => { + Lottie.raiseState(animation); + }); + animation.addEventListener("loopComplete", (e) => { + Lottie.raiseState(animation); + }); + animation.addEventListener("segmentStart", (e) => { + Lottie.raiseState(animation); + }); + animation.addEventListener("data_ready", (e) => { + Lottie._numberOfFrames = animation.totalFrames; + Lottie.raiseState(animation); + }); + Lottie.raiseState(animation); + return runningAnimation; + } + static getStateString(animation) { + const duration = animation.getDuration(false); + const state = `${animation.animationData.w}|${animation.animationData.h}|` + + `${animation.isLoaded}|${animation.isPaused}|${duration}`; + return state; + } + static raiseState(animation) { + const element = animation.wrapper; + const state = Lottie.getStateString(animation); + element.dispatchEvent(new CustomEvent("lottie_state", { detail: state })); + } + static getPlayerConfig(properties, animationData) { + let scaleMode = "none"; + switch (properties.stretch) { + case "Uniform": + scaleMode = "xMidYMid meet"; + break; + case "UniformToFill": + scaleMode = "xMidYMid slice"; + break; + case "Fill": + scaleMode = "none"; + break; + } + const containerElement = Uno.UI.WindowManager.current.getView(properties.elementId); + // https://github.com/airbnb/lottie-web/wiki/loadAnimation-options + const playerConfig = { + loop: true, + autoplay: properties.autoplay, + name: `Lottie-${properties.elementId}`, + renderer: "svg", + container: containerElement, + rendererSettings: { + // https://github.com/airbnb/lottie-web/wiki/Renderer-Settings + preserveAspectRatio: scaleMode + } + }; + // Set source, with priority to animationData, if specified. + if (animationData != null) { + playerConfig.animationData = animationData; + } + else if (properties.jsonPath != null && properties.jsonPath !== "") { + playerConfig.path = properties.jsonPath; + } + return playerConfig; + } + static withPlayer(action) { + if (Lottie._player) { + action(Lottie._player); + } + else { + require([`${config.uno_app_base}/lottie`], (p) => { + if (!Lottie._player) { + Lottie._player = p; + } + action(p); + }); + } + } + } + Lottie._runningAnimations = {}; + UI.Lottie = Lottie; + })(UI = Uno.UI || (Uno.UI = {})); +})(Uno || (Uno = {})); diff --git a/src/AddIns/Uno.UI.Lottie.Skia/ts/Uno.UI.Lottie.ts b/src/AddIns/Uno.UI.Lottie.Skia/ts/Uno.UI.Lottie.ts new file mode 100644 index 000000000000..3c0f13bccf34 --- /dev/null +++ b/src/AddIns/Uno.UI.Lottie.Skia/ts/Uno.UI.Lottie.ts @@ -0,0 +1,255 @@ +declare const require: any; +declare const config: any; + +namespace Uno.UI { + import AnimationData = Lottie.AnimationData; + + export interface LottieAnimationProperties { + elementId: number; + jsonPath?: string; + autoplay: boolean; + stretch: string; + rate: number; + } + + export interface RunningLottieAnimation { + animation: Lottie.AnimationItem; + properties: LottieAnimationProperties; + } + + export class Lottie { + private static _player: LottiePlayer; + private static _runningAnimations: { [id: number]: RunningLottieAnimation } = {}; + private static _numberOfFrames: number; + + public static setAnimationProperties(newProperties: LottieAnimationProperties, animationData?: AnimationData): string { + const elementId = newProperties.elementId; + + Lottie.withPlayer(p => { + let currentAnimation = Lottie._runningAnimations[elementId]; + + if (!currentAnimation || Lottie.needNewPlayerAnimation(currentAnimation.properties, newProperties)) { + // Here we need a new player animation + // (some property changes required a new animation) + currentAnimation = Lottie.createAnimation(newProperties, animationData); + } + + Lottie.updateProperties(currentAnimation, newProperties); + }); + + return "ok"; + } + + public static stop(elementId: number): string { + Lottie.withPlayer(p => { + const a = Lottie._runningAnimations[elementId].animation; + a.stop(); + Lottie.raiseState(a); + }); + + return "ok"; + } + + public static play(elementId: number, fromProgress: number, toProgress: number, looped: boolean): string { + Lottie.withPlayer(p => { + const a = Lottie._runningAnimations[elementId].animation; + a.loop = looped; + + const fromFrame = fromProgress * Lottie._numberOfFrames; + const toFrame = toProgress * Lottie._numberOfFrames; + + a.playSegments([fromFrame, toFrame], false); + Lottie.raiseState(a); + }); + + return "ok"; + } + + public static kill(elementId: number): string { + Lottie.withPlayer(p => { + Lottie._runningAnimations[elementId].animation.destroy(); + delete Lottie._runningAnimations[elementId]; + }); + + return "ok"; + } + + public static pause(elementId: number): string { + Lottie.withPlayer(p => { + const a = Lottie._runningAnimations[elementId].animation; + a.pause(); + Lottie.raiseState(a); + }); + + return "ok"; + } + + public static resume(elementId: number): string { + Lottie.withPlayer(p => { + const a = Lottie._runningAnimations[elementId].animation; + a.play(); + Lottie.raiseState(a); + }); + + return "ok"; + } + + public static setProgress(elementId: number, progress: number): string { + Lottie.withPlayer(p => { + const animation = Lottie._runningAnimations[elementId].animation; + const frames = animation.getDuration(true); + const frame = frames * progress; + animation.goToAndStop(frame, true); + Lottie.raiseState(animation); + + }); + + return "ok"; + } + + public static getAnimationState(elementId: number): string { + const animation = Lottie._runningAnimations[elementId].animation; + + const state = Lottie.getStateString(animation); + + return state; + } + + private static needNewPlayerAnimation(current: LottieAnimationProperties, newProperties: LottieAnimationProperties): boolean { + + if (current.jsonPath !== newProperties.jsonPath) { + return true; + } + if (newProperties.stretch !== current.stretch) { + return true; + } + if (newProperties.autoplay !== current.autoplay) { + return true; + } + + return false; + } + + private static updateProperties( + runningAnimation: RunningLottieAnimation, + newProperties: LottieAnimationProperties) { + + const animation = runningAnimation.animation; + const runningProperties = runningAnimation.properties; + + if (runningProperties == null || newProperties.rate != runningProperties.rate) { + animation.setSpeed(newProperties.rate); + } + + runningAnimation.properties = newProperties; + } + + private static createAnimation(properties: LottieAnimationProperties, animationData?: AnimationData): RunningLottieAnimation { + const existingAnimation = Lottie._runningAnimations[properties.elementId]; + if (existingAnimation) { + // destroy any previous animation + existingAnimation.animation.destroy(); + existingAnimation.animation = null; + } + + const config = Lottie.getPlayerConfig(properties, animationData); + const animation = Lottie._player.loadAnimation(config); + + const runningAnimation = { + animation: animation, + properties: properties + }; + + Lottie._runningAnimations[properties.elementId] = runningAnimation; + + (animation as any).addEventListener("complete", (e: any) => { + Lottie.raiseState(animation); + }); + + (animation as any).addEventListener("loopComplete", (e: any) => { + Lottie.raiseState(animation); + }); + + (animation as any).addEventListener("segmentStart", (e: any) => { + Lottie.raiseState(animation); + }); + + (animation as any).addEventListener("data_ready", (e: any) => { + Lottie._numberOfFrames = animation.totalFrames; + Lottie.raiseState(animation); + }); + + Lottie.raiseState(animation); + + return runningAnimation; + } + + private static getStateString(animation: Lottie.AnimationItem): string { + const duration = animation.getDuration(false); + + const state = `${animation.animationData.w}|${animation.animationData.h}|` + + `${animation.isLoaded}|${animation.isPaused}|${duration}`; + return state; + } + + private static raiseState(animation: Lottie.AnimationItem) { + const element = animation.wrapper; + const state = Lottie.getStateString(animation); + + element.dispatchEvent(new CustomEvent("lottie_state", { detail: state })); + } + + private static getPlayerConfig(properties: LottieAnimationProperties, animationData?: AnimationData): Lottie.AnimationConfig { + let scaleMode = "none"; + switch (properties.stretch) { + case "Uniform": + scaleMode = "xMidYMid meet"; + break; + case "UniformToFill": + scaleMode = "xMidYMid slice"; + break; + case "Fill": + scaleMode = "none"; + break; + } + + const containerElement = (Uno.UI as any).WindowManager.current.getView(properties.elementId); + + // https://github.com/airbnb/lottie-web/wiki/loadAnimation-options + const playerConfig: Lottie.AnimationConfig = { + loop: true, + autoplay: properties.autoplay, + name: `Lottie-${properties.elementId}`, + renderer: "svg", // https://github.com/airbnb/lottie-web/wiki/Features + container: containerElement, + rendererSettings: { + // https://github.com/airbnb/lottie-web/wiki/Renderer-Settings + preserveAspectRatio: scaleMode + } + }; + + // Set source, with priority to animationData, if specified. + if (animationData != null) { + playerConfig.animationData = animationData; + } + else if (properties.jsonPath != null && properties.jsonPath !== "") { + playerConfig.path = properties.jsonPath; + } + + return playerConfig; + } + + private static withPlayer(action: (player: LottiePlayer) => void): void { + if (Lottie._player) { + action(Lottie._player); + } else { + require([`${config.uno_app_base}/lottie`], (p: LottiePlayer) => { + if (!Lottie._player) { + Lottie._player = p; + } + action(p); + }); + } + } + } +} diff --git a/src/AddIns/Uno.UI.Lottie.Skia/ts/lottie-web.d.ts b/src/AddIns/Uno.UI.Lottie.Skia/ts/lottie-web.d.ts new file mode 100644 index 000000000000..fdb38cb04359 --- /dev/null +++ b/src/AddIns/Uno.UI.Lottie.Skia/ts/lottie-web.d.ts @@ -0,0 +1,131 @@ +declare namespace Lottie { + export interface AnimationItem { + play(): void; + + stop(): void; + + pause(): void; + + // one param speed (1 is normal speed) + setSpeed(speed: number): void; + + // one param direction (1 is normal direction) + setDirection(direction: number): void; + + // If false, it will respect the original AE fps. If true, it will update as much as possible. (true by default) + setSubframe(flag: boolean): void; + + // first param is a numeric value. second param is a boolean that defines time or frames for first param + goToAndPlay(value: number, isFrame: boolean): void; + + // first param is a numeric value. second param is a boolean that defines time or frames for first param + goToAndStop(value: number, isFrame: boolean): void; + + // first param is a single array or multiple arrays of two values each(fromFrame,toFrame), second param is a boolean for forcing the new segment right away + playSegments(segments: number[] | number[][], forceFlag: boolean): void; + + // inFrames: If true, returns duration in frames, if false, in seconds. + getDuration(inFrames: boolean): number; + + // To destroy and release resources. + destroy(): void; + + autoplay: boolean; + currentFrame: number; + isLoaded: boolean; + isPaused: boolean; + loop: boolean; + name: string; + playCount: number; + playDirection: number; + playSpeed: number; + totalFrames: number; + animationData: AnimationData; + wrapper: HTMLElement; + } + + export interface AnimationData { + // In Point of the Time Ruler. Sets the initial Frame of the animation. + ip: number; + + // Out Point of the Time Ruler. Sets the final Frame of the animation + op: number; + + // Frame Rate + fr: number; + + // Composition Width + w: number; + + // Composition Height + h: number; + + // Composition has 3-D layers + ddd: boolean; + + // Name + nm: string; + + // Version + v: string; + } + + export interface AnimationConfig { + // an Object with the exported animation data. + animationData?: any; + + // the relative path to the animation object. (animationData and path are mutually exclusive) + path?: string; + + // true / false / number + loop?: boolean | number; + + // true / false it will start playing as soon as it is ready + autoplay?: boolean; + + // animation name for future reference + name?: string; + + // 'svg' / 'canvas' / 'html' to set the renderer + renderer?: string; + + // the dom element on which to render the animation + container?: any; + + scaleMode?: string; + + rendererSettings?: any; + } +} + +declare class LottiePlayer { + // optional parameter name to target a specific animation + play(name?: string): void; + + // optional parameter name to target a specific animation + stop(name?: string): void; + + // first param speed (1 is normal speed) with 1 optional parameter name to target a specific animation + setSpeed(speed: number, name?: string): void; + + // first param direction (1 is normal direction.) with 1 optional parameter name to target a specific animation + setDirection(direction: number, name?: string): void; + + // default 'high', set 'high','medium','low', or a number > 1 to improve player performance. In some animations as low as 2 won't show any difference. + setQuality(quality: string | number): void; + + // param usually pass as location.href. Its useful when you experience mask issue in safari where your url does not have # symbol. + setLocationHref(href: string): void; + + // returns an animation instance to control individually. + loadAnimation(params: Lottie.AnimationConfig): Lottie.AnimationItem; + + // you can register an element directly with registerAnimation. It must have the "data-animation-path" attribute pointing at the data.json url + registerAnimation(element: any, animationData?: any): void; + + // looks for elements with class "lottie" + searchAnimations(animationData?: any, standalone?: boolean, renderer?: string): void; + + // To destroy and release resources. The DOM element will be emptied. + destroy(name?: string): void; +} diff --git a/src/AddIns/Uno.UI.Lottie.Skia/tsconfig.json b/src/AddIns/Uno.UI.Lottie.Skia/tsconfig.json new file mode 100644 index 000000000000..8830b1625cbb --- /dev/null +++ b/src/AddIns/Uno.UI.Lottie.Skia/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "module": "none", + "declaration": true, + "diagnostics": true, + "noImplicitAny": true, + "outFile": "WasmScripts/uno-lottie.js", + "locale": "en-US", + "target": "es2015" + }, + "include": [ + "ts/**/*" + ] +} + diff --git a/src/AddIns/Uno.UI.Lottie.Wasm/Uno.UI.Lottie.Wasm.csproj b/src/AddIns/Uno.UI.Lottie.Wasm/Uno.UI.Lottie.Wasm.csproj new file mode 100644 index 000000000000..69af57d80b13 --- /dev/null +++ b/src/AddIns/Uno.UI.Lottie.Wasm/Uno.UI.Lottie.Wasm.csproj @@ -0,0 +1,61 @@ + + + + netstandard2.0 + $(NoWarn);NU1701 + true + true + + Uno.UI.Lottie + Uno.UI.Lottie + + WebAssembly + ..\Uno.UI.Lottie\ + + + + + + + + + + + + + + + + + + + + + + + + + + ..\..\SourceGenerators\Uno.UI.SourceGenerators\bin\$(Configuration) + + + + + + + + <_OverrideTargetFramework>$(TargetFramework) + <_TargetNugetFolder>$(USERPROFILE)\.nuget\packages\Uno.UI.Lottie\$(UnoNugetOverrideVersion)\uno-runtime\$(UnoRuntimeIdentifier.ToLowerInvariant()) + + + <_OutputFiles Include="$(TargetDir)**" /> + + + + + + + + + + diff --git a/src/AddIns/Uno.UI.Lottie.Wasm/WasmScripts/lottie.js b/src/AddIns/Uno.UI.Lottie.Wasm/WasmScripts/lottie.js new file mode 100644 index 000000000000..f113b07927e3 --- /dev/null +++ b/src/AddIns/Uno.UI.Lottie.Wasm/WasmScripts/lottie.js @@ -0,0 +1,14555 @@ +(typeof navigator !== "undefined") && (function (root, factory) { + if (typeof define === "function" && define.amd) { + define(function () { + return factory(root); + }); + } else if (typeof module === "object" && module.exports) { + module.exports = factory(root); + } else { + root.lottie = factory(root); + root.bodymovin = root.lottie; + } +}((window || {}), function (window) { + "use strict"; + var svgNS = "http://www.w3.org/2000/svg"; + + var locationHref = ''; + + var initialDefaultFrame = -999999; + + var subframeEnabled = true; + var expressionsPlugin; + var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); + var cachedColors = {}; + var bm_rounder = Math.round; + var bm_rnd; + var bm_pow = Math.pow; + var bm_sqrt = Math.sqrt; + var bm_abs = Math.abs; + var bm_floor = Math.floor; + var bm_max = Math.max; + var bm_min = Math.min; + var blitter = 10; + + var BMMath = {}; + (function () { + var propertyNames = ["abs", "acos", "acosh", "asin", "asinh", "atan", "atanh", "atan2", "ceil", "cbrt", "expm1", "clz32", "cos", "cosh", "exp", "floor", "fround", "hypot", "imul", "log", "log1p", "log2", "log10", "max", "min", "pow", "random", "round", "sign", "sin", "sinh", "sqrt", "tan", "tanh", "trunc", "E", "LN10", "LN2", "LOG10E", "LOG2E", "PI", "SQRT1_2", "SQRT2"]; + var i, len = propertyNames.length; + for (i = 0; i < len; i += 1) { + BMMath[propertyNames[i]] = Math[propertyNames[i]]; + } + }()); + + function ProjectInterface() { return {}; } + + BMMath.random = Math.random; + BMMath.abs = function (val) { + var tOfVal = typeof val; + if (tOfVal === 'object' && val.length) { + var absArr = createSizedArray(val.length); + var i, len = val.length; + for (i = 0; i < len; i += 1) { + absArr[i] = Math.abs(val[i]); + } + return absArr; + } + return Math.abs(val); + + }; + var defaultCurveSegments = 150; + var degToRads = Math.PI / 180; + var roundCorner = 0.5519; + + function roundValues(flag) { + if (flag) { + bm_rnd = Math.round; + } else { + bm_rnd = function (val) { + return val; + }; + } + } + roundValues(false); + + function styleDiv(element) { + element.style.position = 'absolute'; + element.style.top = 0; + element.style.left = 0; + element.style.display = 'block'; + element.style.transformOrigin = element.style.webkitTransformOrigin = '0 0'; + element.style.backfaceVisibility = element.style.webkitBackfaceVisibility = 'visible'; + element.style.transformStyle = element.style.webkitTransformStyle = element.style.mozTransformStyle = "preserve-3d"; + } + + function BMEnterFrameEvent(type, currentTime, totalTime, frameMultiplier) { + this.type = type; + this.currentTime = currentTime; + this.totalTime = totalTime; + this.direction = frameMultiplier < 0 ? -1 : 1; + } + + function BMCompleteEvent(type, frameMultiplier) { + this.type = type; + this.direction = frameMultiplier < 0 ? -1 : 1; + } + + function BMCompleteLoopEvent(type, totalLoops, currentLoop, frameMultiplier) { + this.type = type; + this.currentLoop = currentLoop; + this.totalLoops = totalLoops; + this.direction = frameMultiplier < 0 ? -1 : 1; + } + + function BMSegmentStartEvent(type, firstFrame, totalFrames) { + this.type = type; + this.firstFrame = firstFrame; + this.totalFrames = totalFrames; + } + + function BMDestroyEvent(type, target) { + this.type = type; + this.target = target; + } + + function BMRenderFrameErrorEvent(nativeError, currentTime) { + this.type = 'renderFrameError'; + this.nativeError = nativeError; + this.currentTime = currentTime; + } + + function BMConfigErrorEvent(nativeError) { + this.type = 'configError'; + this.nativeError = nativeError; + } + + function BMAnimationConfigErrorEvent(type, nativeError) { + this.type = type; + this.nativeError = nativeError; + this.currentTime = currentTime; + } + + var createElementID = (function () { + var _count = 0; + return function createID() { + return '__lottie_element_' + ++_count + } + }()) + + function HSVtoRGB(h, s, v) { + var r, g, b, i, f, p, q, t; + i = Math.floor(h * 6); + f = h * 6 - i; + p = v * (1 - s); + q = v * (1 - f * s); + t = v * (1 - (1 - f) * s); + switch (i % 6) { + case 0: r = v; g = t; b = p; break; + case 1: r = q; g = v; b = p; break; + case 2: r = p; g = v; b = t; break; + case 3: r = p; g = q; b = v; break; + case 4: r = t; g = p; b = v; break; + case 5: r = v; g = p; b = q; break; + } + return [r, + g, + b]; + } + + function RGBtoHSV(r, g, b) { + var max = Math.max(r, g, b), min = Math.min(r, g, b), + d = max - min, + h, + s = (max === 0 ? 0 : d / max), + v = max / 255; + + switch (max) { + case min: h = 0; break; + case r: h = (g - b) + d * (g < b ? 6 : 0); h /= 6 * d; break; + case g: h = (b - r) + d * 2; h /= 6 * d; break; + case b: h = (r - g) + d * 4; h /= 6 * d; break; + } + + return [ + h, + s, + v + ]; + } + + function addSaturationToRGB(color, offset) { + var hsv = RGBtoHSV(color[0] * 255, color[1] * 255, color[2] * 255); + hsv[1] += offset; + if (hsv[1] > 1) { + hsv[1] = 1; + } + else if (hsv[1] <= 0) { + hsv[1] = 0; + } + return HSVtoRGB(hsv[0], hsv[1], hsv[2]); + } + + function addBrightnessToRGB(color, offset) { + var hsv = RGBtoHSV(color[0] * 255, color[1] * 255, color[2] * 255); + hsv[2] += offset; + if (hsv[2] > 1) { + hsv[2] = 1; + } + else if (hsv[2] < 0) { + hsv[2] = 0; + } + return HSVtoRGB(hsv[0], hsv[1], hsv[2]); + } + + function addHueToRGB(color, offset) { + var hsv = RGBtoHSV(color[0] * 255, color[1] * 255, color[2] * 255); + hsv[0] += offset / 360; + if (hsv[0] > 1) { + hsv[0] -= 1; + } + else if (hsv[0] < 0) { + hsv[0] += 1; + } + return HSVtoRGB(hsv[0], hsv[1], hsv[2]); + } + + var rgbToHex = (function () { + var colorMap = []; + var i; + var hex; + for (i = 0; i < 256; i += 1) { + hex = i.toString(16); + colorMap[i] = hex.length == 1 ? '0' + hex : hex; + } + + return function (r, g, b) { + if (r < 0) { + r = 0; + } + if (g < 0) { + g = 0; + } + if (b < 0) { + b = 0; + } + return '#' + colorMap[r] + colorMap[g] + colorMap[b]; + }; + }()); + function BaseEvent() { } + BaseEvent.prototype = { + triggerEvent: function (eventName, args) { + if (this._cbs[eventName]) { + var len = this._cbs[eventName].length; + for (var i = 0; i < len; i++) { + this._cbs[eventName][i](args); + } + } + }, + addEventListener: function (eventName, callback) { + if (!this._cbs[eventName]) { + this._cbs[eventName] = []; + } + this._cbs[eventName].push(callback); + + return function () { + this.removeEventListener(eventName, callback); + }.bind(this); + }, + removeEventListener: function (eventName, callback) { + if (!callback) { + this._cbs[eventName] = null; + } else if (this._cbs[eventName]) { + var i = 0, len = this._cbs[eventName].length; + while (i < len) { + if (this._cbs[eventName][i] === callback) { + this._cbs[eventName].splice(i, 1); + i -= 1; + len -= 1; + } + i += 1; + } + if (!this._cbs[eventName].length) { + this._cbs[eventName] = null; + } + } + } + }; + var createTypedArray = (function () { + function createRegularArray(type, len) { + var i = 0, arr = [], value; + switch (type) { + case 'int16': + case 'uint8c': + value = 1; + break; + default: + value = 1.1; + break; + } + for (i = 0; i < len; i += 1) { + arr.push(value); + } + return arr; + } + function createTypedArray(type, len) { + if (type === 'float32') { + return new Float32Array(len); + } else if (type === 'int16') { + return new Int16Array(len); + } else if (type === 'uint8c') { + return new Uint8ClampedArray(len); + } + } + if (typeof Uint8ClampedArray === 'function' && typeof Float32Array === 'function') { + return createTypedArray; + } else { + return createRegularArray; + } + }()); + + function createSizedArray(len) { + return Array.apply(null, { length: len }); + } + function createNS(type) { + //return {appendChild:function(){},setAttribute:function(){},style:{}} + return document.createElementNS(svgNS, type); + } + function createTag(type) { + //return {appendChild:function(){},setAttribute:function(){},style:{}} + return document.createElement(type); + } + function DynamicPropertyContainer() { }; + DynamicPropertyContainer.prototype = { + addDynamicProperty: function (prop) { + if (this.dynamicProperties.indexOf(prop) === -1) { + this.dynamicProperties.push(prop); + this.container.addDynamicProperty(this); + this._isAnimated = true; + } + }, + iterateDynamicProperties: function () { + this._mdf = false; + var i, len = this.dynamicProperties.length; + for (i = 0; i < len; i += 1) { + this.dynamicProperties[i].getValue(); + if (this.dynamicProperties[i]._mdf) { + this._mdf = true; + } + } + }, + initDynamicPropertyContainer: function (container) { + this.container = container; + this.dynamicProperties = []; + this._mdf = false; + this._isAnimated = false; + } + } + var getBlendMode = (function () { + + var blendModeEnums = { + 0: 'source-over', + 1: 'multiply', + 2: 'screen', + 3: 'overlay', + 4: 'darken', + 5: 'lighten', + 6: 'color-dodge', + 7: 'color-burn', + 8: 'hard-light', + 9: 'soft-light', + 10: 'difference', + 11: 'exclusion', + 12: 'hue', + 13: 'saturation', + 14: 'color', + 15: 'luminosity' + } + + return function (mode) { + return blendModeEnums[mode] || ''; + } + }()) + /*! + Transformation Matrix v2.0 + (c) Epistemex 2014-2015 + www.epistemex.com + By Ken Fyrstenberg + Contributions by leeoniya. + License: MIT, header required. + */ + + /** + * 2D transformation matrix object initialized with identity matrix. + * + * The matrix can synchronize a canvas context by supplying the context + * as an argument, or later apply current absolute transform to an + * existing context. + * + * All values are handled as floating point values. + * + * @param {CanvasRenderingContext2D} [context] - Optional context to sync with Matrix + * @prop {number} a - scale x + * @prop {number} b - shear y + * @prop {number} c - shear x + * @prop {number} d - scale y + * @prop {number} e - translate x + * @prop {number} f - translate y + * @prop {CanvasRenderingContext2D|null} [context=null] - set or get current canvas context + * @constructor + */ + + var Matrix = (function () { + + var _cos = Math.cos; + var _sin = Math.sin; + var _tan = Math.tan; + var _rnd = Math.round; + + function reset() { + this.props[0] = 1; + this.props[1] = 0; + this.props[2] = 0; + this.props[3] = 0; + this.props[4] = 0; + this.props[5] = 1; + this.props[6] = 0; + this.props[7] = 0; + this.props[8] = 0; + this.props[9] = 0; + this.props[10] = 1; + this.props[11] = 0; + this.props[12] = 0; + this.props[13] = 0; + this.props[14] = 0; + this.props[15] = 1; + return this; + } + + function rotate(angle) { + if (angle === 0) { + return this; + } + var mCos = _cos(angle); + var mSin = _sin(angle); + return this._t(mCos, -mSin, 0, 0, mSin, mCos, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); + } + + function rotateX(angle) { + if (angle === 0) { + return this; + } + var mCos = _cos(angle); + var mSin = _sin(angle); + return this._t(1, 0, 0, 0, 0, mCos, -mSin, 0, 0, mSin, mCos, 0, 0, 0, 0, 1); + } + + function rotateY(angle) { + if (angle === 0) { + return this; + } + var mCos = _cos(angle); + var mSin = _sin(angle); + return this._t(mCos, 0, mSin, 0, 0, 1, 0, 0, -mSin, 0, mCos, 0, 0, 0, 0, 1); + } + + function rotateZ(angle) { + if (angle === 0) { + return this; + } + var mCos = _cos(angle); + var mSin = _sin(angle); + return this._t(mCos, -mSin, 0, 0, mSin, mCos, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); + } + + function shear(sx, sy) { + return this._t(1, sy, sx, 1, 0, 0); + } + + function skew(ax, ay) { + return this.shear(_tan(ax), _tan(ay)); + } + + function skewFromAxis(ax, angle) { + var mCos = _cos(angle); + var mSin = _sin(angle); + return this._t(mCos, mSin, 0, 0, -mSin, mCos, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1) + ._t(1, 0, 0, 0, _tan(ax), 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1) + ._t(mCos, -mSin, 0, 0, mSin, mCos, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); + //return this._t(mCos, mSin, -mSin, mCos, 0, 0)._t(1, 0, _tan(ax), 1, 0, 0)._t(mCos, -mSin, mSin, mCos, 0, 0); + } + + function scale(sx, sy, sz) { + if (!sz && sz !== 0) { + sz = 1; + } + if (sx === 1 && sy === 1 && sz === 1) { + return this; + } + return this._t(sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, sz, 0, 0, 0, 0, 1); + } + + function setTransform(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) { + this.props[0] = a; + this.props[1] = b; + this.props[2] = c; + this.props[3] = d; + this.props[4] = e; + this.props[5] = f; + this.props[6] = g; + this.props[7] = h; + this.props[8] = i; + this.props[9] = j; + this.props[10] = k; + this.props[11] = l; + this.props[12] = m; + this.props[13] = n; + this.props[14] = o; + this.props[15] = p; + return this; + } + + function translate(tx, ty, tz) { + tz = tz || 0; + if (tx !== 0 || ty !== 0 || tz !== 0) { + return this._t(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, tx, ty, tz, 1); + } + return this; + } + + function transform(a2, b2, c2, d2, e2, f2, g2, h2, i2, j2, k2, l2, m2, n2, o2, p2) { + + var _p = this.props; + + if (a2 === 1 && b2 === 0 && c2 === 0 && d2 === 0 && e2 === 0 && f2 === 1 && g2 === 0 && h2 === 0 && i2 === 0 && j2 === 0 && k2 === 1 && l2 === 0) { + //NOTE: commenting this condition because TurboFan deoptimizes code when present + //if(m2 !== 0 || n2 !== 0 || o2 !== 0){ + _p[12] = _p[12] * a2 + _p[15] * m2; + _p[13] = _p[13] * f2 + _p[15] * n2; + _p[14] = _p[14] * k2 + _p[15] * o2; + _p[15] = _p[15] * p2; + //} + this._identityCalculated = false; + return this; + } + + var a1 = _p[0]; + var b1 = _p[1]; + var c1 = _p[2]; + var d1 = _p[3]; + var e1 = _p[4]; + var f1 = _p[5]; + var g1 = _p[6]; + var h1 = _p[7]; + var i1 = _p[8]; + var j1 = _p[9]; + var k1 = _p[10]; + var l1 = _p[11]; + var m1 = _p[12]; + var n1 = _p[13]; + var o1 = _p[14]; + var p1 = _p[15]; + + /* matrix order (canvas compatible): + * ace + * bdf + * 001 + */ + _p[0] = a1 * a2 + b1 * e2 + c1 * i2 + d1 * m2; + _p[1] = a1 * b2 + b1 * f2 + c1 * j2 + d1 * n2; + _p[2] = a1 * c2 + b1 * g2 + c1 * k2 + d1 * o2; + _p[3] = a1 * d2 + b1 * h2 + c1 * l2 + d1 * p2; + + _p[4] = e1 * a2 + f1 * e2 + g1 * i2 + h1 * m2; + _p[5] = e1 * b2 + f1 * f2 + g1 * j2 + h1 * n2; + _p[6] = e1 * c2 + f1 * g2 + g1 * k2 + h1 * o2; + _p[7] = e1 * d2 + f1 * h2 + g1 * l2 + h1 * p2; + + _p[8] = i1 * a2 + j1 * e2 + k1 * i2 + l1 * m2; + _p[9] = i1 * b2 + j1 * f2 + k1 * j2 + l1 * n2; + _p[10] = i1 * c2 + j1 * g2 + k1 * k2 + l1 * o2; + _p[11] = i1 * d2 + j1 * h2 + k1 * l2 + l1 * p2; + + _p[12] = m1 * a2 + n1 * e2 + o1 * i2 + p1 * m2; + _p[13] = m1 * b2 + n1 * f2 + o1 * j2 + p1 * n2; + _p[14] = m1 * c2 + n1 * g2 + o1 * k2 + p1 * o2; + _p[15] = m1 * d2 + n1 * h2 + o1 * l2 + p1 * p2; + + this._identityCalculated = false; + return this; + } + + function isIdentity() { + if (!this._identityCalculated) { + this._identity = !(this.props[0] !== 1 || this.props[1] !== 0 || this.props[2] !== 0 || this.props[3] !== 0 || this.props[4] !== 0 || this.props[5] !== 1 || this.props[6] !== 0 || this.props[7] !== 0 || this.props[8] !== 0 || this.props[9] !== 0 || this.props[10] !== 1 || this.props[11] !== 0 || this.props[12] !== 0 || this.props[13] !== 0 || this.props[14] !== 0 || this.props[15] !== 1); + this._identityCalculated = true; + } + return this._identity; + } + + function equals(matr) { + var i = 0; + while (i < 16) { + if (matr.props[i] !== this.props[i]) { + return false; + } + i += 1; + } + return true; + } + + function clone(matr) { + var i; + for (i = 0; i < 16; i += 1) { + matr.props[i] = this.props[i]; + } + } + + function cloneFromProps(props) { + var i; + for (i = 0; i < 16; i += 1) { + this.props[i] = props[i]; + } + } + + function applyToPoint(x, y, z) { + + return { + x: x * this.props[0] + y * this.props[4] + z * this.props[8] + this.props[12], + y: x * this.props[1] + y * this.props[5] + z * this.props[9] + this.props[13], + z: x * this.props[2] + y * this.props[6] + z * this.props[10] + this.props[14] + }; + /*return { + x: x * me.a + y * me.c + me.e, + y: x * me.b + y * me.d + me.f + };*/ + } + function applyToX(x, y, z) { + return x * this.props[0] + y * this.props[4] + z * this.props[8] + this.props[12]; + } + function applyToY(x, y, z) { + return x * this.props[1] + y * this.props[5] + z * this.props[9] + this.props[13]; + } + function applyToZ(x, y, z) { + return x * this.props[2] + y * this.props[6] + z * this.props[10] + this.props[14]; + } + + function getInverseMatrix() { + var determinant = this.props[0] * this.props[5] - this.props[1] * this.props[4]; + var a = this.props[5] / determinant; + var b = - this.props[1] / determinant; + var c = - this.props[4] / determinant; + var d = this.props[0] / determinant; + var e = (this.props[4] * this.props[13] - this.props[5] * this.props[12]) / determinant; + var f = - (this.props[0] * this.props[13] - this.props[1] * this.props[12]) / determinant; + var inverseMatrix = new Matrix(); + inverseMatrix.props[0] = a; + inverseMatrix.props[1] = b; + inverseMatrix.props[4] = c; + inverseMatrix.props[5] = d; + inverseMatrix.props[12] = e; + inverseMatrix.props[13] = f; + return inverseMatrix; + } + + function inversePoint(pt) { + var inverseMatrix = this.getInverseMatrix(); + return inverseMatrix.applyToPointArray(pt[0], pt[1], pt[2] || 0) + } + + function inversePoints(pts) { + var i, len = pts.length, retPts = []; + for (i = 0; i < len; i += 1) { + retPts[i] = inversePoint(pts[i]); + } + return retPts; + } + + function applyToTriplePoints(pt1, pt2, pt3) { + var arr = createTypedArray('float32', 6); + if (this.isIdentity()) { + arr[0] = pt1[0]; + arr[1] = pt1[1]; + arr[2] = pt2[0]; + arr[3] = pt2[1]; + arr[4] = pt3[0]; + arr[5] = pt3[1]; + } else { + var p0 = this.props[0], p1 = this.props[1], p4 = this.props[4], p5 = this.props[5], p12 = this.props[12], p13 = this.props[13]; + arr[0] = pt1[0] * p0 + pt1[1] * p4 + p12; + arr[1] = pt1[0] * p1 + pt1[1] * p5 + p13; + arr[2] = pt2[0] * p0 + pt2[1] * p4 + p12; + arr[3] = pt2[0] * p1 + pt2[1] * p5 + p13; + arr[4] = pt3[0] * p0 + pt3[1] * p4 + p12; + arr[5] = pt3[0] * p1 + pt3[1] * p5 + p13; + } + return arr; + } + + function applyToPointArray(x, y, z) { + var arr; + if (this.isIdentity()) { + arr = [x, y, z]; + } else { + arr = [x * this.props[0] + y * this.props[4] + z * this.props[8] + this.props[12], x * this.props[1] + y * this.props[5] + z * this.props[9] + this.props[13], x * this.props[2] + y * this.props[6] + z * this.props[10] + this.props[14]]; + } + return arr; + } + + function applyToPointStringified(x, y) { + if (this.isIdentity()) { + return x + ',' + y; + } + var _p = this.props; + return Math.round((x * _p[0] + y * _p[4] + _p[12]) * 100) / 100 + ',' + Math.round((x * _p[1] + y * _p[5] + _p[13]) * 100) / 100; + } + + function toCSS() { + //Doesn't make much sense to add this optimization. If it is an identity matrix, it's very likely this will get called only once since it won't be keyframed. + /*if(this.isIdentity()) { + return ''; + }*/ + var i = 0; + var props = this.props; + var cssValue = 'matrix3d('; + var v = 10000; + while (i < 16) { + cssValue += _rnd(props[i] * v) / v; + cssValue += i === 15 ? ')' : ','; + i += 1; + } + return cssValue; + } + + function roundMatrixProperty(val) { + var v = 10000; + if ((val < 0.000001 && val > 0) || (val > -0.000001 && val < 0)) { + return _rnd(val * v) / v; + } + return val; + } + + function to2dCSS() { + //Doesn't make much sense to add this optimization. If it is an identity matrix, it's very likely this will get called only once since it won't be keyframed. + /*if(this.isIdentity()) { + return ''; + }*/ + var props = this.props; + var _a = roundMatrixProperty(props[0]); + var _b = roundMatrixProperty(props[1]); + var _c = roundMatrixProperty(props[4]); + var _d = roundMatrixProperty(props[5]); + var _e = roundMatrixProperty(props[12]); + var _f = roundMatrixProperty(props[13]); + return "matrix(" + _a + ',' + _b + ',' + _c + ',' + _d + ',' + _e + ',' + _f + ")"; + } + + return function () { + this.reset = reset; + this.rotate = rotate; + this.rotateX = rotateX; + this.rotateY = rotateY; + this.rotateZ = rotateZ; + this.skew = skew; + this.skewFromAxis = skewFromAxis; + this.shear = shear; + this.scale = scale; + this.setTransform = setTransform; + this.translate = translate; + this.transform = transform; + this.applyToPoint = applyToPoint; + this.applyToX = applyToX; + this.applyToY = applyToY; + this.applyToZ = applyToZ; + this.applyToPointArray = applyToPointArray; + this.applyToTriplePoints = applyToTriplePoints; + this.applyToPointStringified = applyToPointStringified; + this.toCSS = toCSS; + this.to2dCSS = to2dCSS; + this.clone = clone; + this.cloneFromProps = cloneFromProps; + this.equals = equals; + this.inversePoints = inversePoints; + this.inversePoint = inversePoint; + this.getInverseMatrix = getInverseMatrix; + this._t = this.transform; + this.isIdentity = isIdentity; + this._identity = true; + this._identityCalculated = false; + + this.props = createTypedArray('float32', 16); + this.reset(); + }; + }()); + + /* + Copyright 2014 David Bau. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + */ + + (function (pool, math) { + // + // The following constants are related to IEEE 754 limits. + // + var global = this, + width = 256, // each RC4 output is 0 <= x < 256 + chunks = 6, // at least six RC4 outputs for each double + digits = 52, // there are 52 significant digits in a double + rngname = 'random', // rngname: name for Math.random and Math.seedrandom + startdenom = math.pow(width, chunks), + significance = math.pow(2, digits), + overflow = significance * 2, + mask = width - 1, + nodecrypto; // node.js crypto module, initialized at the bottom. + + // + // seedrandom() + // This is the seedrandom function described above. + // + function seedrandom(seed, options, callback) { + var key = []; + options = (options === true) ? { entropy: true } : (options || {}); + + // Flatten the seed string or build one from local entropy if needed. + var shortseed = mixkey(flatten( + options.entropy ? [seed, tostring(pool)] : + (seed === null) ? autoseed() : seed, 3), key); + + // Use the seed to initialize an ARC4 generator. + var arc4 = new ARC4(key); + + // This function returns a random double in [0, 1) that contains + // randomness in every bit of the mantissa of the IEEE 754 value. + var prng = function () { + var n = arc4.g(chunks), // Start with a numerator n < 2 ^ 48 + d = startdenom, // and denominator d = 2 ^ 48. + x = 0; // and no 'extra last byte'. + while (n < significance) { // Fill up all significant digits by + n = (n + x) * width; // shifting numerator and + d *= width; // denominator and generating a + x = arc4.g(1); // new least-significant-byte. + } + while (n >= overflow) { // To avoid rounding up, before adding + n /= 2; // last byte, shift everything + d /= 2; // right using integer math until + x >>>= 1; // we have exactly the desired bits. + } + return (n + x) / d; // Form the number within [0, 1). + }; + + prng.int32 = function () { return arc4.g(4) | 0; }; + prng.quick = function () { return arc4.g(4) / 0x100000000; }; + prng.double = prng; + + // Mix the randomness into accumulated entropy. + mixkey(tostring(arc4.S), pool); + + // Calling convention: what to return as a function of prng, seed, is_math. + return (options.pass || callback || + function (prng, seed, is_math_call, state) { + if (state) { + // Load the arc4 state from the given state if it has an S array. + if (state.S) { copy(state, arc4); } + // Only provide the .state method if requested via options.state. + prng.state = function () { return copy(arc4, {}); }; + } + + // If called as a method of Math (Math.seedrandom()), mutate + // Math.random because that is how seedrandom.js has worked since v1.0. + if (is_math_call) { math[rngname] = prng; return seed; } + + // Otherwise, it is a newer calling convention, so return the + // prng directly. + else return prng; + })( + prng, + shortseed, + 'global' in options ? options.global : (this == math), + options.state); + } + math['seed' + rngname] = seedrandom; + + // + // ARC4 + // + // An ARC4 implementation. The constructor takes a key in the form of + // an array of at most (width) integers that should be 0 <= x < (width). + // + // The g(count) method returns a pseudorandom integer that concatenates + // the next (count) outputs from ARC4. Its return value is a number x + // that is in the range 0 <= x < (width ^ count). + // + function ARC4(key) { + var t, keylen = key.length, + me = this, i = 0, j = me.i = me.j = 0, s = me.S = []; + + // The empty key [] is treated as [0]. + if (!keylen) { key = [keylen++]; } + + // Set up S using the standard key scheduling algorithm. + while (i < width) { + s[i] = i++; + } + for (i = 0; i < width; i++) { + s[i] = s[j = mask & (j + key[i % keylen] + (t = s[i]))]; + s[j] = t; + } + + // The "g" method returns the next (count) outputs as one number. + me.g = function (count) { + // Using instance members instead of closure state nearly doubles speed. + var t, r = 0, + i = me.i, j = me.j, s = me.S; + while (count--) { + t = s[i = mask & (i + 1)]; + r = r * width + s[mask & ((s[i] = s[j = mask & (j + t)]) + (s[j] = t))]; + } + me.i = i; me.j = j; + return r; + // For robust unpredictability, the function call below automatically + // discards an initial batch of values. This is called RC4-drop[256]. + // See http://google.com/search?q=rsa+fluhrer+response&btnI + }; + } + + // + // copy() + // Copies internal state of ARC4 to or from a plain object. + // + function copy(f, t) { + t.i = f.i; + t.j = f.j; + t.S = f.S.slice(); + return t; + } + + // + // flatten() + // Converts an object tree to nested arrays of strings. + // + function flatten(obj, depth) { + var result = [], typ = (typeof obj), prop; + if (depth && typ == 'object') { + for (prop in obj) { + try { result.push(flatten(obj[prop], depth - 1)); } catch (e) { } + } + } + return (result.length ? result : typ == 'string' ? obj : obj + '\0'); + } + + // + // mixkey() + // Mixes a string seed into a key that is an array of integers, and + // returns a shortened string seed that is equivalent to the result key. + // + function mixkey(seed, key) { + var stringseed = seed + '', smear, j = 0; + while (j < stringseed.length) { + key[mask & j] = + mask & ((smear ^= key[mask & j] * 19) + stringseed.charCodeAt(j++)); + } + return tostring(key); + } + + // + // autoseed() + // Returns an object for autoseeding, using window.crypto and Node crypto + // module if available. + // + function autoseed() { + try { + if (nodecrypto) { return tostring(nodecrypto.randomBytes(width)); } + var out = new Uint8Array(width); + (global.crypto || global.msCrypto).getRandomValues(out); + return tostring(out); + } catch (e) { + var browser = global.navigator, + plugins = browser && browser.plugins; + return [+new Date(), global, plugins, global.screen, tostring(pool)]; + } + } + + // + // tostring() + // Converts an array of charcodes to a string + // + function tostring(a) { + return String.fromCharCode.apply(0, a); + } + + // + // When seedrandom.js is loaded, we immediately mix a few bits + // from the built-in RNG into the entropy pool. Because we do + // not want to interfere with deterministic PRNG state later, + // seedrandom will not call math.random on its own again after + // initialization. + // + mixkey(math.random(), pool); + + // + // Nodejs and AMD support: export the implementation as a module using + // either convention. + // + + // End anonymous scope, and pass initial values. + })( + [], // pool: entropy pool starts empty + BMMath // math: package containing random, pow, and seedrandom + ); + var BezierFactory = (function () { + /** + * BezierEasing - use bezier curve for transition easing function + * by Gaëtan Renaudeau 2014 - 2015 – MIT License + * + * Credits: is based on Firefox's nsSMILKeySpline.cpp + * Usage: + * var spline = BezierEasing([ 0.25, 0.1, 0.25, 1.0 ]) + * spline.get(x) => returns the easing value | x must be in [0, 1] range + * + */ + + var ob = {}; + ob.getBezierEasing = getBezierEasing; + var beziers = {}; + + function getBezierEasing(a, b, c, d, nm) { + var str = nm || ('bez_' + a + '_' + b + '_' + c + '_' + d).replace(/\./g, 'p'); + if (beziers[str]) { + return beziers[str]; + } + var bezEasing = new BezierEasing([a, b, c, d]); + beziers[str] = bezEasing; + return bezEasing; + } + + // These values are established by empiricism with tests (tradeoff: performance VS precision) + var NEWTON_ITERATIONS = 4; + var NEWTON_MIN_SLOPE = 0.001; + var SUBDIVISION_PRECISION = 0.0000001; + var SUBDIVISION_MAX_ITERATIONS = 10; + + var kSplineTableSize = 11; + var kSampleStepSize = 1.0 / (kSplineTableSize - 1.0); + + var float32ArraySupported = typeof Float32Array === "function"; + + function A(aA1, aA2) { return 1.0 - 3.0 * aA2 + 3.0 * aA1; } + function B(aA1, aA2) { return 3.0 * aA2 - 6.0 * aA1; } + function C(aA1) { return 3.0 * aA1; } + + // Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2. + function calcBezier(aT, aA1, aA2) { + return ((A(aA1, aA2) * aT + B(aA1, aA2)) * aT + C(aA1)) * aT; + } + + // Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2. + function getSlope(aT, aA1, aA2) { + return 3.0 * A(aA1, aA2) * aT * aT + 2.0 * B(aA1, aA2) * aT + C(aA1); + } + + function binarySubdivide(aX, aA, aB, mX1, mX2) { + var currentX, currentT, i = 0; + do { + currentT = aA + (aB - aA) / 2.0; + currentX = calcBezier(currentT, mX1, mX2) - aX; + if (currentX > 0.0) { + aB = currentT; + } else { + aA = currentT; + } + } while (Math.abs(currentX) > SUBDIVISION_PRECISION && ++i < SUBDIVISION_MAX_ITERATIONS); + return currentT; + } + + function newtonRaphsonIterate(aX, aGuessT, mX1, mX2) { + for (var i = 0; i < NEWTON_ITERATIONS; ++i) { + var currentSlope = getSlope(aGuessT, mX1, mX2); + if (currentSlope === 0.0) return aGuessT; + var currentX = calcBezier(aGuessT, mX1, mX2) - aX; + aGuessT -= currentX / currentSlope; + } + return aGuessT; + } + + /** + * points is an array of [ mX1, mY1, mX2, mY2 ] + */ + function BezierEasing(points) { + this._p = points; + this._mSampleValues = float32ArraySupported ? new Float32Array(kSplineTableSize) : new Array(kSplineTableSize); + this._precomputed = false; + + this.get = this.get.bind(this); + } + + BezierEasing.prototype = { + + get: function (x) { + var mX1 = this._p[0], + mY1 = this._p[1], + mX2 = this._p[2], + mY2 = this._p[3]; + if (!this._precomputed) this._precompute(); + if (mX1 === mY1 && mX2 === mY2) return x; // linear + // Because JavaScript number are imprecise, we should guarantee the extremes are right. + if (x === 0) return 0; + if (x === 1) return 1; + return calcBezier(this._getTForX(x), mY1, mY2); + }, + + // Private part + + _precompute: function () { + var mX1 = this._p[0], + mY1 = this._p[1], + mX2 = this._p[2], + mY2 = this._p[3]; + this._precomputed = true; + if (mX1 !== mY1 || mX2 !== mY2) + this._calcSampleValues(); + }, + + _calcSampleValues: function () { + var mX1 = this._p[0], + mX2 = this._p[2]; + for (var i = 0; i < kSplineTableSize; ++i) { + this._mSampleValues[i] = calcBezier(i * kSampleStepSize, mX1, mX2); + } + }, + + /** + * getTForX chose the fastest heuristic to determine the percentage value precisely from a given X projection. + */ + _getTForX: function (aX) { + var mX1 = this._p[0], + mX2 = this._p[2], + mSampleValues = this._mSampleValues; + + var intervalStart = 0.0; + var currentSample = 1; + var lastSample = kSplineTableSize - 1; + + for (; currentSample !== lastSample && mSampleValues[currentSample] <= aX; ++currentSample) { + intervalStart += kSampleStepSize; + } + --currentSample; + + // Interpolate to provide an initial guess for t + var dist = (aX - mSampleValues[currentSample]) / (mSampleValues[currentSample + 1] - mSampleValues[currentSample]); + var guessForT = intervalStart + dist * kSampleStepSize; + + var initialSlope = getSlope(guessForT, mX1, mX2); + if (initialSlope >= NEWTON_MIN_SLOPE) { + return newtonRaphsonIterate(aX, guessForT, mX1, mX2); + } else if (initialSlope === 0.0) { + return guessForT; + } else { + return binarySubdivide(aX, intervalStart, intervalStart + kSampleStepSize, mX1, mX2); + } + } + }; + + return ob; + + }()); + (function () { + var lastTime = 0; + var vendors = ['ms', 'moz', 'webkit', 'o']; + for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { + window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame']; + window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || window[vendors[x] + 'CancelRequestAnimationFrame']; + } + if (!window.requestAnimationFrame) + window.requestAnimationFrame = function (callback, element) { + var currTime = new Date().getTime(); + var timeToCall = Math.max(0, 16 - (currTime - lastTime)); + var id = setTimeout(function () { + callback(currTime + timeToCall); + }, + timeToCall); + lastTime = currTime + timeToCall; + return id; + }; + if (!window.cancelAnimationFrame) + window.cancelAnimationFrame = function (id) { + clearTimeout(id); + }; + }()); + + function extendPrototype(sources, destination) { + var i, len = sources.length, sourcePrototype; + for (i = 0; i < len; i += 1) { + sourcePrototype = sources[i].prototype; + for (var attr in sourcePrototype) { + if (sourcePrototype.hasOwnProperty(attr)) destination.prototype[attr] = sourcePrototype[attr]; + } + } + } + + function getDescriptor(object, prop) { + return Object.getOwnPropertyDescriptor(object, prop); + } + + function createProxyFunction(prototype) { + function ProxyFunction() { } + ProxyFunction.prototype = prototype; + return ProxyFunction; + } + function bezFunction() { + + var easingFunctions = []; + var math = Math; + + function pointOnLine2D(x1, y1, x2, y2, x3, y3) { + var det1 = (x1 * y2) + (y1 * x3) + (x2 * y3) - (x3 * y2) - (y3 * x1) - (x2 * y1); + return det1 > -0.001 && det1 < 0.001; + } + + function pointOnLine3D(x1, y1, z1, x2, y2, z2, x3, y3, z3) { + if (z1 === 0 && z2 === 0 && z3 === 0) { + return pointOnLine2D(x1, y1, x2, y2, x3, y3); + } + var dist1 = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2) + Math.pow(z2 - z1, 2)); + var dist2 = Math.sqrt(Math.pow(x3 - x1, 2) + Math.pow(y3 - y1, 2) + Math.pow(z3 - z1, 2)); + var dist3 = Math.sqrt(Math.pow(x3 - x2, 2) + Math.pow(y3 - y2, 2) + Math.pow(z3 - z2, 2)); + var diffDist; + if (dist1 > dist2) { + if (dist1 > dist3) { + diffDist = dist1 - dist2 - dist3; + } else { + diffDist = dist3 - dist2 - dist1; + } + } else if (dist3 > dist2) { + diffDist = dist3 - dist2 - dist1; + } else { + diffDist = dist2 - dist1 - dist3; + } + return diffDist > -0.0001 && diffDist < 0.0001; + } + + var getBezierLength = (function () { + + return function (pt1, pt2, pt3, pt4) { + var curveSegments = defaultCurveSegments; + var k; + var i, len; + var ptCoord, perc, addedLength = 0; + var ptDistance; + var point = [], lastPoint = []; + var lengthData = bezier_length_pool.newElement(); + len = pt3.length; + for (k = 0; k < curveSegments; k += 1) { + perc = k / (curveSegments - 1); + ptDistance = 0; + for (i = 0; i < len; i += 1) { + ptCoord = bm_pow(1 - perc, 3) * pt1[i] + 3 * bm_pow(1 - perc, 2) * perc * pt3[i] + 3 * (1 - perc) * bm_pow(perc, 2) * pt4[i] + bm_pow(perc, 3) * pt2[i]; + point[i] = ptCoord; + if (lastPoint[i] !== null) { + ptDistance += bm_pow(point[i] - lastPoint[i], 2); + } + lastPoint[i] = point[i]; + } + if (ptDistance) { + ptDistance = bm_sqrt(ptDistance); + addedLength += ptDistance; + } + lengthData.percents[k] = perc; + lengthData.lengths[k] = addedLength; + } + lengthData.addedLength = addedLength; + return lengthData; + }; + }()); + + function getSegmentsLength(shapeData) { + var segmentsLength = segments_length_pool.newElement(); + var closed = shapeData.c; + var pathV = shapeData.v; + var pathO = shapeData.o; + var pathI = shapeData.i; + var i, len = shapeData._length; + var lengths = segmentsLength.lengths; + var totalLength = 0; + for (i = 0; i < len - 1; i += 1) { + lengths[i] = getBezierLength(pathV[i], pathV[i + 1], pathO[i], pathI[i + 1]); + totalLength += lengths[i].addedLength; + } + if (closed && len) { + lengths[i] = getBezierLength(pathV[i], pathV[0], pathO[i], pathI[0]); + totalLength += lengths[i].addedLength; + } + segmentsLength.totalLength = totalLength; + return segmentsLength; + } + + function BezierData(length) { + this.segmentLength = 0; + this.points = new Array(length); + } + + function PointData(partial, point) { + this.partialLength = partial; + this.point = point; + } + + var buildBezierData = (function () { + + var storedData = {}; + + return function (pt1, pt2, pt3, pt4) { + var bezierName = (pt1[0] + '_' + pt1[1] + '_' + pt2[0] + '_' + pt2[1] + '_' + pt3[0] + '_' + pt3[1] + '_' + pt4[0] + '_' + pt4[1]).replace(/\./g, 'p'); + if (!storedData[bezierName]) { + var curveSegments = defaultCurveSegments; + var k, i, len; + var ptCoord, perc, addedLength = 0; + var ptDistance; + var point, lastPoint = null; + if (pt1.length === 2 && (pt1[0] != pt2[0] || pt1[1] != pt2[1]) && pointOnLine2D(pt1[0], pt1[1], pt2[0], pt2[1], pt1[0] + pt3[0], pt1[1] + pt3[1]) && pointOnLine2D(pt1[0], pt1[1], pt2[0], pt2[1], pt2[0] + pt4[0], pt2[1] + pt4[1])) { + curveSegments = 2; + } + var bezierData = new BezierData(curveSegments); + len = pt3.length; + for (k = 0; k < curveSegments; k += 1) { + point = createSizedArray(len); + perc = k / (curveSegments - 1); + ptDistance = 0; + for (i = 0; i < len; i += 1) { + ptCoord = bm_pow(1 - perc, 3) * pt1[i] + 3 * bm_pow(1 - perc, 2) * perc * (pt1[i] + pt3[i]) + 3 * (1 - perc) * bm_pow(perc, 2) * (pt2[i] + pt4[i]) + bm_pow(perc, 3) * pt2[i]; + point[i] = ptCoord; + if (lastPoint !== null) { + ptDistance += bm_pow(point[i] - lastPoint[i], 2); + } + } + ptDistance = bm_sqrt(ptDistance); + addedLength += ptDistance; + bezierData.points[k] = new PointData(ptDistance, point); + lastPoint = point; + } + bezierData.segmentLength = addedLength; + storedData[bezierName] = bezierData; + } + return storedData[bezierName]; + }; + }()); + + function getDistancePerc(perc, bezierData) { + var percents = bezierData.percents; + var lengths = bezierData.lengths; + var len = percents.length; + var initPos = bm_floor((len - 1) * perc); + var lengthPos = perc * bezierData.addedLength; + var lPerc = 0; + if (initPos === len - 1 || initPos === 0 || lengthPos === lengths[initPos]) { + return percents[initPos]; + } else { + var dir = lengths[initPos] > lengthPos ? -1 : 1; + var flag = true; + while (flag) { + if (lengths[initPos] <= lengthPos && lengths[initPos + 1] > lengthPos) { + lPerc = (lengthPos - lengths[initPos]) / (lengths[initPos + 1] - lengths[initPos]); + flag = false; + } else { + initPos += dir; + } + if (initPos < 0 || initPos >= len - 1) { + //FIX for TypedArrays that don't store floating point values with enough accuracy + if (initPos === len - 1) { + return percents[initPos]; + } + flag = false; + } + } + return percents[initPos] + (percents[initPos + 1] - percents[initPos]) * lPerc; + } + } + + function getPointInSegment(pt1, pt2, pt3, pt4, percent, bezierData) { + var t1 = getDistancePerc(percent, bezierData); + var u0 = 1; + var u1 = 1 - t1; + var ptX = Math.round((u1 * u1 * u1 * pt1[0] + (t1 * u1 * u1 + u1 * t1 * u1 + u1 * u1 * t1) * pt3[0] + (t1 * t1 * u1 + u1 * t1 * t1 + t1 * u1 * t1) * pt4[0] + t1 * t1 * t1 * pt2[0]) * 1000) / 1000; + var ptY = Math.round((u1 * u1 * u1 * pt1[1] + (t1 * u1 * u1 + u1 * t1 * u1 + u1 * u1 * t1) * pt3[1] + (t1 * t1 * u1 + u1 * t1 * t1 + t1 * u1 * t1) * pt4[1] + t1 * t1 * t1 * pt2[1]) * 1000) / 1000; + return [ptX, ptY]; + } + + function getSegmentArray() { + + } + + var bezier_segment_points = createTypedArray('float32', 8); + + function getNewSegment(pt1, pt2, pt3, pt4, startPerc, endPerc, bezierData) { + + startPerc = startPerc < 0 ? 0 : startPerc > 1 ? 1 : startPerc; + var t0 = getDistancePerc(startPerc, bezierData); + endPerc = endPerc > 1 ? 1 : endPerc; + var t1 = getDistancePerc(endPerc, bezierData); + var i, len = pt1.length; + var u0 = 1 - t0; + var u1 = 1 - t1; + var u0u0u0 = u0 * u0 * u0; + var t0u0u0_3 = t0 * u0 * u0 * 3; + var t0t0u0_3 = t0 * t0 * u0 * 3; + var t0t0t0 = t0 * t0 * t0; + // + var u0u0u1 = u0 * u0 * u1; + var t0u0u1_3 = t0 * u0 * u1 + u0 * t0 * u1 + u0 * u0 * t1; + var t0t0u1_3 = t0 * t0 * u1 + u0 * t0 * t1 + t0 * u0 * t1; + var t0t0t1 = t0 * t0 * t1; + // + var u0u1u1 = u0 * u1 * u1; + var t0u1u1_3 = t0 * u1 * u1 + u0 * t1 * u1 + u0 * u1 * t1; + var t0t1u1_3 = t0 * t1 * u1 + u0 * t1 * t1 + t0 * u1 * t1; + var t0t1t1 = t0 * t1 * t1; + // + var u1u1u1 = u1 * u1 * u1; + var t1u1u1_3 = t1 * u1 * u1 + u1 * t1 * u1 + u1 * u1 * t1; + var t1t1u1_3 = t1 * t1 * u1 + u1 * t1 * t1 + t1 * u1 * t1; + var t1t1t1 = t1 * t1 * t1; + for (i = 0; i < len; i += 1) { + bezier_segment_points[i * 4] = Math.round((u0u0u0 * pt1[i] + t0u0u0_3 * pt3[i] + t0t0u0_3 * pt4[i] + t0t0t0 * pt2[i]) * 1000) / 1000; + bezier_segment_points[i * 4 + 1] = Math.round((u0u0u1 * pt1[i] + t0u0u1_3 * pt3[i] + t0t0u1_3 * pt4[i] + t0t0t1 * pt2[i]) * 1000) / 1000; + bezier_segment_points[i * 4 + 2] = Math.round((u0u1u1 * pt1[i] + t0u1u1_3 * pt3[i] + t0t1u1_3 * pt4[i] + t0t1t1 * pt2[i]) * 1000) / 1000; + bezier_segment_points[i * 4 + 3] = Math.round((u1u1u1 * pt1[i] + t1u1u1_3 * pt3[i] + t1t1u1_3 * pt4[i] + t1t1t1 * pt2[i]) * 1000) / 1000; + } + + return bezier_segment_points; + } + + return { + getSegmentsLength: getSegmentsLength, + getNewSegment: getNewSegment, + getPointInSegment: getPointInSegment, + buildBezierData: buildBezierData, + pointOnLine2D: pointOnLine2D, + pointOnLine3D: pointOnLine3D + }; + } + + var bez = bezFunction(); + function dataFunctionManager() { + + //var tCanvasHelper = createTag('canvas').getContext('2d'); + + function completeLayers(layers, comps, fontManager) { + var layerData; + var animArray, lastFrame; + var i, len = layers.length; + var j, jLen, k, kLen; + for (i = 0; i < len; i += 1) { + layerData = layers[i]; + if (!('ks' in layerData) || layerData.completed) { + continue; + } + layerData.completed = true; + if (layerData.tt) { + layers[i - 1].td = layerData.tt; + } + animArray = []; + lastFrame = -1; + if (layerData.hasMask) { + var maskProps = layerData.masksProperties; + jLen = maskProps.length; + for (j = 0; j < jLen; j += 1) { + if (maskProps[j].pt.k.i) { + convertPathsToAbsoluteValues(maskProps[j].pt.k); + } else { + kLen = maskProps[j].pt.k.length; + for (k = 0; k < kLen; k += 1) { + if (maskProps[j].pt.k[k].s) { + convertPathsToAbsoluteValues(maskProps[j].pt.k[k].s[0]); + } + if (maskProps[j].pt.k[k].e) { + convertPathsToAbsoluteValues(maskProps[j].pt.k[k].e[0]); + } + } + } + } + } + if (layerData.ty === 0) { + layerData.layers = findCompLayers(layerData.refId, comps); + completeLayers(layerData.layers, comps, fontManager); + } else if (layerData.ty === 4) { + completeShapes(layerData.shapes); + } else if (layerData.ty == 5) { + completeText(layerData, fontManager); + } + } + } + + function findCompLayers(id, comps) { + var i = 0, len = comps.length; + while (i < len) { + if (comps[i].id === id) { + if (!comps[i].layers.__used) { + comps[i].layers.__used = true; + return comps[i].layers; + } + return JSON.parse(JSON.stringify(comps[i].layers)); + } + i += 1; + } + } + + function completeShapes(arr) { + var i, len = arr.length; + var j, jLen; + var hasPaths = false; + for (i = len - 1; i >= 0; i -= 1) { + if (arr[i].ty == 'sh') { + if (arr[i].ks.k.i) { + convertPathsToAbsoluteValues(arr[i].ks.k); + } else { + jLen = arr[i].ks.k.length; + for (j = 0; j < jLen; j += 1) { + if (arr[i].ks.k[j].s) { + convertPathsToAbsoluteValues(arr[i].ks.k[j].s[0]); + } + if (arr[i].ks.k[j].e) { + convertPathsToAbsoluteValues(arr[i].ks.k[j].e[0]); + } + } + } + hasPaths = true; + } else if (arr[i].ty == 'gr') { + completeShapes(arr[i].it); + } + } + /*if(hasPaths){ + //mx: distance + //ss: sensitivity + //dc: decay + arr.splice(arr.length-1,0,{ + "ty": "ms", + "mx":20, + "ss":10, + "dc":0.001, + "maxDist":200 + }); + }*/ + } + + function convertPathsToAbsoluteValues(path) { + var i, len = path.i.length; + for (i = 0; i < len; i += 1) { + path.i[i][0] += path.v[i][0]; + path.i[i][1] += path.v[i][1]; + path.o[i][0] += path.v[i][0]; + path.o[i][1] += path.v[i][1]; + } + } + + function checkVersion(minimum, animVersionString) { + var animVersion = animVersionString ? animVersionString.split('.') : [100, 100, 100]; + if (minimum[0] > animVersion[0]) { + return true; + } else if (animVersion[0] > minimum[0]) { + return false; + } + if (minimum[1] > animVersion[1]) { + return true; + } else if (animVersion[1] > minimum[1]) { + return false; + } + if (minimum[2] > animVersion[2]) { + return true; + } else if (animVersion[2] > minimum[2]) { + return false; + } + } + + var checkText = (function () { + var minimumVersion = [4, 4, 14]; + + function updateTextLayer(textLayer) { + var documentData = textLayer.t.d; + textLayer.t.d = { + k: [ + { + s: documentData, + t: 0 + } + ] + }; + } + + function iterateLayers(layers) { + var i, len = layers.length; + for (i = 0; i < len; i += 1) { + if (layers[i].ty === 5) { + updateTextLayer(layers[i]); + } + } + } + + return function (animationData) { + if (checkVersion(minimumVersion, animationData.v)) { + iterateLayers(animationData.layers); + if (animationData.assets) { + var i, len = animationData.assets.length; + for (i = 0; i < len; i += 1) { + if (animationData.assets[i].layers) { + iterateLayers(animationData.assets[i].layers); + + } + } + } + } + }; + }()); + + var checkChars = (function () { + var minimumVersion = [4, 7, 99]; + return function (animationData) { + if (animationData.chars && !checkVersion(minimumVersion, animationData.v)) { + var i, len = animationData.chars.length, j, jLen, k, kLen; + var pathData, paths; + for (i = 0; i < len; i += 1) { + if (animationData.chars[i].data && animationData.chars[i].data.shapes) { + paths = animationData.chars[i].data.shapes[0].it; + jLen = paths.length; + + for (j = 0; j < jLen; j += 1) { + pathData = paths[j].ks.k; + if (!pathData.__converted) { + convertPathsToAbsoluteValues(paths[j].ks.k); + pathData.__converted = true; + } + } + } + } + } + }; + }()); + + var checkColors = (function () { + var minimumVersion = [4, 1, 9]; + + function iterateShapes(shapes) { + var i, len = shapes.length; + var j, jLen; + for (i = 0; i < len; i += 1) { + if (shapes[i].ty === 'gr') { + iterateShapes(shapes[i].it); + } else if (shapes[i].ty === 'fl' || shapes[i].ty === 'st') { + if (shapes[i].c.k && shapes[i].c.k[0].i) { + jLen = shapes[i].c.k.length; + for (j = 0; j < jLen; j += 1) { + if (shapes[i].c.k[j].s) { + shapes[i].c.k[j].s[0] /= 255; + shapes[i].c.k[j].s[1] /= 255; + shapes[i].c.k[j].s[2] /= 255; + shapes[i].c.k[j].s[3] /= 255; + } + if (shapes[i].c.k[j].e) { + shapes[i].c.k[j].e[0] /= 255; + shapes[i].c.k[j].e[1] /= 255; + shapes[i].c.k[j].e[2] /= 255; + shapes[i].c.k[j].e[3] /= 255; + } + } + } else { + shapes[i].c.k[0] /= 255; + shapes[i].c.k[1] /= 255; + shapes[i].c.k[2] /= 255; + shapes[i].c.k[3] /= 255; + } + } + } + } + + function iterateLayers(layers) { + var i, len = layers.length; + for (i = 0; i < len; i += 1) { + if (layers[i].ty === 4) { + iterateShapes(layers[i].shapes); + } + } + } + + return function (animationData) { + if (checkVersion(minimumVersion, animationData.v)) { + iterateLayers(animationData.layers); + if (animationData.assets) { + var i, len = animationData.assets.length; + for (i = 0; i < len; i += 1) { + if (animationData.assets[i].layers) { + iterateLayers(animationData.assets[i].layers); + + } + } + } + } + }; + }()); + + var checkShapes = (function () { + var minimumVersion = [4, 4, 18]; + + + + function completeShapes(arr) { + var i, len = arr.length; + var j, jLen; + var hasPaths = false; + for (i = len - 1; i >= 0; i -= 1) { + if (arr[i].ty == 'sh') { + if (arr[i].ks.k.i) { + arr[i].ks.k.c = arr[i].closed; + } else { + jLen = arr[i].ks.k.length; + for (j = 0; j < jLen; j += 1) { + if (arr[i].ks.k[j].s) { + arr[i].ks.k[j].s[0].c = arr[i].closed; + } + if (arr[i].ks.k[j].e) { + arr[i].ks.k[j].e[0].c = arr[i].closed; + } + } + } + hasPaths = true; + } else if (arr[i].ty == 'gr') { + completeShapes(arr[i].it); + } + } + } + + function iterateLayers(layers) { + var layerData; + var i, len = layers.length; + var j, jLen, k, kLen; + for (i = 0; i < len; i += 1) { + layerData = layers[i]; + if (layerData.hasMask) { + var maskProps = layerData.masksProperties; + jLen = maskProps.length; + for (j = 0; j < jLen; j += 1) { + if (maskProps[j].pt.k.i) { + maskProps[j].pt.k.c = maskProps[j].cl; + } else { + kLen = maskProps[j].pt.k.length; + for (k = 0; k < kLen; k += 1) { + if (maskProps[j].pt.k[k].s) { + maskProps[j].pt.k[k].s[0].c = maskProps[j].cl; + } + if (maskProps[j].pt.k[k].e) { + maskProps[j].pt.k[k].e[0].c = maskProps[j].cl; + } + } + } + } + } + if (layerData.ty === 4) { + completeShapes(layerData.shapes); + } + } + } + + return function (animationData) { + if (checkVersion(minimumVersion, animationData.v)) { + iterateLayers(animationData.layers); + if (animationData.assets) { + var i, len = animationData.assets.length; + for (i = 0; i < len; i += 1) { + if (animationData.assets[i].layers) { + iterateLayers(animationData.assets[i].layers); + + } + } + } + } + }; + }()); + + function completeData(animationData, fontManager) { + if (animationData.__complete) { + return; + } + checkColors(animationData); + checkText(animationData); + checkChars(animationData); + checkShapes(animationData); + completeLayers(animationData.layers, animationData.assets, fontManager); + animationData.__complete = true; + //blitAnimation(animationData, animationData.assets, fontManager); + } + + function completeText(data, fontManager) { + if (data.t.a.length === 0 && !('m' in data.t.p)) { + data.singleShape = true; + } + } + + var moduleOb = {}; + moduleOb.completeData = completeData; + moduleOb.checkColors = checkColors; + moduleOb.checkChars = checkChars; + moduleOb.checkShapes = checkShapes; + moduleOb.completeLayers = completeLayers; + + return moduleOb; + } + + var dataManager = dataFunctionManager(); + + var FontManager = (function () { + + var maxWaitingTime = 5000; + var emptyChar = { + w: 0, + size: 0, + shapes: [] + }; + var combinedCharacters = []; + //Hindi characters + combinedCharacters = combinedCharacters.concat([2304, 2305, 2306, 2307, 2362, 2363, 2364, 2364, 2366 + , 2367, 2368, 2369, 2370, 2371, 2372, 2373, 2374, 2375, 2376, 2377, 2378, 2379 + , 2380, 2381, 2382, 2383, 2387, 2388, 2389, 2390, 2391, 2402, 2403]); + + function setUpNode(font, family) { + var parentNode = createTag('span'); + parentNode.style.fontFamily = family; + var node = createTag('span'); + // Characters that vary significantly among different fonts + node.innerHTML = 'giItT1WQy@!-/#'; + // Visible - so we can measure it - but not on the screen + parentNode.style.position = 'absolute'; + parentNode.style.left = '-10000px'; + parentNode.style.top = '-10000px'; + // Large font size makes even subtle changes obvious + parentNode.style.fontSize = '300px'; + // Reset any font properties + parentNode.style.fontVariant = 'normal'; + parentNode.style.fontStyle = 'normal'; + parentNode.style.fontWeight = 'normal'; + parentNode.style.letterSpacing = '0'; + parentNode.appendChild(node); + document.body.appendChild(parentNode); + + // Remember width with no applied web font + var width = node.offsetWidth; + node.style.fontFamily = font + ', ' + family; + return { node: node, w: width, parent: parentNode }; + } + + function checkLoadedFonts() { + var i, len = this.fonts.length; + var node, w; + var loadedCount = len; + for (i = 0; i < len; i += 1) { + if (this.fonts[i].loaded) { + loadedCount -= 1; + continue; + } + if (this.fonts[i].fOrigin === 'n' || this.fonts[i].origin === 0) { + this.fonts[i].loaded = true; + } else { + node = this.fonts[i].monoCase.node; + w = this.fonts[i].monoCase.w; + if (node.offsetWidth !== w) { + loadedCount -= 1; + this.fonts[i].loaded = true; + } else { + node = this.fonts[i].sansCase.node; + w = this.fonts[i].sansCase.w; + if (node.offsetWidth !== w) { + loadedCount -= 1; + this.fonts[i].loaded = true; + } + } + if (this.fonts[i].loaded) { + this.fonts[i].sansCase.parent.parentNode.removeChild(this.fonts[i].sansCase.parent); + this.fonts[i].monoCase.parent.parentNode.removeChild(this.fonts[i].monoCase.parent); + } + } + } + + if (loadedCount !== 0 && Date.now() - this.initTime < maxWaitingTime) { + setTimeout(this.checkLoadedFonts.bind(this), 20); + } else { + setTimeout(function () { this.isLoaded = true; }.bind(this), 0); + + } + } + + function createHelper(def, fontData) { + var tHelper = createNS('text'); + tHelper.style.fontSize = '100px'; + //tHelper.style.fontFamily = fontData.fFamily; + tHelper.setAttribute('font-family', fontData.fFamily); + tHelper.setAttribute('font-style', fontData.fStyle); + tHelper.setAttribute('font-weight', fontData.fWeight); + tHelper.textContent = '1'; + if (fontData.fClass) { + tHelper.style.fontFamily = 'inherit'; + tHelper.setAttribute('class', fontData.fClass); + } else { + tHelper.style.fontFamily = fontData.fFamily; + } + def.appendChild(tHelper); + var tCanvasHelper = createTag('canvas').getContext('2d'); + tCanvasHelper.font = fontData.fWeight + ' ' + fontData.fStyle + ' 100px ' + fontData.fFamily; + //tCanvasHelper.font = ' 100px '+ fontData.fFamily; + return tHelper; + } + + function addFonts(fontData, defs) { + if (!fontData) { + this.isLoaded = true; + return; + } + if (this.chars) { + this.isLoaded = true; + this.fonts = fontData.list; + return; + } + + + var fontArr = fontData.list; + var i, len = fontArr.length; + var _pendingFonts = len; + for (i = 0; i < len; i += 1) { + var shouldLoadFont = true; + var loadedSelector; + var j; + fontArr[i].loaded = false; + fontArr[i].monoCase = setUpNode(fontArr[i].fFamily, 'monospace'); + fontArr[i].sansCase = setUpNode(fontArr[i].fFamily, 'sans-serif'); + if (!fontArr[i].fPath) { + fontArr[i].loaded = true; + _pendingFonts -= 1; + } else if (fontArr[i].fOrigin === 'p' || fontArr[i].origin === 3) { + loadedSelector = document.querySelectorAll('style[f-forigin="p"][f-family="' + fontArr[i].fFamily + '"], style[f-origin="3"][f-family="' + fontArr[i].fFamily + '"]'); + + if (loadedSelector.length > 0) { + shouldLoadFont = false; + } + + if (shouldLoadFont) { + var s = createTag('style'); + s.setAttribute('f-forigin', fontArr[i].fOrigin); + s.setAttribute('f-origin', fontArr[i].origin); + s.setAttribute('f-family', fontArr[i].fFamily); + s.type = "text/css"; + s.innerHTML = "@font-face {" + "font-family: " + fontArr[i].fFamily + "; font-style: normal; src: url('" + fontArr[i].fPath + "');}"; + defs.appendChild(s); + } + } else if (fontArr[i].fOrigin === 'g' || fontArr[i].origin === 1) { + loadedSelector = document.querySelectorAll('link[f-forigin="g"], link[f-origin="1"]'); + + for (j = 0; j < loadedSelector.length; j++) { + if (loadedSelector[j].href.indexOf(fontArr[i].fPath) !== -1) { + // Font is already loaded + shouldLoadFont = false; + } + } + + if (shouldLoadFont) { + var l = createTag('link'); + l.setAttribute('f-forigin', fontArr[i].fOrigin); + l.setAttribute('f-origin', fontArr[i].origin); + l.type = "text/css"; + l.rel = "stylesheet"; + l.href = fontArr[i].fPath; + document.body.appendChild(l); + } + } else if (fontArr[i].fOrigin === 't' || fontArr[i].origin === 2) { + loadedSelector = document.querySelectorAll('script[f-forigin="t"], script[f-origin="2"]'); + + for (j = 0; j < loadedSelector.length; j++) { + if (fontArr[i].fPath === loadedSelector[j].src) { + // Font is already loaded + shouldLoadFont = false; + } + } + + if (shouldLoadFont) { + var sc = createTag('link'); + sc.setAttribute('f-forigin', fontArr[i].fOrigin); + sc.setAttribute('f-origin', fontArr[i].origin); + sc.setAttribute('rel', 'stylesheet'); + sc.setAttribute('href', fontArr[i].fPath); + defs.appendChild(sc); + } + } + fontArr[i].helper = createHelper(defs, fontArr[i]); + fontArr[i].cache = {}; + this.fonts.push(fontArr[i]); + } + if (_pendingFonts === 0) { + this.isLoaded = true; + } else { + //On some cases even if the font is loaded, it won't load correctly when measuring text on canvas. + //Adding this timeout seems to fix it + setTimeout(this.checkLoadedFonts.bind(this), 100); + } + } + + function addChars(chars) { + if (!chars) { + return; + } + if (!this.chars) { + this.chars = []; + } + var i, len = chars.length; + var j, jLen = this.chars.length, found; + for (i = 0; i < len; i += 1) { + j = 0; + found = false; + while (j < jLen) { + if (this.chars[j].style === chars[i].style && this.chars[j].fFamily === chars[i].fFamily && this.chars[j].ch === chars[i].ch) { + found = true; + } + j += 1; + } + if (!found) { + this.chars.push(chars[i]); + jLen += 1; + } + } + } + + function getCharData(char, style, font) { + var i = 0, len = this.chars.length; + while (i < len) { + if (this.chars[i].ch === char && this.chars[i].style === style && this.chars[i].fFamily === font) { + + return this.chars[i]; + } + i += 1; + } + if ((typeof char === 'string' && char.charCodeAt(0) !== 13 || !char) && console && console.warn) { + console.warn('Missing character from exported characters list: ', char, style, font); + } + return emptyChar; + } + + function measureText(char, fontName, size) { + var fontData = this.getFontByName(fontName); + var index = char.charCodeAt(0); + if (!fontData.cache[index + 1]) { + var tHelper = fontData.helper; + //Canvas version + //fontData.cache[index] = tHelper.measureText(char).width / 100; + //SVG version + //console.log(tHelper.getBBox().width) + if (char === ' ') { + tHelper.textContent = '|' + char + '|'; + var doubleSize = tHelper.getComputedTextLength(); + tHelper.textContent = '||'; + var singleSize = tHelper.getComputedTextLength(); + fontData.cache[index + 1] = (doubleSize - singleSize) / 100; + } else { + tHelper.textContent = char; + fontData.cache[index + 1] = (tHelper.getComputedTextLength()) / 100; + } + } + return fontData.cache[index + 1] * size; + } + + function getFontByName(name) { + var i = 0, len = this.fonts.length; + while (i < len) { + if (this.fonts[i].fName === name) { + return this.fonts[i]; + } + i += 1; + } + return this.fonts[0]; + } + + function getCombinedCharacterCodes() { + return combinedCharacters; + } + + function loaded() { + return this.isLoaded; + } + + var Font = function () { + this.fonts = []; + this.chars = null; + this.typekitLoaded = 0; + this.isLoaded = false; + this.initTime = Date.now(); + }; + //TODO: for now I'm adding these methods to the Class and not the prototype. Think of a better way to implement it. + Font.getCombinedCharacterCodes = getCombinedCharacterCodes; + + Font.prototype.addChars = addChars; + Font.prototype.addFonts = addFonts; + Font.prototype.getCharData = getCharData; + Font.prototype.getFontByName = getFontByName; + Font.prototype.measureText = measureText; + Font.prototype.checkLoadedFonts = checkLoadedFonts; + Font.prototype.loaded = loaded; + + return Font; + + }()); + var PropertyFactory = (function () { + + var initFrame = initialDefaultFrame; + var math_abs = Math.abs; + + function interpolateValue(frameNum, caching) { + var offsetTime = this.offsetTime; + var newValue; + if (this.propType === 'multidimensional') { + newValue = createTypedArray('float32', this.pv.length); + } + var iterationIndex = caching.lastIndex; + var i = iterationIndex; + var len = this.keyframes.length - 1, flag = true; + var keyData, nextKeyData; + + while (flag) { + keyData = this.keyframes[i]; + nextKeyData = this.keyframes[i + 1]; + if (i === len - 1 && frameNum >= nextKeyData.t - offsetTime) { + if (keyData.h) { + keyData = nextKeyData; + } + iterationIndex = 0; + break; + } + if ((nextKeyData.t - offsetTime) > frameNum) { + iterationIndex = i; + break; + } + if (i < len - 1) { + i += 1; + } else { + iterationIndex = 0; + flag = false; + } + } + + var k, kLen, perc, jLen, j, fnc; + var nextKeyTime = nextKeyData.t - offsetTime; + var keyTime = keyData.t - offsetTime; + var endValue; + if (keyData.to) { + if (!keyData.bezierData) { + keyData.bezierData = bez.buildBezierData(keyData.s, nextKeyData.s || keyData.e, keyData.to, keyData.ti); + } + var bezierData = keyData.bezierData; + if (frameNum >= nextKeyTime || frameNum < keyTime) { + var ind = frameNum >= nextKeyTime ? bezierData.points.length - 1 : 0; + kLen = bezierData.points[ind].point.length; + for (k = 0; k < kLen; k += 1) { + newValue[k] = bezierData.points[ind].point[k]; + } + // caching._lastKeyframeIndex = -1; + } else { + if (keyData.__fnct) { + fnc = keyData.__fnct; + } else { + fnc = BezierFactory.getBezierEasing(keyData.o.x, keyData.o.y, keyData.i.x, keyData.i.y, keyData.n).get; + keyData.__fnct = fnc; + } + perc = fnc((frameNum - keyTime) / (nextKeyTime - keyTime)); + var distanceInLine = bezierData.segmentLength * perc; + + var segmentPerc; + var addedLength = (caching.lastFrame < frameNum && caching._lastKeyframeIndex === i) ? caching._lastAddedLength : 0; + j = (caching.lastFrame < frameNum && caching._lastKeyframeIndex === i) ? caching._lastPoint : 0; + flag = true; + jLen = bezierData.points.length; + while (flag) { + addedLength += bezierData.points[j].partialLength; + if (distanceInLine === 0 || perc === 0 || j === bezierData.points.length - 1) { + kLen = bezierData.points[j].point.length; + for (k = 0; k < kLen; k += 1) { + newValue[k] = bezierData.points[j].point[k]; + } + break; + } else if (distanceInLine >= addedLength && distanceInLine < addedLength + bezierData.points[j + 1].partialLength) { + segmentPerc = (distanceInLine - addedLength) / bezierData.points[j + 1].partialLength; + kLen = bezierData.points[j].point.length; + for (k = 0; k < kLen; k += 1) { + newValue[k] = bezierData.points[j].point[k] + (bezierData.points[j + 1].point[k] - bezierData.points[j].point[k]) * segmentPerc; + } + break; + } + if (j < jLen - 1) { + j += 1; + } else { + flag = false; + } + } + caching._lastPoint = j; + caching._lastAddedLength = addedLength - bezierData.points[j].partialLength; + caching._lastKeyframeIndex = i; + } + } else { + var outX, outY, inX, inY, keyValue; + len = keyData.s.length; + endValue = nextKeyData.s || keyData.e; + if (this.sh && keyData.h !== 1) { + if (frameNum >= nextKeyTime) { + newValue[0] = endValue[0]; + newValue[1] = endValue[1]; + newValue[2] = endValue[2]; + } else if (frameNum <= keyTime) { + newValue[0] = keyData.s[0]; + newValue[1] = keyData.s[1]; + newValue[2] = keyData.s[2]; + } else { + var quatStart = createQuaternion(keyData.s); + var quatEnd = createQuaternion(endValue); + var time = (frameNum - keyTime) / (nextKeyTime - keyTime); + quaternionToEuler(newValue, slerp(quatStart, quatEnd, time)); + } + + } else { + for (i = 0; i < len; i += 1) { + if (keyData.h !== 1) { + if (frameNum >= nextKeyTime) { + perc = 1; + } else if (frameNum < keyTime) { + perc = 0; + } else { + if (keyData.o.x.constructor === Array) { + if (!keyData.__fnct) { + keyData.__fnct = []; + } + if (!keyData.__fnct[i]) { + outX = (typeof keyData.o.x[i] === 'undefined') ? keyData.o.x[0] : keyData.o.x[i]; + outY = (typeof keyData.o.y[i] === 'undefined') ? keyData.o.y[0] : keyData.o.y[i]; + inX = (typeof keyData.i.x[i] === 'undefined') ? keyData.i.x[0] : keyData.i.x[i]; + inY = (typeof keyData.i.y[i] === 'undefined') ? keyData.i.y[0] : keyData.i.y[i]; + fnc = BezierFactory.getBezierEasing(outX, outY, inX, inY).get; + keyData.__fnct[i] = fnc; + } else { + fnc = keyData.__fnct[i]; + } + } else { + if (!keyData.__fnct) { + outX = keyData.o.x; + outY = keyData.o.y; + inX = keyData.i.x; + inY = keyData.i.y; + fnc = BezierFactory.getBezierEasing(outX, outY, inX, inY).get; + keyData.__fnct = fnc; + } else { + fnc = keyData.__fnct; + } + } + perc = fnc((frameNum - keyTime) / (nextKeyTime - keyTime)); + } + } + + endValue = nextKeyData.s || keyData.e; + keyValue = keyData.h === 1 ? keyData.s[i] : keyData.s[i] + (endValue[i] - keyData.s[i]) * perc; + + if (this.propType === 'multidimensional') { + newValue[i] = keyValue; + } else { + newValue = keyValue; + } + } + } + } + caching.lastIndex = iterationIndex; + return newValue; + } + + //based on @Toji's https://github.com/toji/gl-matrix/ + function slerp(a, b, t) { + var out = []; + var ax = a[0], ay = a[1], az = a[2], aw = a[3], + bx = b[0], by = b[1], bz = b[2], bw = b[3] + + var omega, cosom, sinom, scale0, scale1; + + cosom = ax * bx + ay * by + az * bz + aw * bw; + if (cosom < 0.0) { + cosom = -cosom; + bx = -bx; + by = -by; + bz = -bz; + bw = -bw; + } + if ((1.0 - cosom) > 0.000001) { + omega = Math.acos(cosom); + sinom = Math.sin(omega); + scale0 = Math.sin((1.0 - t) * omega) / sinom; + scale1 = Math.sin(t * omega) / sinom; + } else { + scale0 = 1.0 - t; + scale1 = t; + } + out[0] = scale0 * ax + scale1 * bx; + out[1] = scale0 * ay + scale1 * by; + out[2] = scale0 * az + scale1 * bz; + out[3] = scale0 * aw + scale1 * bw; + + return out; + } + + function quaternionToEuler(out, quat) { + var qx = quat[0]; + var qy = quat[1]; + var qz = quat[2]; + var qw = quat[3]; + var heading = Math.atan2(2 * qy * qw - 2 * qx * qz, 1 - 2 * qy * qy - 2 * qz * qz) + var attitude = Math.asin(2 * qx * qy + 2 * qz * qw) + var bank = Math.atan2(2 * qx * qw - 2 * qy * qz, 1 - 2 * qx * qx - 2 * qz * qz); + out[0] = heading / degToRads; + out[1] = attitude / degToRads; + out[2] = bank / degToRads; + } + + function createQuaternion(values) { + var heading = values[0] * degToRads; + var attitude = values[1] * degToRads; + var bank = values[2] * degToRads; + var c1 = Math.cos(heading / 2); + var c2 = Math.cos(attitude / 2); + var c3 = Math.cos(bank / 2); + var s1 = Math.sin(heading / 2); + var s2 = Math.sin(attitude / 2); + var s3 = Math.sin(bank / 2); + var w = c1 * c2 * c3 - s1 * s2 * s3; + var x = s1 * s2 * c3 + c1 * c2 * s3; + var y = s1 * c2 * c3 + c1 * s2 * s3; + var z = c1 * s2 * c3 - s1 * c2 * s3; + + return [x, y, z, w]; + } + + function getValueAtCurrentTime() { + var frameNum = this.comp.renderedFrame - this.offsetTime; + var initTime = this.keyframes[0].t - this.offsetTime; + var endTime = this.keyframes[this.keyframes.length - 1].t - this.offsetTime; + if (!(frameNum === this._caching.lastFrame || (this._caching.lastFrame !== initFrame && ((this._caching.lastFrame >= endTime && frameNum >= endTime) || (this._caching.lastFrame < initTime && frameNum < initTime))))) { + if (this._caching.lastFrame >= frameNum) { + this._caching._lastKeyframeIndex = -1; + this._caching.lastIndex = 0; + } + + var renderResult = this.interpolateValue(frameNum, this._caching); + this.pv = renderResult; + } + this._caching.lastFrame = frameNum; + return this.pv; + } + + function setVValue(val) { + var multipliedValue; + if (this.propType === 'unidimensional') { + multipliedValue = val * this.mult; + if (math_abs(this.v - multipliedValue) > 0.00001) { + this.v = multipliedValue; + this._mdf = true; + } + } else { + var i = 0, len = this.v.length; + while (i < len) { + multipliedValue = val[i] * this.mult; + if (math_abs(this.v[i] - multipliedValue) > 0.00001) { + this.v[i] = multipliedValue; + this._mdf = true; + } + i += 1; + } + } + } + + function processEffectsSequence() { + if (this.elem.globalData.frameId === this.frameId || !this.effectsSequence.length) { + return; + } + if (this.lock) { + this.setVValue(this.pv); + return; + } + this.lock = true; + this._mdf = this._isFirstFrame; + var multipliedValue; + var i, len = this.effectsSequence.length; + var finalValue = this.kf ? this.pv : this.data.k; + for (i = 0; i < len; i += 1) { + finalValue = this.effectsSequence[i](finalValue); + } + this.setVValue(finalValue); + this._isFirstFrame = false; + this.lock = false; + this.frameId = this.elem.globalData.frameId; + } + + function addEffect(effectFunction) { + this.effectsSequence.push(effectFunction); + this.container.addDynamicProperty(this); + } + + function ValueProperty(elem, data, mult, container) { + this.propType = 'unidimensional'; + this.mult = mult || 1; + this.data = data; + this.v = mult ? data.k * mult : data.k; + this.pv = data.k; + this._mdf = false; + this.elem = elem; + this.container = container; + this.comp = elem.comp; + this.k = false; + this.kf = false; + this.vel = 0; + this.effectsSequence = []; + this._isFirstFrame = true; + this.getValue = processEffectsSequence; + this.setVValue = setVValue; + this.addEffect = addEffect; + } + + function MultiDimensionalProperty(elem, data, mult, container) { + this.propType = 'multidimensional'; + this.mult = mult || 1; + this.data = data; + this._mdf = false; + this.elem = elem; + this.container = container; + this.comp = elem.comp; + this.k = false; + this.kf = false; + this.frameId = -1; + var i, len = data.k.length; + this.v = createTypedArray('float32', len); + this.pv = createTypedArray('float32', len); + var arr = createTypedArray('float32', len); + this.vel = createTypedArray('float32', len); + for (i = 0; i < len; i += 1) { + this.v[i] = data.k[i] * this.mult; + this.pv[i] = data.k[i]; + } + this._isFirstFrame = true; + this.effectsSequence = []; + this.getValue = processEffectsSequence; + this.setVValue = setVValue; + this.addEffect = addEffect; + } + + function KeyframedValueProperty(elem, data, mult, container) { + this.propType = 'unidimensional'; + this.keyframes = data.k; + this.offsetTime = elem.data.st; + this.frameId = -1; + this._caching = { lastFrame: initFrame, lastIndex: 0, value: 0, _lastKeyframeIndex: -1 }; + this.k = true; + this.kf = true; + this.data = data; + this.mult = mult || 1; + this.elem = elem; + this.container = container; + this.comp = elem.comp; + this.v = initFrame; + this.pv = initFrame; + this._isFirstFrame = true; + this.getValue = processEffectsSequence; + this.setVValue = setVValue; + this.interpolateValue = interpolateValue; + this.effectsSequence = [getValueAtCurrentTime.bind(this)]; + this.addEffect = addEffect; + } + + function KeyframedMultidimensionalProperty(elem, data, mult, container) { + this.propType = 'multidimensional'; + var i, len = data.k.length; + var s, e, to, ti; + for (i = 0; i < len - 1; i += 1) { + if (data.k[i].to && data.k[i].s && data.k[i + 1] && data.k[i + 1].s) { + s = data.k[i].s; + e = data.k[i + 1].s; + to = data.k[i].to; + ti = data.k[i].ti; + if ((s.length === 2 && !(s[0] === e[0] && s[1] === e[1]) && bez.pointOnLine2D(s[0], s[1], e[0], e[1], s[0] + to[0], s[1] + to[1]) && bez.pointOnLine2D(s[0], s[1], e[0], e[1], e[0] + ti[0], e[1] + ti[1])) || (s.length === 3 && !(s[0] === e[0] && s[1] === e[1] && s[2] === e[2]) && bez.pointOnLine3D(s[0], s[1], s[2], e[0], e[1], e[2], s[0] + to[0], s[1] + to[1], s[2] + to[2]) && bez.pointOnLine3D(s[0], s[1], s[2], e[0], e[1], e[2], e[0] + ti[0], e[1] + ti[1], e[2] + ti[2]))) { + data.k[i].to = null; + data.k[i].ti = null; + } + if (s[0] === e[0] && s[1] === e[1] && to[0] === 0 && to[1] === 0 && ti[0] === 0 && ti[1] === 0) { + if (s.length === 2 || (s[2] === e[2] && to[2] === 0 && ti[2] === 0)) { + data.k[i].to = null; + data.k[i].ti = null; + } + } + } + } + this.effectsSequence = [getValueAtCurrentTime.bind(this)]; + this.keyframes = data.k; + this.offsetTime = elem.data.st; + this.k = true; + this.kf = true; + this._isFirstFrame = true; + this.mult = mult || 1; + this.elem = elem; + this.container = container; + this.comp = elem.comp; + this.getValue = processEffectsSequence; + this.setVValue = setVValue; + this.interpolateValue = interpolateValue; + this.frameId = -1; + var arrLen = data.k[0].s.length; + this.v = createTypedArray('float32', arrLen); + this.pv = createTypedArray('float32', arrLen); + for (i = 0; i < arrLen; i += 1) { + this.v[i] = initFrame; + this.pv[i] = initFrame; + } + this._caching = { lastFrame: initFrame, lastIndex: 0, value: createTypedArray('float32', arrLen) }; + this.addEffect = addEffect; + } + + function getProp(elem, data, type, mult, container) { + var p; + if (!data.k.length) { + p = new ValueProperty(elem, data, mult, container); + } else if (typeof (data.k[0]) === 'number') { + p = new MultiDimensionalProperty(elem, data, mult, container); + } else { + switch (type) { + case 0: + p = new KeyframedValueProperty(elem, data, mult, container); + break; + case 1: + p = new KeyframedMultidimensionalProperty(elem, data, mult, container); + break; + } + } + if (p.effectsSequence.length) { + container.addDynamicProperty(p); + } + return p; + } + + var ob = { + getProp: getProp + }; + return ob; + }()); + var TransformPropertyFactory = (function () { + + var defaultVector = [0, 0] + + function applyToMatrix(mat) { + var _mdf = this._mdf; + this.iterateDynamicProperties(); + this._mdf = this._mdf || _mdf; + if (this.a) { + mat.translate(-this.a.v[0], -this.a.v[1], this.a.v[2]); + } + if (this.s) { + mat.scale(this.s.v[0], this.s.v[1], this.s.v[2]); + } + if (this.sk) { + mat.skewFromAxis(-this.sk.v, this.sa.v); + } + if (this.r) { + mat.rotate(-this.r.v); + } else { + mat.rotateZ(-this.rz.v).rotateY(this.ry.v).rotateX(this.rx.v).rotateZ(-this.or.v[2]).rotateY(this.or.v[1]).rotateX(this.or.v[0]); + } + if (this.data.p.s) { + if (this.data.p.z) { + mat.translate(this.px.v, this.py.v, -this.pz.v); + } else { + mat.translate(this.px.v, this.py.v, 0); + } + } else { + mat.translate(this.p.v[0], this.p.v[1], -this.p.v[2]); + } + } + function processKeys(forceRender) { + if (this.elem.globalData.frameId === this.frameId) { + return; + } + if (this._isDirty) { + this.precalculateMatrix(); + this._isDirty = false; + } + + this.iterateDynamicProperties(); + + if (this._mdf || forceRender) { + this.v.cloneFromProps(this.pre.props); + if (this.appliedTransformations < 1) { + this.v.translate(-this.a.v[0], -this.a.v[1], this.a.v[2]); + } + if (this.appliedTransformations < 2) { + this.v.scale(this.s.v[0], this.s.v[1], this.s.v[2]); + } + if (this.sk && this.appliedTransformations < 3) { + this.v.skewFromAxis(-this.sk.v, this.sa.v); + } + if (this.r && this.appliedTransformations < 4) { + this.v.rotate(-this.r.v); + } else if (!this.r && this.appliedTransformations < 4) { + this.v.rotateZ(-this.rz.v).rotateY(this.ry.v).rotateX(this.rx.v).rotateZ(-this.or.v[2]).rotateY(this.or.v[1]).rotateX(this.or.v[0]); + } + if (this.autoOriented) { + var v1, v2, frameRate = this.elem.globalData.frameRate; + if (this.p && this.p.keyframes && this.p.getValueAtTime) { + if (this.p._caching.lastFrame + this.p.offsetTime <= this.p.keyframes[0].t) { + v1 = this.p.getValueAtTime((this.p.keyframes[0].t + 0.01) / frameRate, 0); + v2 = this.p.getValueAtTime(this.p.keyframes[0].t / frameRate, 0); + } else if (this.p._caching.lastFrame + this.p.offsetTime >= this.p.keyframes[this.p.keyframes.length - 1].t) { + v1 = this.p.getValueAtTime((this.p.keyframes[this.p.keyframes.length - 1].t / frameRate), 0); + v2 = this.p.getValueAtTime((this.p.keyframes[this.p.keyframes.length - 1].t - 0.05) / frameRate, 0); + } else { + v1 = this.p.pv; + v2 = this.p.getValueAtTime((this.p._caching.lastFrame + this.p.offsetTime - 0.01) / frameRate, this.p.offsetTime); + } + } else if (this.px && this.px.keyframes && this.py.keyframes && this.px.getValueAtTime && this.py.getValueAtTime) { + v1 = []; + v2 = []; + var px = this.px, py = this.py, frameRate; + if (px._caching.lastFrame + px.offsetTime <= px.keyframes[0].t) { + v1[0] = px.getValueAtTime((px.keyframes[0].t + 0.01) / frameRate, 0); + v1[1] = py.getValueAtTime((py.keyframes[0].t + 0.01) / frameRate, 0); + v2[0] = px.getValueAtTime((px.keyframes[0].t) / frameRate, 0); + v2[1] = py.getValueAtTime((py.keyframes[0].t) / frameRate, 0); + } else if (px._caching.lastFrame + px.offsetTime >= px.keyframes[px.keyframes.length - 1].t) { + v1[0] = px.getValueAtTime((px.keyframes[px.keyframes.length - 1].t / frameRate), 0); + v1[1] = py.getValueAtTime((py.keyframes[py.keyframes.length - 1].t / frameRate), 0); + v2[0] = px.getValueAtTime((px.keyframes[px.keyframes.length - 1].t - 0.01) / frameRate, 0); + v2[1] = py.getValueAtTime((py.keyframes[py.keyframes.length - 1].t - 0.01) / frameRate, 0); + } else { + v1 = [px.pv, py.pv]; + v2[0] = px.getValueAtTime((px._caching.lastFrame + px.offsetTime - 0.01) / frameRate, px.offsetTime); + v2[1] = py.getValueAtTime((py._caching.lastFrame + py.offsetTime - 0.01) / frameRate, py.offsetTime); + } + } else { + v1 = v2 = defaultVector + } + this.v.rotate(-Math.atan2(v1[1] - v2[1], v1[0] - v2[0])); + } + if (this.data.p && this.data.p.s) { + if (this.data.p.z) { + this.v.translate(this.px.v, this.py.v, -this.pz.v); + } else { + this.v.translate(this.px.v, this.py.v, 0); + } + } else { + this.v.translate(this.p.v[0], this.p.v[1], -this.p.v[2]); + } + } + this.frameId = this.elem.globalData.frameId; + } + + function precalculateMatrix() { + if (!this.a.k) { + this.pre.translate(-this.a.v[0], -this.a.v[1], this.a.v[2]); + this.appliedTransformations = 1; + } else { + return; + } + if (!this.s.effectsSequence.length) { + this.pre.scale(this.s.v[0], this.s.v[1], this.s.v[2]); + this.appliedTransformations = 2; + } else { + return; + } + if (this.sk) { + if (!this.sk.effectsSequence.length && !this.sa.effectsSequence.length) { + this.pre.skewFromAxis(-this.sk.v, this.sa.v); + this.appliedTransformations = 3; + } else { + return; + } + } + if (this.r) { + if (!this.r.effectsSequence.length) { + this.pre.rotate(-this.r.v); + this.appliedTransformations = 4; + } else { + return; + } + } else if (!this.rz.effectsSequence.length && !this.ry.effectsSequence.length && !this.rx.effectsSequence.length && !this.or.effectsSequence.length) { + this.pre.rotateZ(-this.rz.v).rotateY(this.ry.v).rotateX(this.rx.v).rotateZ(-this.or.v[2]).rotateY(this.or.v[1]).rotateX(this.or.v[0]); + this.appliedTransformations = 4; + } + } + + function autoOrient() { + // + //var prevP = this.getValueAtTime(); + } + + function addDynamicProperty(prop) { + this._addDynamicProperty(prop); + this.elem.addDynamicProperty(prop); + this._isDirty = true; + } + + function TransformProperty(elem, data, container) { + this.elem = elem; + this.frameId = -1; + this.propType = 'transform'; + this.data = data; + this.v = new Matrix(); + //Precalculated matrix with non animated properties + this.pre = new Matrix(); + this.appliedTransformations = 0; + this.initDynamicPropertyContainer(container || elem); + if (data.p && data.p.s) { + this.px = PropertyFactory.getProp(elem, data.p.x, 0, 0, this); + this.py = PropertyFactory.getProp(elem, data.p.y, 0, 0, this); + if (data.p.z) { + this.pz = PropertyFactory.getProp(elem, data.p.z, 0, 0, this); + } + } else { + this.p = PropertyFactory.getProp(elem, data.p || { k: [0, 0, 0] }, 1, 0, this); + } + if (data.rx) { + this.rx = PropertyFactory.getProp(elem, data.rx, 0, degToRads, this); + this.ry = PropertyFactory.getProp(elem, data.ry, 0, degToRads, this); + this.rz = PropertyFactory.getProp(elem, data.rz, 0, degToRads, this); + if (data.or.k[0].ti) { + var i, len = data.or.k.length; + for (i = 0; i < len; i += 1) { + data.or.k[i].to = data.or.k[i].ti = null; + } + } + this.or = PropertyFactory.getProp(elem, data.or, 1, degToRads, this); + //sh Indicates it needs to be capped between -180 and 180 + this.or.sh = true; + } else { + this.r = PropertyFactory.getProp(elem, data.r || { k: 0 }, 0, degToRads, this); + } + if (data.sk) { + this.sk = PropertyFactory.getProp(elem, data.sk, 0, degToRads, this); + this.sa = PropertyFactory.getProp(elem, data.sa, 0, degToRads, this); + } + this.a = PropertyFactory.getProp(elem, data.a || { k: [0, 0, 0] }, 1, 0, this); + this.s = PropertyFactory.getProp(elem, data.s || { k: [100, 100, 100] }, 1, 0.01, this); + // Opacity is not part of the transform properties, that's why it won't use this.dynamicProperties. That way transforms won't get updated if opacity changes. + if (data.o) { + this.o = PropertyFactory.getProp(elem, data.o, 0, 0.01, elem); + } else { + this.o = { _mdf: false, v: 1 }; + } + this._isDirty = true; + if (!this.dynamicProperties.length) { + this.getValue(true); + } + } + + TransformProperty.prototype = { + applyToMatrix: applyToMatrix, + getValue: processKeys, + precalculateMatrix: precalculateMatrix, + autoOrient: autoOrient + } + + extendPrototype([DynamicPropertyContainer], TransformProperty); + TransformProperty.prototype.addDynamicProperty = addDynamicProperty; + TransformProperty.prototype._addDynamicProperty = DynamicPropertyContainer.prototype.addDynamicProperty; + + function getTransformProperty(elem, data, container) { + return new TransformProperty(elem, data, container); + } + + return { + getTransformProperty: getTransformProperty + }; + + }()); + function ShapePath() { + this.c = false; + this._length = 0; + this._maxLength = 8; + this.v = createSizedArray(this._maxLength); + this.o = createSizedArray(this._maxLength); + this.i = createSizedArray(this._maxLength); + } + + ShapePath.prototype.setPathData = function (closed, len) { + this.c = closed; + this.setLength(len); + var i = 0; + while (i < len) { + this.v[i] = point_pool.newElement(); + this.o[i] = point_pool.newElement(); + this.i[i] = point_pool.newElement(); + i += 1; + } + }; + + ShapePath.prototype.setLength = function (len) { + while (this._maxLength < len) { + this.doubleArrayLength(); + } + this._length = len; + }; + + ShapePath.prototype.doubleArrayLength = function () { + this.v = this.v.concat(createSizedArray(this._maxLength)); + this.i = this.i.concat(createSizedArray(this._maxLength)); + this.o = this.o.concat(createSizedArray(this._maxLength)); + this._maxLength *= 2; + }; + + ShapePath.prototype.setXYAt = function (x, y, type, pos, replace) { + var arr; + this._length = Math.max(this._length, pos + 1); + if (this._length >= this._maxLength) { + this.doubleArrayLength(); + } + switch (type) { + case 'v': + arr = this.v; + break; + case 'i': + arr = this.i; + break; + case 'o': + arr = this.o; + break; + } + if (!arr[pos] || (arr[pos] && !replace)) { + arr[pos] = point_pool.newElement(); + } + arr[pos][0] = x; + arr[pos][1] = y; + }; + + ShapePath.prototype.setTripleAt = function (vX, vY, oX, oY, iX, iY, pos, replace) { + this.setXYAt(vX, vY, 'v', pos, replace); + this.setXYAt(oX, oY, 'o', pos, replace); + this.setXYAt(iX, iY, 'i', pos, replace); + }; + + ShapePath.prototype.reverse = function () { + var newPath = new ShapePath(); + newPath.setPathData(this.c, this._length); + var vertices = this.v, outPoints = this.o, inPoints = this.i; + var init = 0; + if (this.c) { + newPath.setTripleAt(vertices[0][0], vertices[0][1], inPoints[0][0], inPoints[0][1], outPoints[0][0], outPoints[0][1], 0, false); + init = 1; + } + var cnt = this._length - 1; + var len = this._length; + + var i; + for (i = init; i < len; i += 1) { + newPath.setTripleAt(vertices[cnt][0], vertices[cnt][1], inPoints[cnt][0], inPoints[cnt][1], outPoints[cnt][0], outPoints[cnt][1], i, false); + cnt -= 1; + } + return newPath; + }; + var ShapePropertyFactory = (function () { + + var initFrame = -999999; + + function interpolateShape(frameNum, previousValue, caching) { + var iterationIndex = caching.lastIndex; + var keyPropS, keyPropE, isHold, j, k, jLen, kLen, perc, vertexValue; + var kf = this.keyframes; + if (frameNum < kf[0].t - this.offsetTime) { + keyPropS = kf[0].s[0]; + isHold = true; + iterationIndex = 0; + } else if (frameNum >= kf[kf.length - 1].t - this.offsetTime) { + keyPropS = kf[kf.length - 1].s ? kf[kf.length - 1].s[0] : kf[kf.length - 2].e[0]; + /*if(kf[kf.length - 1].s){ + keyPropS = kf[kf.length - 1].s[0]; + }else{ + keyPropS = kf[kf.length - 2].e[0]; + }*/ + isHold = true; + } else { + var i = iterationIndex; + var len = kf.length - 1, flag = true, keyData, nextKeyData; + while (flag) { + keyData = kf[i]; + nextKeyData = kf[i + 1]; + if ((nextKeyData.t - this.offsetTime) > frameNum) { + break; + } + if (i < len - 1) { + i += 1; + } else { + flag = false; + } + } + isHold = keyData.h === 1; + iterationIndex = i; + if (!isHold) { + if (frameNum >= nextKeyData.t - this.offsetTime) { + perc = 1; + } else if (frameNum < keyData.t - this.offsetTime) { + perc = 0; + } else { + var fnc; + if (keyData.__fnct) { + fnc = keyData.__fnct; + } else { + fnc = BezierFactory.getBezierEasing(keyData.o.x, keyData.o.y, keyData.i.x, keyData.i.y).get; + keyData.__fnct = fnc; + } + perc = fnc((frameNum - (keyData.t - this.offsetTime)) / ((nextKeyData.t - this.offsetTime) - (keyData.t - this.offsetTime))); + } + keyPropE = nextKeyData.s ? nextKeyData.s[0] : keyData.e[0]; + } + keyPropS = keyData.s[0]; + } + jLen = previousValue._length; + kLen = keyPropS.i[0].length; + caching.lastIndex = iterationIndex; + + for (j = 0; j < jLen; j += 1) { + for (k = 0; k < kLen; k += 1) { + vertexValue = isHold ? keyPropS.i[j][k] : keyPropS.i[j][k] + (keyPropE.i[j][k] - keyPropS.i[j][k]) * perc; + previousValue.i[j][k] = vertexValue; + vertexValue = isHold ? keyPropS.o[j][k] : keyPropS.o[j][k] + (keyPropE.o[j][k] - keyPropS.o[j][k]) * perc; + previousValue.o[j][k] = vertexValue; + vertexValue = isHold ? keyPropS.v[j][k] : keyPropS.v[j][k] + (keyPropE.v[j][k] - keyPropS.v[j][k]) * perc; + previousValue.v[j][k] = vertexValue; + } + } + } + + function interpolateShapeCurrentTime() { + var frameNum = this.comp.renderedFrame - this.offsetTime; + var initTime = this.keyframes[0].t - this.offsetTime; + var endTime = this.keyframes[this.keyframes.length - 1].t - this.offsetTime; + var lastFrame = this._caching.lastFrame; + if (!(lastFrame !== initFrame && ((lastFrame < initTime && frameNum < initTime) || (lastFrame > endTime && frameNum > endTime)))) { + //// + this._caching.lastIndex = lastFrame < frameNum ? this._caching.lastIndex : 0; + this.interpolateShape(frameNum, this.pv, this._caching); + //// + } + this._caching.lastFrame = frameNum; + return this.pv; + } + + function resetShape() { + this.paths = this.localShapeCollection; + } + + function shapesEqual(shape1, shape2) { + if (shape1._length !== shape2._length || shape1.c !== shape2.c) { + return false; + } + var i, len = shape1._length; + for (i = 0; i < len; i += 1) { + if (shape1.v[i][0] !== shape2.v[i][0] + || shape1.v[i][1] !== shape2.v[i][1] + || shape1.o[i][0] !== shape2.o[i][0] + || shape1.o[i][1] !== shape2.o[i][1] + || shape1.i[i][0] !== shape2.i[i][0] + || shape1.i[i][1] !== shape2.i[i][1]) { + return false; + } + } + return true; + } + + function setVValue(newPath) { + if (!shapesEqual(this.v, newPath)) { + this.v = shape_pool.clone(newPath); + this.localShapeCollection.releaseShapes(); + this.localShapeCollection.addShape(this.v); + this._mdf = true; + this.paths = this.localShapeCollection; + } + } + + function processEffectsSequence() { + if (this.elem.globalData.frameId === this.frameId) { + return; + } else if (!this.effectsSequence.length) { + this._mdf = false; + return; + } + if (this.lock) { + this.setVValue(this.pv); + return; + } + this.lock = true; + this._mdf = false; + var finalValue = this.kf ? this.pv : this.data.ks ? this.data.ks.k : this.data.pt.k; + var i, len = this.effectsSequence.length; + for (i = 0; i < len; i += 1) { + finalValue = this.effectsSequence[i](finalValue); + } + this.setVValue(finalValue); + this.lock = false; + this.frameId = this.elem.globalData.frameId; + }; + + function ShapeProperty(elem, data, type) { + this.propType = 'shape'; + this.comp = elem.comp; + this.container = elem; + this.elem = elem; + this.data = data; + this.k = false; + this.kf = false; + this._mdf = false; + var pathData = type === 3 ? data.pt.k : data.ks.k; + this.v = shape_pool.clone(pathData); + this.pv = shape_pool.clone(this.v); + this.localShapeCollection = shapeCollection_pool.newShapeCollection(); + this.paths = this.localShapeCollection; + this.paths.addShape(this.v); + this.reset = resetShape; + this.effectsSequence = []; + } + + function addEffect(effectFunction) { + this.effectsSequence.push(effectFunction); + this.container.addDynamicProperty(this); + } + + ShapeProperty.prototype.interpolateShape = interpolateShape; + ShapeProperty.prototype.getValue = processEffectsSequence; + ShapeProperty.prototype.setVValue = setVValue; + ShapeProperty.prototype.addEffect = addEffect; + + function KeyframedShapeProperty(elem, data, type) { + this.propType = 'shape'; + this.comp = elem.comp; + this.elem = elem; + this.container = elem; + this.offsetTime = elem.data.st; + this.keyframes = type === 3 ? data.pt.k : data.ks.k; + this.k = true; + this.kf = true; + var i, len = this.keyframes[0].s[0].i.length; + var jLen = this.keyframes[0].s[0].i[0].length; + this.v = shape_pool.newElement(); + this.v.setPathData(this.keyframes[0].s[0].c, len); + this.pv = shape_pool.clone(this.v); + this.localShapeCollection = shapeCollection_pool.newShapeCollection(); + this.paths = this.localShapeCollection; + this.paths.addShape(this.v); + this.lastFrame = initFrame; + this.reset = resetShape; + this._caching = { lastFrame: initFrame, lastIndex: 0 }; + this.effectsSequence = [interpolateShapeCurrentTime.bind(this)]; + } + KeyframedShapeProperty.prototype.getValue = processEffectsSequence; + KeyframedShapeProperty.prototype.interpolateShape = interpolateShape; + KeyframedShapeProperty.prototype.setVValue = setVValue; + KeyframedShapeProperty.prototype.addEffect = addEffect; + + var EllShapeProperty = (function () { + + var cPoint = roundCorner; + + function EllShapeProperty(elem, data) { + /*this.v = { + v: createSizedArray(4), + i: createSizedArray(4), + o: createSizedArray(4), + c: true + };*/ + this.v = shape_pool.newElement(); + this.v.setPathData(true, 4); + this.localShapeCollection = shapeCollection_pool.newShapeCollection(); + this.paths = this.localShapeCollection; + this.localShapeCollection.addShape(this.v); + this.d = data.d; + this.elem = elem; + this.comp = elem.comp; + this.frameId = -1; + this.initDynamicPropertyContainer(elem); + this.p = PropertyFactory.getProp(elem, data.p, 1, 0, this); + this.s = PropertyFactory.getProp(elem, data.s, 1, 0, this); + if (this.dynamicProperties.length) { + this.k = true; + } else { + this.k = false; + this.convertEllToPath(); + } + }; + + EllShapeProperty.prototype = { + reset: resetShape, + getValue: function () { + if (this.elem.globalData.frameId === this.frameId) { + return; + } + this.frameId = this.elem.globalData.frameId; + this.iterateDynamicProperties(); + + if (this._mdf) { + this.convertEllToPath(); + } + }, + convertEllToPath: function () { + var p0 = this.p.v[0], p1 = this.p.v[1], s0 = this.s.v[0] / 2, s1 = this.s.v[1] / 2; + var _cw = this.d !== 3; + var _v = this.v; + _v.v[0][0] = p0; + _v.v[0][1] = p1 - s1; + _v.v[1][0] = _cw ? p0 + s0 : p0 - s0; + _v.v[1][1] = p1; + _v.v[2][0] = p0; + _v.v[2][1] = p1 + s1; + _v.v[3][0] = _cw ? p0 - s0 : p0 + s0; + _v.v[3][1] = p1; + _v.i[0][0] = _cw ? p0 - s0 * cPoint : p0 + s0 * cPoint; + _v.i[0][1] = p1 - s1; + _v.i[1][0] = _cw ? p0 + s0 : p0 - s0; + _v.i[1][1] = p1 - s1 * cPoint; + _v.i[2][0] = _cw ? p0 + s0 * cPoint : p0 - s0 * cPoint; + _v.i[2][1] = p1 + s1; + _v.i[3][0] = _cw ? p0 - s0 : p0 + s0; + _v.i[3][1] = p1 + s1 * cPoint; + _v.o[0][0] = _cw ? p0 + s0 * cPoint : p0 - s0 * cPoint; + _v.o[0][1] = p1 - s1; + _v.o[1][0] = _cw ? p0 + s0 : p0 - s0; + _v.o[1][1] = p1 + s1 * cPoint; + _v.o[2][0] = _cw ? p0 - s0 * cPoint : p0 + s0 * cPoint; + _v.o[2][1] = p1 + s1; + _v.o[3][0] = _cw ? p0 - s0 : p0 + s0; + _v.o[3][1] = p1 - s1 * cPoint; + } + } + + extendPrototype([DynamicPropertyContainer], EllShapeProperty); + + return EllShapeProperty; + }()); + + var StarShapeProperty = (function () { + + function StarShapeProperty(elem, data) { + this.v = shape_pool.newElement(); + this.v.setPathData(true, 0); + this.elem = elem; + this.comp = elem.comp; + this.data = data; + this.frameId = -1; + this.d = data.d; + this.initDynamicPropertyContainer(elem); + if (data.sy === 1) { + this.ir = PropertyFactory.getProp(elem, data.ir, 0, 0, this); + this.is = PropertyFactory.getProp(elem, data.is, 0, 0.01, this); + this.convertToPath = this.convertStarToPath; + } else { + this.convertToPath = this.convertPolygonToPath; + } + this.pt = PropertyFactory.getProp(elem, data.pt, 0, 0, this); + this.p = PropertyFactory.getProp(elem, data.p, 1, 0, this); + this.r = PropertyFactory.getProp(elem, data.r, 0, degToRads, this); + this.or = PropertyFactory.getProp(elem, data.or, 0, 0, this); + this.os = PropertyFactory.getProp(elem, data.os, 0, 0.01, this); + this.localShapeCollection = shapeCollection_pool.newShapeCollection(); + this.localShapeCollection.addShape(this.v); + this.paths = this.localShapeCollection; + if (this.dynamicProperties.length) { + this.k = true; + } else { + this.k = false; + this.convertToPath(); + } + }; + + StarShapeProperty.prototype = { + reset: resetShape, + getValue: function () { + if (this.elem.globalData.frameId === this.frameId) { + return; + } + this.frameId = this.elem.globalData.frameId; + this.iterateDynamicProperties(); + if (this._mdf) { + this.convertToPath(); + } + }, + convertStarToPath: function () { + var numPts = Math.floor(this.pt.v) * 2; + var angle = Math.PI * 2 / numPts; + /*this.v.v.length = numPts; + this.v.i.length = numPts; + this.v.o.length = numPts;*/ + var longFlag = true; + var longRad = this.or.v; + var shortRad = this.ir.v; + var longRound = this.os.v; + var shortRound = this.is.v; + var longPerimSegment = 2 * Math.PI * longRad / (numPts * 2); + var shortPerimSegment = 2 * Math.PI * shortRad / (numPts * 2); + var i, rad, roundness, perimSegment, currentAng = -Math.PI / 2; + currentAng += this.r.v; + var dir = this.data.d === 3 ? -1 : 1; + this.v._length = 0; + for (i = 0; i < numPts; i += 1) { + rad = longFlag ? longRad : shortRad; + roundness = longFlag ? longRound : shortRound; + perimSegment = longFlag ? longPerimSegment : shortPerimSegment; + var x = rad * Math.cos(currentAng); + var y = rad * Math.sin(currentAng); + var ox = x === 0 && y === 0 ? 0 : y / Math.sqrt(x * x + y * y); + var oy = x === 0 && y === 0 ? 0 : -x / Math.sqrt(x * x + y * y); + x += + this.p.v[0]; + y += + this.p.v[1]; + this.v.setTripleAt(x, y, x - ox * perimSegment * roundness * dir, y - oy * perimSegment * roundness * dir, x + ox * perimSegment * roundness * dir, y + oy * perimSegment * roundness * dir, i, true); + + /*this.v.v[i] = [x,y]; + this.v.i[i] = [x+ox*perimSegment*roundness*dir,y+oy*perimSegment*roundness*dir]; + this.v.o[i] = [x-ox*perimSegment*roundness*dir,y-oy*perimSegment*roundness*dir]; + this.v._length = numPts;*/ + longFlag = !longFlag; + currentAng += angle * dir; + } + }, + convertPolygonToPath: function () { + var numPts = Math.floor(this.pt.v); + var angle = Math.PI * 2 / numPts; + var rad = this.or.v; + var roundness = this.os.v; + var perimSegment = 2 * Math.PI * rad / (numPts * 4); + var i, currentAng = -Math.PI / 2; + var dir = this.data.d === 3 ? -1 : 1; + currentAng += this.r.v; + this.v._length = 0; + for (i = 0; i < numPts; i += 1) { + var x = rad * Math.cos(currentAng); + var y = rad * Math.sin(currentAng); + var ox = x === 0 && y === 0 ? 0 : y / Math.sqrt(x * x + y * y); + var oy = x === 0 && y === 0 ? 0 : -x / Math.sqrt(x * x + y * y); + x += + this.p.v[0]; + y += + this.p.v[1]; + this.v.setTripleAt(x, y, x - ox * perimSegment * roundness * dir, y - oy * perimSegment * roundness * dir, x + ox * perimSegment * roundness * dir, y + oy * perimSegment * roundness * dir, i, true); + currentAng += angle * dir; + } + this.paths.length = 0; + this.paths[0] = this.v; + } + + } + extendPrototype([DynamicPropertyContainer], StarShapeProperty); + + return StarShapeProperty; + }()); + + var RectShapeProperty = (function () { + + function RectShapeProperty(elem, data) { + this.v = shape_pool.newElement(); + this.v.c = true; + this.localShapeCollection = shapeCollection_pool.newShapeCollection(); + this.localShapeCollection.addShape(this.v); + this.paths = this.localShapeCollection; + this.elem = elem; + this.comp = elem.comp; + this.frameId = -1; + this.d = data.d; + this.initDynamicPropertyContainer(elem); + this.p = PropertyFactory.getProp(elem, data.p, 1, 0, this); + this.s = PropertyFactory.getProp(elem, data.s, 1, 0, this); + this.r = PropertyFactory.getProp(elem, data.r, 0, 0, this); + if (this.dynamicProperties.length) { + this.k = true; + } else { + this.k = false; + this.convertRectToPath(); + } + }; + + RectShapeProperty.prototype = { + convertRectToPath: function () { + var p0 = this.p.v[0], p1 = this.p.v[1], v0 = this.s.v[0] / 2, v1 = this.s.v[1] / 2; + var round = bm_min(v0, v1, this.r.v); + var cPoint = round * (1 - roundCorner); + this.v._length = 0; + + if (this.d === 2 || this.d === 1) { + this.v.setTripleAt(p0 + v0, p1 - v1 + round, p0 + v0, p1 - v1 + round, p0 + v0, p1 - v1 + cPoint, 0, true); + this.v.setTripleAt(p0 + v0, p1 + v1 - round, p0 + v0, p1 + v1 - cPoint, p0 + v0, p1 + v1 - round, 1, true); + if (round !== 0) { + this.v.setTripleAt(p0 + v0 - round, p1 + v1, p0 + v0 - round, p1 + v1, p0 + v0 - cPoint, p1 + v1, 2, true); + this.v.setTripleAt(p0 - v0 + round, p1 + v1, p0 - v0 + cPoint, p1 + v1, p0 - v0 + round, p1 + v1, 3, true); + this.v.setTripleAt(p0 - v0, p1 + v1 - round, p0 - v0, p1 + v1 - round, p0 - v0, p1 + v1 - cPoint, 4, true); + this.v.setTripleAt(p0 - v0, p1 - v1 + round, p0 - v0, p1 - v1 + cPoint, p0 - v0, p1 - v1 + round, 5, true); + this.v.setTripleAt(p0 - v0 + round, p1 - v1, p0 - v0 + round, p1 - v1, p0 - v0 + cPoint, p1 - v1, 6, true); + this.v.setTripleAt(p0 + v0 - round, p1 - v1, p0 + v0 - cPoint, p1 - v1, p0 + v0 - round, p1 - v1, 7, true); + } else { + this.v.setTripleAt(p0 - v0, p1 + v1, p0 - v0 + cPoint, p1 + v1, p0 - v0, p1 + v1, 2); + this.v.setTripleAt(p0 - v0, p1 - v1, p0 - v0, p1 - v1 + cPoint, p0 - v0, p1 - v1, 3); + } + } else { + this.v.setTripleAt(p0 + v0, p1 - v1 + round, p0 + v0, p1 - v1 + cPoint, p0 + v0, p1 - v1 + round, 0, true); + if (round !== 0) { + this.v.setTripleAt(p0 + v0 - round, p1 - v1, p0 + v0 - round, p1 - v1, p0 + v0 - cPoint, p1 - v1, 1, true); + this.v.setTripleAt(p0 - v0 + round, p1 - v1, p0 - v0 + cPoint, p1 - v1, p0 - v0 + round, p1 - v1, 2, true); + this.v.setTripleAt(p0 - v0, p1 - v1 + round, p0 - v0, p1 - v1 + round, p0 - v0, p1 - v1 + cPoint, 3, true); + this.v.setTripleAt(p0 - v0, p1 + v1 - round, p0 - v0, p1 + v1 - cPoint, p0 - v0, p1 + v1 - round, 4, true); + this.v.setTripleAt(p0 - v0 + round, p1 + v1, p0 - v0 + round, p1 + v1, p0 - v0 + cPoint, p1 + v1, 5, true); + this.v.setTripleAt(p0 + v0 - round, p1 + v1, p0 + v0 - cPoint, p1 + v1, p0 + v0 - round, p1 + v1, 6, true); + this.v.setTripleAt(p0 + v0, p1 + v1 - round, p0 + v0, p1 + v1 - round, p0 + v0, p1 + v1 - cPoint, 7, true); + } else { + this.v.setTripleAt(p0 - v0, p1 - v1, p0 - v0 + cPoint, p1 - v1, p0 - v0, p1 - v1, 1, true); + this.v.setTripleAt(p0 - v0, p1 + v1, p0 - v0, p1 + v1 - cPoint, p0 - v0, p1 + v1, 2, true); + this.v.setTripleAt(p0 + v0, p1 + v1, p0 + v0 - cPoint, p1 + v1, p0 + v0, p1 + v1, 3, true); + + } + } + }, + getValue: function (frameNum) { + if (this.elem.globalData.frameId === this.frameId) { + return; + } + this.frameId = this.elem.globalData.frameId; + this.iterateDynamicProperties(); + if (this._mdf) { + this.convertRectToPath(); + } + + }, + reset: resetShape + } + extendPrototype([DynamicPropertyContainer], RectShapeProperty); + + return RectShapeProperty; + }()); + + function getShapeProp(elem, data, type) { + var prop; + if (type === 3 || type === 4) { + var dataProp = type === 3 ? data.pt : data.ks; + var keys = dataProp.k; + if (keys.length) { + prop = new KeyframedShapeProperty(elem, data, type); + } else { + prop = new ShapeProperty(elem, data, type); + } + } else if (type === 5) { + prop = new RectShapeProperty(elem, data); + } else if (type === 6) { + prop = new EllShapeProperty(elem, data); + } else if (type === 7) { + prop = new StarShapeProperty(elem, data); + } + if (prop.k) { + elem.addDynamicProperty(prop); + } + return prop; + } + + function getConstructorFunction() { + return ShapeProperty; + } + + function getKeyframedConstructorFunction() { + return KeyframedShapeProperty; + } + + var ob = {}; + ob.getShapeProp = getShapeProp; + ob.getConstructorFunction = getConstructorFunction; + ob.getKeyframedConstructorFunction = getKeyframedConstructorFunction; + return ob; + }()); + var ShapeModifiers = (function () { + var ob = {}; + var modifiers = {}; + ob.registerModifier = registerModifier; + ob.getModifier = getModifier; + + function registerModifier(nm, factory) { + if (!modifiers[nm]) { + modifiers[nm] = factory; + } + } + + function getModifier(nm, elem, data) { + return new modifiers[nm](elem, data); + } + + return ob; + }()); + + function ShapeModifier() { } + ShapeModifier.prototype.initModifierProperties = function () { }; + ShapeModifier.prototype.addShapeToModifier = function () { }; + ShapeModifier.prototype.addShape = function (data) { + if (!this.closed) { + // Adding shape to dynamic properties. It covers the case where a shape has no effects applied, to reset it's _mdf state on every tick. + data.sh.container.addDynamicProperty(data.sh); + var shapeData = { shape: data.sh, data: data, localShapeCollection: shapeCollection_pool.newShapeCollection() }; + this.shapes.push(shapeData); + this.addShapeToModifier(shapeData); + if (this._isAnimated) { + data.setAsAnimated(); + } + } + }; + ShapeModifier.prototype.init = function (elem, data) { + this.shapes = []; + this.elem = elem; + this.initDynamicPropertyContainer(elem); + this.initModifierProperties(elem, data); + this.frameId = initialDefaultFrame; + this.closed = false; + this.k = false; + if (this.dynamicProperties.length) { + this.k = true; + } else { + this.getValue(true); + } + }; + ShapeModifier.prototype.processKeys = function () { + if (this.elem.globalData.frameId === this.frameId) { + return; + } + this.frameId = this.elem.globalData.frameId; + this.iterateDynamicProperties(); + }; + + extendPrototype([DynamicPropertyContainer], ShapeModifier); + function TrimModifier() { + } + extendPrototype([ShapeModifier], TrimModifier); + TrimModifier.prototype.initModifierProperties = function (elem, data) { + this.s = PropertyFactory.getProp(elem, data.s, 0, 0.01, this); + this.e = PropertyFactory.getProp(elem, data.e, 0, 0.01, this); + this.o = PropertyFactory.getProp(elem, data.o, 0, 0, this); + this.sValue = 0; + this.eValue = 0; + this.getValue = this.processKeys; + this.m = data.m; + this._isAnimated = !!this.s.effectsSequence.length || !!this.e.effectsSequence.length || !!this.o.effectsSequence.length; + }; + + TrimModifier.prototype.addShapeToModifier = function (shapeData) { + shapeData.pathsData = []; + }; + + TrimModifier.prototype.calculateShapeEdges = function (s, e, shapeLength, addedLength, totalModifierLength) { + var segments = []; + if (e <= 1) { + segments.push({ + s: s, + e: e + }); + } else if (s >= 1) { + segments.push({ + s: s - 1, + e: e - 1 + }); + } else { + segments.push({ + s: s, + e: 1 + }); + segments.push({ + s: 0, + e: e - 1 + }); + } + var shapeSegments = []; + var i, len = segments.length, segmentOb; + for (i = 0; i < len; i += 1) { + segmentOb = segments[i]; + if (segmentOb.e * totalModifierLength < addedLength || segmentOb.s * totalModifierLength > addedLength + shapeLength) { + + } else { + var shapeS, shapeE; + if (segmentOb.s * totalModifierLength <= addedLength) { + shapeS = 0; + } else { + shapeS = (segmentOb.s * totalModifierLength - addedLength) / shapeLength; + } + if (segmentOb.e * totalModifierLength >= addedLength + shapeLength) { + shapeE = 1; + } else { + shapeE = ((segmentOb.e * totalModifierLength - addedLength) / shapeLength); + } + shapeSegments.push([shapeS, shapeE]); + } + } + if (!shapeSegments.length) { + shapeSegments.push([0, 0]); + } + return shapeSegments; + }; + + TrimModifier.prototype.releasePathsData = function (pathsData) { + var i, len = pathsData.length; + for (i = 0; i < len; i += 1) { + segments_length_pool.release(pathsData[i]); + } + pathsData.length = 0; + return pathsData; + }; + + TrimModifier.prototype.processShapes = function (_isFirstFrame) { + var s, e; + if (this._mdf || _isFirstFrame) { + var o = (this.o.v % 360) / 360; + if (o < 0) { + o += 1; + } + s = (this.s.v > 1 ? 1 : this.s.v < 0 ? 0 : this.s.v) + o; + e = (this.e.v > 1 ? 1 : this.e.v < 0 ? 0 : this.e.v) + o; + if (s === e) { + + } + if (s > e) { + var _s = s; + s = e; + e = _s; + } + s = Math.round(s * 10000) * 0.0001; + e = Math.round(e * 10000) * 0.0001; + this.sValue = s; + this.eValue = e; + } else { + s = this.sValue; + e = this.eValue; + } + var shapePaths; + var i, len = this.shapes.length, j, jLen; + var pathsData, pathData, totalShapeLength, totalModifierLength = 0; + + if (e === s) { + for (i = 0; i < len; i += 1) { + this.shapes[i].localShapeCollection.releaseShapes(); + this.shapes[i].shape._mdf = true; + this.shapes[i].shape.paths = this.shapes[i].localShapeCollection; + } + } else if (!((e === 1 && s === 0) || (e === 0 && s === 1))) { + var segments = [], shapeData, localShapeCollection; + for (i = 0; i < len; i += 1) { + shapeData = this.shapes[i]; + // if shape hasn't changed and trim properties haven't changed, cached previous path can be used + if (!shapeData.shape._mdf && !this._mdf && !_isFirstFrame && this.m !== 2) { + shapeData.shape.paths = shapeData.localShapeCollection; + } else { + shapePaths = shapeData.shape.paths; + jLen = shapePaths._length; + totalShapeLength = 0; + if (!shapeData.shape._mdf && shapeData.pathsData.length) { + totalShapeLength = shapeData.totalShapeLength; + } else { + pathsData = this.releasePathsData(shapeData.pathsData); + for (j = 0; j < jLen; j += 1) { + pathData = bez.getSegmentsLength(shapePaths.shapes[j]); + pathsData.push(pathData); + totalShapeLength += pathData.totalLength; + } + shapeData.totalShapeLength = totalShapeLength; + shapeData.pathsData = pathsData; + } + + totalModifierLength += totalShapeLength; + shapeData.shape._mdf = true; + } + } + var shapeS = s, shapeE = e, addedLength = 0, edges; + for (i = len - 1; i >= 0; i -= 1) { + shapeData = this.shapes[i]; + if (shapeData.shape._mdf) { + localShapeCollection = shapeData.localShapeCollection; + localShapeCollection.releaseShapes(); + //if m === 2 means paths are trimmed individually so edges need to be found for this specific shape relative to whoel group + if (this.m === 2 && len > 1) { + edges = this.calculateShapeEdges(s, e, shapeData.totalShapeLength, addedLength, totalModifierLength); + addedLength += shapeData.totalShapeLength; + } else { + edges = [[shapeS, shapeE]]; + } + jLen = edges.length; + for (j = 0; j < jLen; j += 1) { + shapeS = edges[j][0]; + shapeE = edges[j][1]; + segments.length = 0; + if (shapeE <= 1) { + segments.push({ + s: shapeData.totalShapeLength * shapeS, + e: shapeData.totalShapeLength * shapeE + }); + } else if (shapeS >= 1) { + segments.push({ + s: shapeData.totalShapeLength * (shapeS - 1), + e: shapeData.totalShapeLength * (shapeE - 1) + }); + } else { + segments.push({ + s: shapeData.totalShapeLength * shapeS, + e: shapeData.totalShapeLength + }); + segments.push({ + s: 0, + e: shapeData.totalShapeLength * (shapeE - 1) + }); + } + var newShapesData = this.addShapes(shapeData, segments[0]); + if (segments[0].s !== segments[0].e) { + if (segments.length > 1) { + var lastShapeInCollection = shapeData.shape.paths.shapes[shapeData.shape.paths._length - 1]; + if (lastShapeInCollection.c) { + var lastShape = newShapesData.pop(); + this.addPaths(newShapesData, localShapeCollection); + newShapesData = this.addShapes(shapeData, segments[1], lastShape); + } else { + this.addPaths(newShapesData, localShapeCollection); + newShapesData = this.addShapes(shapeData, segments[1]); + } + } + this.addPaths(newShapesData, localShapeCollection); + } + + } + shapeData.shape.paths = localShapeCollection; + } + } + } else if (this._mdf) { + for (i = 0; i < len; i += 1) { + //Releasign Trim Cached paths data when no trim applied in case shapes are modified inbetween. + //Don't remove this even if it's losing cached info. + this.shapes[i].pathsData.length = 0; + this.shapes[i].shape._mdf = true; + } + } + }; + + TrimModifier.prototype.addPaths = function (newPaths, localShapeCollection) { + var i, len = newPaths.length; + for (i = 0; i < len; i += 1) { + localShapeCollection.addShape(newPaths[i]); + } + }; + + TrimModifier.prototype.addSegment = function (pt1, pt2, pt3, pt4, shapePath, pos, newShape) { + shapePath.setXYAt(pt2[0], pt2[1], 'o', pos); + shapePath.setXYAt(pt3[0], pt3[1], 'i', pos + 1); + if (newShape) { + shapePath.setXYAt(pt1[0], pt1[1], 'v', pos); + } + shapePath.setXYAt(pt4[0], pt4[1], 'v', pos + 1); + }; + + TrimModifier.prototype.addSegmentFromArray = function (points, shapePath, pos, newShape) { + shapePath.setXYAt(points[1], points[5], 'o', pos); + shapePath.setXYAt(points[2], points[6], 'i', pos + 1); + if (newShape) { + shapePath.setXYAt(points[0], points[4], 'v', pos); + } + shapePath.setXYAt(points[3], points[7], 'v', pos + 1); + }; + + TrimModifier.prototype.addShapes = function (shapeData, shapeSegment, shapePath) { + var pathsData = shapeData.pathsData; + var shapePaths = shapeData.shape.paths.shapes; + var i, len = shapeData.shape.paths._length, j, jLen; + var addedLength = 0; + var currentLengthData, segmentCount; + var lengths; + var segment; + var shapes = []; + var initPos; + var newShape = true; + if (!shapePath) { + shapePath = shape_pool.newElement(); + segmentCount = 0; + initPos = 0; + } else { + segmentCount = shapePath._length; + initPos = shapePath._length; + } + shapes.push(shapePath); + for (i = 0; i < len; i += 1) { + lengths = pathsData[i].lengths; + shapePath.c = shapePaths[i].c; + jLen = shapePaths[i].c ? lengths.length : lengths.length + 1; + for (j = 1; j < jLen; j += 1) { + currentLengthData = lengths[j - 1]; + if (addedLength + currentLengthData.addedLength < shapeSegment.s) { + addedLength += currentLengthData.addedLength; + shapePath.c = false; + } else if (addedLength > shapeSegment.e) { + shapePath.c = false; + break; + } else { + if (shapeSegment.s <= addedLength && shapeSegment.e >= addedLength + currentLengthData.addedLength) { + this.addSegment(shapePaths[i].v[j - 1], shapePaths[i].o[j - 1], shapePaths[i].i[j], shapePaths[i].v[j], shapePath, segmentCount, newShape); + newShape = false; + } else { + segment = bez.getNewSegment(shapePaths[i].v[j - 1], shapePaths[i].v[j], shapePaths[i].o[j - 1], shapePaths[i].i[j], (shapeSegment.s - addedLength) / currentLengthData.addedLength, (shapeSegment.e - addedLength) / currentLengthData.addedLength, lengths[j - 1]); + this.addSegmentFromArray(segment, shapePath, segmentCount, newShape); + // this.addSegment(segment.pt1, segment.pt3, segment.pt4, segment.pt2, shapePath, segmentCount, newShape); + newShape = false; + shapePath.c = false; + } + addedLength += currentLengthData.addedLength; + segmentCount += 1; + } + } + if (shapePaths[i].c && lengths.length) { + currentLengthData = lengths[j - 1]; + if (addedLength <= shapeSegment.e) { + var segmentLength = lengths[j - 1].addedLength; + if (shapeSegment.s <= addedLength && shapeSegment.e >= addedLength + segmentLength) { + this.addSegment(shapePaths[i].v[j - 1], shapePaths[i].o[j - 1], shapePaths[i].i[0], shapePaths[i].v[0], shapePath, segmentCount, newShape); + newShape = false; + } else { + segment = bez.getNewSegment(shapePaths[i].v[j - 1], shapePaths[i].v[0], shapePaths[i].o[j - 1], shapePaths[i].i[0], (shapeSegment.s - addedLength) / segmentLength, (shapeSegment.e - addedLength) / segmentLength, lengths[j - 1]); + this.addSegmentFromArray(segment, shapePath, segmentCount, newShape); + // this.addSegment(segment.pt1, segment.pt3, segment.pt4, segment.pt2, shapePath, segmentCount, newShape); + newShape = false; + shapePath.c = false; + } + } else { + shapePath.c = false; + } + addedLength += currentLengthData.addedLength; + segmentCount += 1; + } + if (shapePath._length) { + shapePath.setXYAt(shapePath.v[initPos][0], shapePath.v[initPos][1], 'i', initPos); + shapePath.setXYAt(shapePath.v[shapePath._length - 1][0], shapePath.v[shapePath._length - 1][1], 'o', shapePath._length - 1); + } + if (addedLength > shapeSegment.e) { + break; + } + if (i < len - 1) { + shapePath = shape_pool.newElement(); + newShape = true; + shapes.push(shapePath); + segmentCount = 0; + } + } + return shapes; + }; + + + ShapeModifiers.registerModifier('tm', TrimModifier); + function RoundCornersModifier() { } + extendPrototype([ShapeModifier], RoundCornersModifier); + RoundCornersModifier.prototype.initModifierProperties = function (elem, data) { + this.getValue = this.processKeys; + this.rd = PropertyFactory.getProp(elem, data.r, 0, null, this); + this._isAnimated = !!this.rd.effectsSequence.length; + }; + + RoundCornersModifier.prototype.processPath = function (path, round) { + var cloned_path = shape_pool.newElement(); + cloned_path.c = path.c; + var i, len = path._length; + var currentV, currentI, currentO, closerV, newV, newO, newI, distance, newPosPerc, index = 0; + var vX, vY, oX, oY, iX, iY; + for (i = 0; i < len; i += 1) { + currentV = path.v[i]; + currentO = path.o[i]; + currentI = path.i[i]; + if (currentV[0] === currentO[0] && currentV[1] === currentO[1] && currentV[0] === currentI[0] && currentV[1] === currentI[1]) { + if ((i === 0 || i === len - 1) && !path.c) { + cloned_path.setTripleAt(currentV[0], currentV[1], currentO[0], currentO[1], currentI[0], currentI[1], index); + /*cloned_path.v[index] = currentV; + cloned_path.o[index] = currentO; + cloned_path.i[index] = currentI;*/ + index += 1; + } else { + if (i === 0) { + closerV = path.v[len - 1]; + } else { + closerV = path.v[i - 1]; + } + distance = Math.sqrt(Math.pow(currentV[0] - closerV[0], 2) + Math.pow(currentV[1] - closerV[1], 2)); + newPosPerc = distance ? Math.min(distance / 2, round) / distance : 0; + vX = iX = currentV[0] + (closerV[0] - currentV[0]) * newPosPerc; + vY = iY = currentV[1] - (currentV[1] - closerV[1]) * newPosPerc; + oX = vX - (vX - currentV[0]) * roundCorner; + oY = vY - (vY - currentV[1]) * roundCorner; + cloned_path.setTripleAt(vX, vY, oX, oY, iX, iY, index); + index += 1; + + if (i === len - 1) { + closerV = path.v[0]; + } else { + closerV = path.v[i + 1]; + } + distance = Math.sqrt(Math.pow(currentV[0] - closerV[0], 2) + Math.pow(currentV[1] - closerV[1], 2)); + newPosPerc = distance ? Math.min(distance / 2, round) / distance : 0; + vX = oX = currentV[0] + (closerV[0] - currentV[0]) * newPosPerc; + vY = oY = currentV[1] + (closerV[1] - currentV[1]) * newPosPerc; + iX = vX - (vX - currentV[0]) * roundCorner; + iY = vY - (vY - currentV[1]) * roundCorner; + cloned_path.setTripleAt(vX, vY, oX, oY, iX, iY, index); + index += 1; + } + } else { + cloned_path.setTripleAt(path.v[i][0], path.v[i][1], path.o[i][0], path.o[i][1], path.i[i][0], path.i[i][1], index); + index += 1; + } + } + return cloned_path; + }; + + RoundCornersModifier.prototype.processShapes = function (_isFirstFrame) { + var shapePaths; + var i, len = this.shapes.length; + var j, jLen; + var rd = this.rd.v; + + if (rd !== 0) { + var shapeData, newPaths, localShapeCollection; + for (i = 0; i < len; i += 1) { + shapeData = this.shapes[i]; + newPaths = shapeData.shape.paths; + localShapeCollection = shapeData.localShapeCollection; + if (!(!shapeData.shape._mdf && !this._mdf && !_isFirstFrame)) { + localShapeCollection.releaseShapes(); + shapeData.shape._mdf = true; + shapePaths = shapeData.shape.paths.shapes; + jLen = shapeData.shape.paths._length; + for (j = 0; j < jLen; j += 1) { + localShapeCollection.addShape(this.processPath(shapePaths[j], rd)); + } + } + shapeData.shape.paths = shapeData.localShapeCollection; + } + + } + if (!this.dynamicProperties.length) { + this._mdf = false; + } + }; + + ShapeModifiers.registerModifier('rd', RoundCornersModifier); + function RepeaterModifier() { } + extendPrototype([ShapeModifier], RepeaterModifier); + + RepeaterModifier.prototype.initModifierProperties = function (elem, data) { + this.getValue = this.processKeys; + this.c = PropertyFactory.getProp(elem, data.c, 0, null, this); + this.o = PropertyFactory.getProp(elem, data.o, 0, null, this); + this.tr = TransformPropertyFactory.getTransformProperty(elem, data.tr, this); + this.so = PropertyFactory.getProp(elem, data.tr.so, 0, 0.01, this); + this.eo = PropertyFactory.getProp(elem, data.tr.eo, 0, 0.01, this); + this.data = data; + if (!this.dynamicProperties.length) { + this.getValue(true); + } + this._isAnimated = !!this.dynamicProperties.length; + this.pMatrix = new Matrix(); + this.rMatrix = new Matrix(); + this.sMatrix = new Matrix(); + this.tMatrix = new Matrix(); + this.matrix = new Matrix(); + }; + + RepeaterModifier.prototype.applyTransforms = function (pMatrix, rMatrix, sMatrix, transform, perc, inv) { + var dir = inv ? -1 : 1; + var scaleX = transform.s.v[0] + (1 - transform.s.v[0]) * (1 - perc); + var scaleY = transform.s.v[1] + (1 - transform.s.v[1]) * (1 - perc); + pMatrix.translate(transform.p.v[0] * dir * perc, transform.p.v[1] * dir * perc, transform.p.v[2]); + rMatrix.translate(-transform.a.v[0], -transform.a.v[1], transform.a.v[2]); + rMatrix.rotate(-transform.r.v * dir * perc); + rMatrix.translate(transform.a.v[0], transform.a.v[1], transform.a.v[2]); + sMatrix.translate(-transform.a.v[0], -transform.a.v[1], transform.a.v[2]); + sMatrix.scale(inv ? 1 / scaleX : scaleX, inv ? 1 / scaleY : scaleY); + sMatrix.translate(transform.a.v[0], transform.a.v[1], transform.a.v[2]); + }; + + RepeaterModifier.prototype.init = function (elem, arr, pos, elemsData) { + this.elem = elem; + this.arr = arr; + this.pos = pos; + this.elemsData = elemsData; + this._currentCopies = 0; + this._elements = []; + this._groups = []; + this.frameId = -1; + this.initDynamicPropertyContainer(elem); + this.initModifierProperties(elem, arr[pos]); + var cont = 0; + while (pos > 0) { + pos -= 1; + //this._elements.unshift(arr.splice(pos,1)[0]); + this._elements.unshift(arr[pos]); + cont += 1; + } + if (this.dynamicProperties.length) { + this.k = true; + } else { + this.getValue(true); + } + }; + + RepeaterModifier.prototype.resetElements = function (elements) { + var i, len = elements.length; + for (i = 0; i < len; i += 1) { + elements[i]._processed = false; + if (elements[i].ty === 'gr') { + this.resetElements(elements[i].it); + } + } + }; + + RepeaterModifier.prototype.cloneElements = function (elements) { + var i, len = elements.length; + var newElements = JSON.parse(JSON.stringify(elements)); + this.resetElements(newElements); + return newElements; + }; + + RepeaterModifier.prototype.changeGroupRender = function (elements, renderFlag) { + var i, len = elements.length; + for (i = 0; i < len; i += 1) { + elements[i]._render = renderFlag; + if (elements[i].ty === 'gr') { + this.changeGroupRender(elements[i].it, renderFlag); + } + } + }; + + RepeaterModifier.prototype.processShapes = function (_isFirstFrame) { + var items, itemsTransform, i, dir, cont; + if (this._mdf || _isFirstFrame) { + var copies = Math.ceil(this.c.v); + if (this._groups.length < copies) { + while (this._groups.length < copies) { + var group = { + it: this.cloneElements(this._elements), + ty: 'gr' + }; + group.it.push({ "a": { "a": 0, "ix": 1, "k": [0, 0] }, "nm": "Transform", "o": { "a": 0, "ix": 7, "k": 100 }, "p": { "a": 0, "ix": 2, "k": [0, 0] }, "r": { "a": 1, "ix": 6, "k": [{ s: 0, e: 0, t: 0 }, { s: 0, e: 0, t: 1 }] }, "s": { "a": 0, "ix": 3, "k": [100, 100] }, "sa": { "a": 0, "ix": 5, "k": 0 }, "sk": { "a": 0, "ix": 4, "k": 0 }, "ty": "tr" }); + + this.arr.splice(0, 0, group); + this._groups.splice(0, 0, group); + this._currentCopies += 1; + } + this.elem.reloadShapes(); + } + cont = 0; + var renderFlag; + for (i = 0; i <= this._groups.length - 1; i += 1) { + renderFlag = cont < copies; + this._groups[i]._render = renderFlag; + this.changeGroupRender(this._groups[i].it, renderFlag); + cont += 1; + } + + this._currentCopies = copies; + //// + + var offset = this.o.v; + var offsetModulo = offset % 1; + var roundOffset = offset > 0 ? Math.floor(offset) : Math.ceil(offset); + var k; + var tMat = this.tr.v.props; + var pProps = this.pMatrix.props; + var rProps = this.rMatrix.props; + var sProps = this.sMatrix.props; + this.pMatrix.reset(); + this.rMatrix.reset(); + this.sMatrix.reset(); + this.tMatrix.reset(); + this.matrix.reset(); + var iteration = 0; + + if (offset > 0) { + while (iteration < roundOffset) { + this.applyTransforms(this.pMatrix, this.rMatrix, this.sMatrix, this.tr, 1, false); + iteration += 1; + } + if (offsetModulo) { + this.applyTransforms(this.pMatrix, this.rMatrix, this.sMatrix, this.tr, offsetModulo, false); + iteration += offsetModulo; + } + } else if (offset < 0) { + while (iteration > roundOffset) { + this.applyTransforms(this.pMatrix, this.rMatrix, this.sMatrix, this.tr, 1, true); + iteration -= 1; + } + if (offsetModulo) { + this.applyTransforms(this.pMatrix, this.rMatrix, this.sMatrix, this.tr, - offsetModulo, true); + iteration -= offsetModulo; + } + } + i = this.data.m === 1 ? 0 : this._currentCopies - 1; + dir = this.data.m === 1 ? 1 : -1; + cont = this._currentCopies; + var j, jLen; + while (cont) { + items = this.elemsData[i].it; + itemsTransform = items[items.length - 1].transform.mProps.v.props; + jLen = itemsTransform.length; + items[items.length - 1].transform.mProps._mdf = true; + items[items.length - 1].transform.op._mdf = true; + items[items.length - 1].transform.op.v = this.so.v + (this.eo.v - this.so.v) * (i / (this._currentCopies - 1)); + if (iteration !== 0) { + if ((i !== 0 && dir === 1) || (i !== this._currentCopies - 1 && dir === -1)) { + this.applyTransforms(this.pMatrix, this.rMatrix, this.sMatrix, this.tr, 1, false); + } + this.matrix.transform(rProps[0], rProps[1], rProps[2], rProps[3], rProps[4], rProps[5], rProps[6], rProps[7], rProps[8], rProps[9], rProps[10], rProps[11], rProps[12], rProps[13], rProps[14], rProps[15]); + this.matrix.transform(sProps[0], sProps[1], sProps[2], sProps[3], sProps[4], sProps[5], sProps[6], sProps[7], sProps[8], sProps[9], sProps[10], sProps[11], sProps[12], sProps[13], sProps[14], sProps[15]); + this.matrix.transform(pProps[0], pProps[1], pProps[2], pProps[3], pProps[4], pProps[5], pProps[6], pProps[7], pProps[8], pProps[9], pProps[10], pProps[11], pProps[12], pProps[13], pProps[14], pProps[15]); + + for (j = 0; j < jLen; j += 1) { + itemsTransform[j] = this.matrix.props[j]; + } + this.matrix.reset(); + } else { + this.matrix.reset(); + for (j = 0; j < jLen; j += 1) { + itemsTransform[j] = this.matrix.props[j]; + } + } + iteration += 1; + cont -= 1; + i += dir; + } + } else { + cont = this._currentCopies; + i = 0; + dir = 1; + while (cont) { + items = this.elemsData[i].it; + itemsTransform = items[items.length - 1].transform.mProps.v.props; + items[items.length - 1].transform.mProps._mdf = false; + items[items.length - 1].transform.op._mdf = false; + cont -= 1; + i += dir; + } + } + }; + + RepeaterModifier.prototype.addShape = function () { }; + + ShapeModifiers.registerModifier('rp', RepeaterModifier); + function ShapeCollection() { + this._length = 0; + this._maxLength = 4; + this.shapes = createSizedArray(this._maxLength); + } + + ShapeCollection.prototype.addShape = function (shapeData) { + if (this._length === this._maxLength) { + this.shapes = this.shapes.concat(createSizedArray(this._maxLength)); + this._maxLength *= 2; + } + this.shapes[this._length] = shapeData; + this._length += 1; + }; + + ShapeCollection.prototype.releaseShapes = function () { + var i; + for (i = 0; i < this._length; i += 1) { + shape_pool.release(this.shapes[i]); + } + this._length = 0; + }; + function DashProperty(elem, data, renderer, container) { + this.elem = elem; + this.frameId = -1; + this.dataProps = createSizedArray(data.length); + this.renderer = renderer; + this.k = false; + this.dashStr = ''; + this.dashArray = createTypedArray('float32', data.length ? data.length - 1 : 0); + this.dashoffset = createTypedArray('float32', 1); + this.initDynamicPropertyContainer(container); + var i, len = data.length || 0, prop; + for (i = 0; i < len; i += 1) { + prop = PropertyFactory.getProp(elem, data[i].v, 0, 0, this); + this.k = prop.k || this.k; + this.dataProps[i] = { n: data[i].n, p: prop }; + } + if (!this.k) { + this.getValue(true); + } + this._isAnimated = this.k; + } + + DashProperty.prototype.getValue = function (forceRender) { + if (this.elem.globalData.frameId === this.frameId && !forceRender) { + return; + } + this.frameId = this.elem.globalData.frameId; + this.iterateDynamicProperties(); + this._mdf = this._mdf || forceRender; + if (this._mdf) { + var i = 0, len = this.dataProps.length; + if (this.renderer === 'svg') { + this.dashStr = ''; + } + for (i = 0; i < len; i += 1) { + if (this.dataProps[i].n != 'o') { + if (this.renderer === 'svg') { + this.dashStr += ' ' + this.dataProps[i].p.v; + } else { + this.dashArray[i] = this.dataProps[i].p.v; + } + } else { + this.dashoffset[0] = this.dataProps[i].p.v; + } + } + } + }; + extendPrototype([DynamicPropertyContainer], DashProperty); + function GradientProperty(elem, data, container) { + this.data = data; + this.c = createTypedArray('uint8c', data.p * 4); + var cLength = data.k.k[0].s ? (data.k.k[0].s.length - data.p * 4) : data.k.k.length - data.p * 4; + this.o = createTypedArray('float32', cLength); + this._cmdf = false; + this._omdf = false; + this._collapsable = this.checkCollapsable(); + this._hasOpacity = cLength; + this.initDynamicPropertyContainer(container); + this.prop = PropertyFactory.getProp(elem, data.k, 1, null, this); + this.k = this.prop.k; + this.getValue(true); + } + + GradientProperty.prototype.comparePoints = function (values, points) { + var i = 0, len = this.o.length / 2, diff; + while (i < len) { + diff = Math.abs(values[i * 4] - values[points * 4 + i * 2]); + if (diff > 0.01) { + return false; + } + i += 1; + } + return true; + }; + + GradientProperty.prototype.checkCollapsable = function () { + if (this.o.length / 2 !== this.c.length / 4) { + return false; + } + if (this.data.k.k[0].s) { + var i = 0, len = this.data.k.k.length; + while (i < len) { + if (!this.comparePoints(this.data.k.k[i].s, this.data.p)) { + return false; + } + i += 1; + } + } else if (!this.comparePoints(this.data.k.k, this.data.p)) { + return false; + } + return true; + }; + + GradientProperty.prototype.getValue = function (forceRender) { + this.prop.getValue(); + this._mdf = false; + this._cmdf = false; + this._omdf = false; + if (this.prop._mdf || forceRender) { + var i, len = this.data.p * 4; + var mult, val; + for (i = 0; i < len; i += 1) { + mult = i % 4 === 0 ? 100 : 255; + val = Math.round(this.prop.v[i] * mult); + if (this.c[i] !== val) { + this.c[i] = val; + this._cmdf = !forceRender; + } + } + if (this.o.length) { + len = this.prop.v.length; + for (i = this.data.p * 4; i < len; i += 1) { + mult = i % 2 === 0 ? 100 : 1; + val = i % 2 === 0 ? Math.round(this.prop.v[i] * 100) : this.prop.v[i]; + if (this.o[i - this.data.p * 4] !== val) { + this.o[i - this.data.p * 4] = val; + this._omdf = !forceRender; + } + } + } + this._mdf = !forceRender; + } + }; + + extendPrototype([DynamicPropertyContainer], GradientProperty); + var buildShapeString = function (pathNodes, length, closed, mat) { + if (length === 0) { + return ''; + } + var _o = pathNodes.o; + var _i = pathNodes.i; + var _v = pathNodes.v; + var i, shapeString = " M" + mat.applyToPointStringified(_v[0][0], _v[0][1]); + for (i = 1; i < length; i += 1) { + shapeString += " C" + mat.applyToPointStringified(_o[i - 1][0], _o[i - 1][1]) + " " + mat.applyToPointStringified(_i[i][0], _i[i][1]) + " " + mat.applyToPointStringified(_v[i][0], _v[i][1]); + } + if (closed && length) { + shapeString += " C" + mat.applyToPointStringified(_o[i - 1][0], _o[i - 1][1]) + " " + mat.applyToPointStringified(_i[0][0], _i[0][1]) + " " + mat.applyToPointStringified(_v[0][0], _v[0][1]); + shapeString += 'z'; + } + return shapeString; + } + var ImagePreloader = (function () { + + var proxyImage = (function () { + var canvas = createTag('canvas'); + canvas.width = 1; + canvas.height = 1; + var ctx = canvas.getContext('2d'); + ctx.fillStyle = 'rgba(0,0,0,0)'; + ctx.fillRect(0, 0, 1, 1); + return canvas; + }()) + + function imageLoaded() { + this.loadedAssets += 1; + if (this.loadedAssets === this.totalImages) { + if (this.imagesLoadedCb) { + this.imagesLoadedCb(null); + } + } + } + + function getAssetsPath(assetData, assetsPath, original_path) { + var path = ''; + if (assetData.e) { + path = assetData.p; + } else if (assetsPath) { + var imagePath = assetData.p; + if (imagePath.indexOf('images/') !== -1) { + imagePath = imagePath.split('/')[1]; + } + path = assetsPath + imagePath; + } else { + path = original_path; + path += assetData.u ? assetData.u : ''; + path += assetData.p; + } + return path; + } + + function createImageData(assetData) { + var path = getAssetsPath(assetData, this.assetsPath, this.path); + var img = createTag('img'); + img.crossOrigin = 'anonymous'; + img.addEventListener('load', this._imageLoaded.bind(this), false); + img.addEventListener('error', function () { + ob.img = proxyImage; + this._imageLoaded(); + }.bind(this), false); + img.src = path; + var ob = { + img: img, + assetData: assetData + } + return ob; + } + + function loadAssets(assets, cb) { + this.imagesLoadedCb = cb; + var i, len = assets.length; + for (i = 0; i < len; i += 1) { + if (!assets[i].layers) { + this.totalImages += 1; + this.images.push(this._createImageData(assets[i])); + } + } + } + + function setPath(path) { + this.path = path || ''; + } + + function setAssetsPath(path) { + this.assetsPath = path || ''; + } + + function getImage(assetData) { + var i = 0, len = this.images.length; + while (i < len) { + if (this.images[i].assetData === assetData) { + return this.images[i].img; + } + i += 1; + } + } + + function destroy() { + this.imagesLoadedCb = null; + this.images.length = 0; + } + + function loaded() { + return this.totalImages === this.loadedAssets; + } + + return function ImagePreloader() { + this.loadAssets = loadAssets; + this.setAssetsPath = setAssetsPath; + this.setPath = setPath; + this.loaded = loaded; + this.destroy = destroy; + this.getImage = getImage; + this._createImageData = createImageData; + this._imageLoaded = imageLoaded; + this.assetsPath = ''; + this.path = ''; + this.totalImages = 0; + this.loadedAssets = 0; + this.imagesLoadedCb = null; + this.images = []; + }; + }()); + var featureSupport = (function () { + var ob = { + maskType: true + }; + if (/MSIE 10/i.test(navigator.userAgent) || /MSIE 9/i.test(navigator.userAgent) || /rv:11.0/i.test(navigator.userAgent) || /Edge\/\d./i.test(navigator.userAgent)) { + ob.maskType = false; + } + return ob; + }()); + var filtersFactory = (function () { + var ob = {}; + ob.createFilter = createFilter; + ob.createAlphaToLuminanceFilter = createAlphaToLuminanceFilter; + + function createFilter(filId) { + var fil = createNS('filter'); + fil.setAttribute('id', filId); + fil.setAttribute('filterUnits', 'objectBoundingBox'); + fil.setAttribute('x', '0%'); + fil.setAttribute('y', '0%'); + fil.setAttribute('width', '100%'); + fil.setAttribute('height', '100%'); + return fil; + } + + function createAlphaToLuminanceFilter() { + var feColorMatrix = createNS('feColorMatrix'); + feColorMatrix.setAttribute('type', 'matrix'); + feColorMatrix.setAttribute('color-interpolation-filters', 'sRGB'); + feColorMatrix.setAttribute('values', '0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 1'); + return feColorMatrix; + } + + return ob; + }()); + var assetLoader = (function () { + + function formatResponse(xhr) { + if (xhr.response && typeof xhr.response === 'object') { + return xhr.response; + } else if (xhr.response && typeof xhr.response === 'string') { + return JSON.parse(xhr.response); + } else if (xhr.responseText) { + return JSON.parse(xhr.responseText); + } + } + + function loadAsset(path, callback, errorCallback) { + var response; + var xhr = new XMLHttpRequest(); + xhr.open('GET', path, true); + // set responseType after calling open or IE will break. + try { + // This crashes on Android WebView prior to KitKat + xhr.responseType = "json"; + } catch (err) { } + xhr.send(); + xhr.onreadystatechange = function () { + if (xhr.readyState == 4) { + if (xhr.status == 200) { + response = formatResponse(xhr); + callback(response); + } else { + try { + response = formatResponse(xhr); + callback(response); + } catch (err) { + if (errorCallback) { + errorCallback(err); + } + } + } + } + }; + } + return { + load: loadAsset + } + }()) + + function TextAnimatorProperty(textData, renderType, elem) { + this._isFirstFrame = true; + this._hasMaskedPath = false; + this._frameId = -1; + this._textData = textData; + this._renderType = renderType; + this._elem = elem; + this._animatorsData = createSizedArray(this._textData.a.length); + this._pathData = {}; + this._moreOptions = { + alignment: {} + }; + this.renderedLetters = []; + this.lettersChangedFlag = false; + this.initDynamicPropertyContainer(elem); + + } + + TextAnimatorProperty.prototype.searchProperties = function () { + var i, len = this._textData.a.length, animatorProps; + var getProp = PropertyFactory.getProp; + for (i = 0; i < len; i += 1) { + animatorProps = this._textData.a[i]; + this._animatorsData[i] = new TextAnimatorDataProperty(this._elem, animatorProps, this); + } + if (this._textData.p && 'm' in this._textData.p) { + this._pathData = { + f: getProp(this._elem, this._textData.p.f, 0, 0, this), + l: getProp(this._elem, this._textData.p.l, 0, 0, this), + r: this._textData.p.r, + m: this._elem.maskManager.getMaskProperty(this._textData.p.m) + }; + this._hasMaskedPath = true; + } else { + this._hasMaskedPath = false; + } + this._moreOptions.alignment = getProp(this._elem, this._textData.m.a, 1, 0, this); + }; + + TextAnimatorProperty.prototype.getMeasures = function (documentData, lettersChangedFlag) { + this.lettersChangedFlag = lettersChangedFlag; + if (!this._mdf && !this._isFirstFrame && !lettersChangedFlag && (!this._hasMaskedPath || !this._pathData.m._mdf)) { + return; + } + this._isFirstFrame = false; + var alignment = this._moreOptions.alignment.v; + var animators = this._animatorsData; + var textData = this._textData; + var matrixHelper = this.mHelper; + var renderType = this._renderType; + var renderedLettersCount = this.renderedLetters.length; + var data = this.data; + var xPos, yPos; + var i, len; + var letters = documentData.l, pathInfo, currentLength, currentPoint, segmentLength, flag, pointInd, segmentInd, prevPoint, points, segments, partialLength, totalLength, perc, tanAngle, mask; + if (this._hasMaskedPath) { + mask = this._pathData.m; + if (!this._pathData.n || this._pathData._mdf) { + var paths = mask.v; + if (this._pathData.r) { + paths = paths.reverse(); + } + // TODO: release bezier data cached from previous pathInfo: this._pathData.pi + pathInfo = { + tLength: 0, + segments: [] + }; + len = paths._length - 1; + var bezierData; + totalLength = 0; + for (i = 0; i < len; i += 1) { + bezierData = bez.buildBezierData(paths.v[i] + , paths.v[i + 1] + , [paths.o[i][0] - paths.v[i][0], paths.o[i][1] - paths.v[i][1]] + , [paths.i[i + 1][0] - paths.v[i + 1][0], paths.i[i + 1][1] - paths.v[i + 1][1]]); + pathInfo.tLength += bezierData.segmentLength; + pathInfo.segments.push(bezierData); + totalLength += bezierData.segmentLength; + } + i = len; + if (mask.v.c) { + bezierData = bez.buildBezierData(paths.v[i] + , paths.v[0] + , [paths.o[i][0] - paths.v[i][0], paths.o[i][1] - paths.v[i][1]] + , [paths.i[0][0] - paths.v[0][0], paths.i[0][1] - paths.v[0][1]]); + pathInfo.tLength += bezierData.segmentLength; + pathInfo.segments.push(bezierData); + totalLength += bezierData.segmentLength; + } + this._pathData.pi = pathInfo; + } + pathInfo = this._pathData.pi; + + currentLength = this._pathData.f.v; + segmentInd = 0; + pointInd = 1; + segmentLength = 0; + flag = true; + segments = pathInfo.segments; + if (currentLength < 0 && mask.v.c) { + if (pathInfo.tLength < Math.abs(currentLength)) { + currentLength = -Math.abs(currentLength) % pathInfo.tLength; + } + segmentInd = segments.length - 1; + points = segments[segmentInd].points; + pointInd = points.length - 1; + while (currentLength < 0) { + currentLength += points[pointInd].partialLength; + pointInd -= 1; + if (pointInd < 0) { + segmentInd -= 1; + points = segments[segmentInd].points; + pointInd = points.length - 1; + } + } + + } + points = segments[segmentInd].points; + prevPoint = points[pointInd - 1]; + currentPoint = points[pointInd]; + partialLength = currentPoint.partialLength; + } + + + len = letters.length; + xPos = 0; + yPos = 0; + var yOff = documentData.finalSize * 1.2 * 0.714; + var firstLine = true; + var animatorProps, animatorSelector; + var j, jLen; + var letterValue; + + jLen = animators.length; + var lastLetter; + + var mult, ind = -1, offf, xPathPos, yPathPos; + var initPathPos = currentLength, initSegmentInd = segmentInd, initPointInd = pointInd, currentLine = -1; + var elemOpacity; + var sc, sw, fc, k; + var lineLength = 0; + var letterSw, letterSc, letterFc, letterM = '', letterP = this.defaultPropsArray, letterO; + + // + if (documentData.j === 2 || documentData.j === 1) { + var animatorJustifyOffset = 0; + var animatorFirstCharOffset = 0; + var justifyOffsetMult = documentData.j === 2 ? -0.5 : -1; + var lastIndex = 0; + var isNewLine = true; + + for (i = 0; i < len; i += 1) { + if (letters[i].n) { + if (animatorJustifyOffset) { + animatorJustifyOffset += animatorFirstCharOffset; + } + while (lastIndex < i) { + letters[lastIndex].animatorJustifyOffset = animatorJustifyOffset; + lastIndex += 1; + } + animatorJustifyOffset = 0; + isNewLine = true; + } else { + for (j = 0; j < jLen; j += 1) { + animatorProps = animators[j].a; + if (animatorProps.t.propType) { + if (isNewLine && documentData.j === 2) { + animatorFirstCharOffset += animatorProps.t.v * justifyOffsetMult; + } + animatorSelector = animators[j].s; + mult = animatorSelector.getMult(letters[i].anIndexes[j], textData.a[j].s.totalChars); + if (mult.length) { + animatorJustifyOffset += animatorProps.t.v * mult[0] * justifyOffsetMult; + } else { + animatorJustifyOffset += animatorProps.t.v * mult * justifyOffsetMult; + } + } + } + isNewLine = false; + } + } + if (animatorJustifyOffset) { + animatorJustifyOffset += animatorFirstCharOffset; + } + while (lastIndex < i) { + letters[lastIndex].animatorJustifyOffset = animatorJustifyOffset; + lastIndex += 1; + } + } + // + + for (i = 0; i < len; i += 1) { + + matrixHelper.reset(); + elemOpacity = 1; + if (letters[i].n) { + xPos = 0; + yPos += documentData.yOffset; + yPos += firstLine ? 1 : 0; + currentLength = initPathPos; + firstLine = false; + lineLength = 0; + if (this._hasMaskedPath) { + segmentInd = initSegmentInd; + pointInd = initPointInd; + points = segments[segmentInd].points; + prevPoint = points[pointInd - 1]; + currentPoint = points[pointInd]; + partialLength = currentPoint.partialLength; + segmentLength = 0; + } + letterO = letterSw = letterFc = letterM = ''; + letterP = this.defaultPropsArray; + } else { + if (this._hasMaskedPath) { + if (currentLine !== letters[i].line) { + switch (documentData.j) { + case 1: + currentLength += totalLength - documentData.lineWidths[letters[i].line]; + break; + case 2: + currentLength += (totalLength - documentData.lineWidths[letters[i].line]) / 2; + break; + } + currentLine = letters[i].line; + } + if (ind !== letters[i].ind) { + if (letters[ind]) { + currentLength += letters[ind].extra; + } + currentLength += letters[i].an / 2; + ind = letters[i].ind; + } + currentLength += alignment[0] * letters[i].an / 200; + var animatorOffset = 0; + for (j = 0; j < jLen; j += 1) { + animatorProps = animators[j].a; + if (animatorProps.p.propType) { + animatorSelector = animators[j].s; + mult = animatorSelector.getMult(letters[i].anIndexes[j], textData.a[j].s.totalChars); + if (mult.length) { + animatorOffset += animatorProps.p.v[0] * mult[0]; + } else { + animatorOffset += animatorProps.p.v[0] * mult; + } + + } + if (animatorProps.a.propType) { + animatorSelector = animators[j].s; + mult = animatorSelector.getMult(letters[i].anIndexes[j], textData.a[j].s.totalChars); + if (mult.length) { + animatorOffset += animatorProps.a.v[0] * mult[0]; + } else { + animatorOffset += animatorProps.a.v[0] * mult; + } + + } + } + flag = true; + while (flag) { + if (segmentLength + partialLength >= currentLength + animatorOffset || !points) { + perc = (currentLength + animatorOffset - segmentLength) / currentPoint.partialLength; + xPathPos = prevPoint.point[0] + (currentPoint.point[0] - prevPoint.point[0]) * perc; + yPathPos = prevPoint.point[1] + (currentPoint.point[1] - prevPoint.point[1]) * perc; + matrixHelper.translate(-alignment[0] * letters[i].an / 200, -(alignment[1] * yOff / 100)); + flag = false; + } else if (points) { + segmentLength += currentPoint.partialLength; + pointInd += 1; + if (pointInd >= points.length) { + pointInd = 0; + segmentInd += 1; + if (!segments[segmentInd]) { + if (mask.v.c) { + pointInd = 0; + segmentInd = 0; + points = segments[segmentInd].points; + } else { + segmentLength -= currentPoint.partialLength; + points = null; + } + } else { + points = segments[segmentInd].points; + } + } + if (points) { + prevPoint = currentPoint; + currentPoint = points[pointInd]; + partialLength = currentPoint.partialLength; + } + } + } + offf = letters[i].an / 2 - letters[i].add; + matrixHelper.translate(-offf, 0, 0); + } else { + offf = letters[i].an / 2 - letters[i].add; + matrixHelper.translate(-offf, 0, 0); + + // Grouping alignment + matrixHelper.translate(-alignment[0] * letters[i].an / 200, -alignment[1] * yOff / 100, 0); + } + + lineLength += letters[i].l / 2; + for (j = 0; j < jLen; j += 1) { + animatorProps = animators[j].a; + if (animatorProps.t.propType) { + animatorSelector = animators[j].s; + mult = animatorSelector.getMult(letters[i].anIndexes[j], textData.a[j].s.totalChars); + //This condition is to prevent applying tracking to first character in each line. Might be better to use a boolean "isNewLine" + if (xPos !== 0 || documentData.j !== 0) { + if (this._hasMaskedPath) { + if (mult.length) { + currentLength += animatorProps.t.v * mult[0]; + } else { + currentLength += animatorProps.t.v * mult; + } + } else { + if (mult.length) { + xPos += animatorProps.t.v * mult[0]; + } else { + xPos += animatorProps.t.v * mult; + } + } + } + } + } + lineLength += letters[i].l / 2; + if (documentData.strokeWidthAnim) { + sw = documentData.sw || 0; + } + if (documentData.strokeColorAnim) { + if (documentData.sc) { + sc = [documentData.sc[0], documentData.sc[1], documentData.sc[2]]; + } else { + sc = [0, 0, 0]; + } + } + if (documentData.fillColorAnim && documentData.fc) { + fc = [documentData.fc[0], documentData.fc[1], documentData.fc[2]]; + } + for (j = 0; j < jLen; j += 1) { + animatorProps = animators[j].a; + if (animatorProps.a.propType) { + animatorSelector = animators[j].s; + mult = animatorSelector.getMult(letters[i].anIndexes[j], textData.a[j].s.totalChars); + + if (mult.length) { + matrixHelper.translate(-animatorProps.a.v[0] * mult[0], -animatorProps.a.v[1] * mult[1], animatorProps.a.v[2] * mult[2]); + } else { + matrixHelper.translate(-animatorProps.a.v[0] * mult, -animatorProps.a.v[1] * mult, animatorProps.a.v[2] * mult); + } + } + } + for (j = 0; j < jLen; j += 1) { + animatorProps = animators[j].a; + if (animatorProps.s.propType) { + animatorSelector = animators[j].s; + mult = animatorSelector.getMult(letters[i].anIndexes[j], textData.a[j].s.totalChars); + if (mult.length) { + matrixHelper.scale(1 + ((animatorProps.s.v[0] - 1) * mult[0]), 1 + ((animatorProps.s.v[1] - 1) * mult[1]), 1); + } else { + matrixHelper.scale(1 + ((animatorProps.s.v[0] - 1) * mult), 1 + ((animatorProps.s.v[1] - 1) * mult), 1); + } + } + } + for (j = 0; j < jLen; j += 1) { + animatorProps = animators[j].a; + animatorSelector = animators[j].s; + mult = animatorSelector.getMult(letters[i].anIndexes[j], textData.a[j].s.totalChars); + if (animatorProps.sk.propType) { + if (mult.length) { + matrixHelper.skewFromAxis(-animatorProps.sk.v * mult[0], animatorProps.sa.v * mult[1]); + } else { + matrixHelper.skewFromAxis(-animatorProps.sk.v * mult, animatorProps.sa.v * mult); + } + } + if (animatorProps.r.propType) { + if (mult.length) { + matrixHelper.rotateZ(-animatorProps.r.v * mult[2]); + } else { + matrixHelper.rotateZ(-animatorProps.r.v * mult); + } + } + if (animatorProps.ry.propType) { + + if (mult.length) { + matrixHelper.rotateY(animatorProps.ry.v * mult[1]); + } else { + matrixHelper.rotateY(animatorProps.ry.v * mult); + } + } + if (animatorProps.rx.propType) { + if (mult.length) { + matrixHelper.rotateX(animatorProps.rx.v * mult[0]); + } else { + matrixHelper.rotateX(animatorProps.rx.v * mult); + } + } + if (animatorProps.o.propType) { + if (mult.length) { + elemOpacity += ((animatorProps.o.v) * mult[0] - elemOpacity) * mult[0]; + } else { + elemOpacity += ((animatorProps.o.v) * mult - elemOpacity) * mult; + } + } + if (documentData.strokeWidthAnim && animatorProps.sw.propType) { + if (mult.length) { + sw += animatorProps.sw.v * mult[0]; + } else { + sw += animatorProps.sw.v * mult; + } + } + if (documentData.strokeColorAnim && animatorProps.sc.propType) { + for (k = 0; k < 3; k += 1) { + if (mult.length) { + sc[k] = sc[k] + (animatorProps.sc.v[k] - sc[k]) * mult[0]; + } else { + sc[k] = sc[k] + (animatorProps.sc.v[k] - sc[k]) * mult; + } + } + } + if (documentData.fillColorAnim && documentData.fc) { + if (animatorProps.fc.propType) { + for (k = 0; k < 3; k += 1) { + if (mult.length) { + fc[k] = fc[k] + (animatorProps.fc.v[k] - fc[k]) * mult[0]; + } else { + fc[k] = fc[k] + (animatorProps.fc.v[k] - fc[k]) * mult; + } + } + } + if (animatorProps.fh.propType) { + if (mult.length) { + fc = addHueToRGB(fc, animatorProps.fh.v * mult[0]); + } else { + fc = addHueToRGB(fc, animatorProps.fh.v * mult); + } + } + if (animatorProps.fs.propType) { + if (mult.length) { + fc = addSaturationToRGB(fc, animatorProps.fs.v * mult[0]); + } else { + fc = addSaturationToRGB(fc, animatorProps.fs.v * mult); + } + } + if (animatorProps.fb.propType) { + if (mult.length) { + fc = addBrightnessToRGB(fc, animatorProps.fb.v * mult[0]); + } else { + fc = addBrightnessToRGB(fc, animatorProps.fb.v * mult); + } + } + } + } + + for (j = 0; j < jLen; j += 1) { + animatorProps = animators[j].a; + + if (animatorProps.p.propType) { + animatorSelector = animators[j].s; + mult = animatorSelector.getMult(letters[i].anIndexes[j], textData.a[j].s.totalChars); + if (this._hasMaskedPath) { + if (mult.length) { + matrixHelper.translate(0, animatorProps.p.v[1] * mult[0], -animatorProps.p.v[2] * mult[1]); + } else { + matrixHelper.translate(0, animatorProps.p.v[1] * mult, -animatorProps.p.v[2] * mult); + } + } else { + if (mult.length) { + matrixHelper.translate(animatorProps.p.v[0] * mult[0], animatorProps.p.v[1] * mult[1], -animatorProps.p.v[2] * mult[2]); + } else { + matrixHelper.translate(animatorProps.p.v[0] * mult, animatorProps.p.v[1] * mult, -animatorProps.p.v[2] * mult); + + } + } + } + } + if (documentData.strokeWidthAnim) { + letterSw = sw < 0 ? 0 : sw; + } + if (documentData.strokeColorAnim) { + letterSc = 'rgb(' + Math.round(sc[0] * 255) + ',' + Math.round(sc[1] * 255) + ',' + Math.round(sc[2] * 255) + ')'; + } + if (documentData.fillColorAnim && documentData.fc) { + letterFc = 'rgb(' + Math.round(fc[0] * 255) + ',' + Math.round(fc[1] * 255) + ',' + Math.round(fc[2] * 255) + ')'; + } + + if (this._hasMaskedPath) { + matrixHelper.translate(0, -documentData.ls); + + matrixHelper.translate(0, alignment[1] * yOff / 100 + yPos, 0); + if (textData.p.p) { + tanAngle = (currentPoint.point[1] - prevPoint.point[1]) / (currentPoint.point[0] - prevPoint.point[0]); + var rot = Math.atan(tanAngle) * 180 / Math.PI; + if (currentPoint.point[0] < prevPoint.point[0]) { + rot += 180; + } + matrixHelper.rotate(-rot * Math.PI / 180); + } + matrixHelper.translate(xPathPos, yPathPos, 0); + currentLength -= alignment[0] * letters[i].an / 200; + if (letters[i + 1] && ind !== letters[i + 1].ind) { + currentLength += letters[i].an / 2; + currentLength += documentData.tr / 1000 * documentData.finalSize; + } + } else { + + matrixHelper.translate(xPos, yPos, 0); + + if (documentData.ps) { + //matrixHelper.translate(documentData.ps[0],documentData.ps[1],0); + matrixHelper.translate(documentData.ps[0], documentData.ps[1] + documentData.ascent, 0); + } + switch (documentData.j) { + case 1: + matrixHelper.translate(letters[i].animatorJustifyOffset + documentData.justifyOffset + (documentData.boxWidth - documentData.lineWidths[letters[i].line]), 0, 0); + break; + case 2: + matrixHelper.translate(letters[i].animatorJustifyOffset + documentData.justifyOffset + (documentData.boxWidth - documentData.lineWidths[letters[i].line]) / 2, 0, 0); + break; + } + matrixHelper.translate(0, -documentData.ls); + matrixHelper.translate(offf, 0, 0); + matrixHelper.translate(alignment[0] * letters[i].an / 200, alignment[1] * yOff / 100, 0); + xPos += letters[i].l + documentData.tr / 1000 * documentData.finalSize; + } + if (renderType === 'html') { + letterM = matrixHelper.toCSS(); + } else if (renderType === 'svg') { + letterM = matrixHelper.to2dCSS(); + } else { + letterP = [matrixHelper.props[0], matrixHelper.props[1], matrixHelper.props[2], matrixHelper.props[3], matrixHelper.props[4], matrixHelper.props[5], matrixHelper.props[6], matrixHelper.props[7], matrixHelper.props[8], matrixHelper.props[9], matrixHelper.props[10], matrixHelper.props[11], matrixHelper.props[12], matrixHelper.props[13], matrixHelper.props[14], matrixHelper.props[15]]; + } + letterO = elemOpacity; + } + + if (renderedLettersCount <= i) { + letterValue = new LetterProps(letterO, letterSw, letterSc, letterFc, letterM, letterP); + this.renderedLetters.push(letterValue); + renderedLettersCount += 1; + this.lettersChangedFlag = true; + } else { + letterValue = this.renderedLetters[i]; + this.lettersChangedFlag = letterValue.update(letterO, letterSw, letterSc, letterFc, letterM, letterP) || this.lettersChangedFlag; + } + } + }; + + TextAnimatorProperty.prototype.getValue = function () { + if (this._elem.globalData.frameId === this._frameId) { + return; + } + this._frameId = this._elem.globalData.frameId; + this.iterateDynamicProperties(); + }; + + TextAnimatorProperty.prototype.mHelper = new Matrix(); + TextAnimatorProperty.prototype.defaultPropsArray = []; + extendPrototype([DynamicPropertyContainer], TextAnimatorProperty); + function TextAnimatorDataProperty(elem, animatorProps, container) { + var defaultData = { propType: false }; + var getProp = PropertyFactory.getProp; + var textAnimator_animatables = animatorProps.a; + this.a = { + r: textAnimator_animatables.r ? getProp(elem, textAnimator_animatables.r, 0, degToRads, container) : defaultData, + rx: textAnimator_animatables.rx ? getProp(elem, textAnimator_animatables.rx, 0, degToRads, container) : defaultData, + ry: textAnimator_animatables.ry ? getProp(elem, textAnimator_animatables.ry, 0, degToRads, container) : defaultData, + sk: textAnimator_animatables.sk ? getProp(elem, textAnimator_animatables.sk, 0, degToRads, container) : defaultData, + sa: textAnimator_animatables.sa ? getProp(elem, textAnimator_animatables.sa, 0, degToRads, container) : defaultData, + s: textAnimator_animatables.s ? getProp(elem, textAnimator_animatables.s, 1, 0.01, container) : defaultData, + a: textAnimator_animatables.a ? getProp(elem, textAnimator_animatables.a, 1, 0, container) : defaultData, + o: textAnimator_animatables.o ? getProp(elem, textAnimator_animatables.o, 0, 0.01, container) : defaultData, + p: textAnimator_animatables.p ? getProp(elem, textAnimator_animatables.p, 1, 0, container) : defaultData, + sw: textAnimator_animatables.sw ? getProp(elem, textAnimator_animatables.sw, 0, 0, container) : defaultData, + sc: textAnimator_animatables.sc ? getProp(elem, textAnimator_animatables.sc, 1, 0, container) : defaultData, + fc: textAnimator_animatables.fc ? getProp(elem, textAnimator_animatables.fc, 1, 0, container) : defaultData, + fh: textAnimator_animatables.fh ? getProp(elem, textAnimator_animatables.fh, 0, 0, container) : defaultData, + fs: textAnimator_animatables.fs ? getProp(elem, textAnimator_animatables.fs, 0, 0.01, container) : defaultData, + fb: textAnimator_animatables.fb ? getProp(elem, textAnimator_animatables.fb, 0, 0.01, container) : defaultData, + t: textAnimator_animatables.t ? getProp(elem, textAnimator_animatables.t, 0, 0, container) : defaultData + }; + + this.s = TextSelectorProp.getTextSelectorProp(elem, animatorProps.s, container); + this.s.t = animatorProps.s.t; + } + function LetterProps(o, sw, sc, fc, m, p) { + this.o = o; + this.sw = sw; + this.sc = sc; + this.fc = fc; + this.m = m; + this.p = p; + this._mdf = { + o: true, + sw: !!sw, + sc: !!sc, + fc: !!fc, + m: true, + p: true + }; + } + + LetterProps.prototype.update = function (o, sw, sc, fc, m, p) { + this._mdf.o = false; + this._mdf.sw = false; + this._mdf.sc = false; + this._mdf.fc = false; + this._mdf.m = false; + this._mdf.p = false; + var updated = false; + + if (this.o !== o) { + this.o = o; + this._mdf.o = true; + updated = true; + } + if (this.sw !== sw) { + this.sw = sw; + this._mdf.sw = true; + updated = true; + } + if (this.sc !== sc) { + this.sc = sc; + this._mdf.sc = true; + updated = true; + } + if (this.fc !== fc) { + this.fc = fc; + this._mdf.fc = true; + updated = true; + } + if (this.m !== m) { + this.m = m; + this._mdf.m = true; + updated = true; + } + if (p.length && (this.p[0] !== p[0] || this.p[1] !== p[1] || this.p[4] !== p[4] || this.p[5] !== p[5] || this.p[12] !== p[12] || this.p[13] !== p[13])) { + this.p = p; + this._mdf.p = true; + updated = true; + } + return updated; + }; + function TextProperty(elem, data) { + this._frameId = initialDefaultFrame; + this.pv = ''; + this.v = ''; + this.kf = false; + this._isFirstFrame = true; + this._mdf = false; + this.data = data; + this.elem = elem; + this.comp = this.elem.comp; + this.keysIndex = 0; + this.canResize = false; + this.minimumFontSize = 1; + this.effectsSequence = []; + this.currentData = { + ascent: 0, + boxWidth: this.defaultBoxWidth, + f: '', + fStyle: '', + fWeight: '', + fc: '', + j: '', + justifyOffset: '', + l: [], + lh: 0, + lineWidths: [], + ls: '', + of: '', + s: '', + sc: '', + sw: 0, + t: 0, + tr: 0, + sz: 0, + ps: null, + fillColorAnim: false, + strokeColorAnim: false, + strokeWidthAnim: false, + yOffset: 0, + finalSize: 0, + finalText: [], + finalLineHeight: 0, + __complete: false + + }; + this.copyData(this.currentData, this.data.d.k[0].s); + + if (!this.searchProperty()) { + this.completeTextData(this.currentData); + } + } + + TextProperty.prototype.defaultBoxWidth = [0, 0]; + + TextProperty.prototype.copyData = function (obj, data) { + for (var s in data) { + if (data.hasOwnProperty(s)) { + obj[s] = data[s]; + } + } + return obj; + } + + TextProperty.prototype.setCurrentData = function (data) { + if (!data.__complete) { + this.completeTextData(data); + } + this.currentData = data; + this.currentData.boxWidth = this.currentData.boxWidth || this.defaultBoxWidth; + this._mdf = true; + }; + + TextProperty.prototype.searchProperty = function () { + return this.searchKeyframes(); + }; + + TextProperty.prototype.searchKeyframes = function () { + this.kf = this.data.d.k.length > 1; + if (this.kf) { + this.addEffect(this.getKeyframeValue.bind(this)); + } + return this.kf; + } + + TextProperty.prototype.addEffect = function (effectFunction) { + this.effectsSequence.push(effectFunction); + this.elem.addDynamicProperty(this); + }; + + TextProperty.prototype.getValue = function (_finalValue) { + if ((this.elem.globalData.frameId === this.frameId || !this.effectsSequence.length) && !_finalValue) { + return; + } + this.currentData.t = this.data.d.k[this.keysIndex].s.t; + var currentValue = this.currentData; + var currentIndex = this.keysIndex; + if (this.lock) { + this.setCurrentData(this.currentData); + return; + } + this.lock = true; + this._mdf = false; + var multipliedValue; + var i, len = this.effectsSequence.length; + var finalValue = _finalValue || this.data.d.k[this.keysIndex].s; + for (i = 0; i < len; i += 1) { + //Checking if index changed to prevent creating a new object every time the expression updates. + if (currentIndex !== this.keysIndex) { + finalValue = this.effectsSequence[i](finalValue, finalValue.t); + } else { + finalValue = this.effectsSequence[i](this.currentData, finalValue.t); + } + } + if (currentValue !== finalValue) { + this.setCurrentData(finalValue); + } + this.pv = this.v = this.currentData; + this.lock = false; + this.frameId = this.elem.globalData.frameId; + } + + TextProperty.prototype.getKeyframeValue = function () { + var textKeys = this.data.d.k, textDocumentData; + var frameNum = this.elem.comp.renderedFrame; + var i = 0, len = textKeys.length; + while (i <= len - 1) { + textDocumentData = textKeys[i].s; + if (i === len - 1 || textKeys[i + 1].t > frameNum) { + break; + } + i += 1; + } + if (this.keysIndex !== i) { + this.keysIndex = i; + } + return this.data.d.k[this.keysIndex].s; + }; + + TextProperty.prototype.buildFinalText = function (text) { + var combinedCharacters = FontManager.getCombinedCharacterCodes(); + var charactersArray = []; + var i = 0, len = text.length; + var charCode; + while (i < len) { + charCode = text.charCodeAt(i); + if (combinedCharacters.indexOf(charCode) !== -1) { + charactersArray[charactersArray.length - 1] += text.charAt(i); + } else { + if (charCode >= 0xD800 && charCode <= 0xDBFF) { + charCode = text.charCodeAt(i + 1); + if (charCode >= 0xDC00 && charCode <= 0xDFFF) { + charactersArray.push(text.substr(i, 2)); + ++i; + } else { + charactersArray.push(text.charAt(i)); + } + } else { + charactersArray.push(text.charAt(i)); + } + } + i += 1; + } + return charactersArray; + } + + TextProperty.prototype.completeTextData = function (documentData) { + documentData.__complete = true; + var fontManager = this.elem.globalData.fontManager; + var data = this.data; + var letters = []; + var i, len; + var newLineFlag, index = 0, val; + var anchorGrouping = data.m.g; + var currentSize = 0, currentPos = 0, currentLine = 0, lineWidths = []; + var lineWidth = 0; + var maxLineWidth = 0; + var j, jLen; + var fontData = fontManager.getFontByName(documentData.f); + var charData, cLength = 0; + var styles = fontData.fStyle ? fontData.fStyle.split(' ') : []; + + var fWeight = 'normal', fStyle = 'normal'; + len = styles.length; + var styleName; + for (i = 0; i < len; i += 1) { + styleName = styles[i].toLowerCase(); + switch (styleName) { + case 'italic': + fStyle = 'italic'; + break; + case 'bold': + fWeight = '700'; + break; + case 'black': + fWeight = '900'; + break; + case 'medium': + fWeight = '500'; + break; + case 'regular': + case 'normal': + fWeight = '400'; + break; + case 'light': + case 'thin': + fWeight = '200'; + break; + } + } + documentData.fWeight = fontData.fWeight || fWeight; + documentData.fStyle = fStyle; + documentData.finalSize = documentData.s; + documentData.finalText = this.buildFinalText(documentData.t); + len = documentData.finalText.length; + documentData.finalLineHeight = documentData.lh; + var trackingOffset = documentData.tr / 1000 * documentData.finalSize; + var charCode; + if (documentData.sz) { + var flag = true; + var boxWidth = documentData.sz[0]; + var boxHeight = documentData.sz[1]; + var currentHeight, finalText; + while (flag) { + finalText = this.buildFinalText(documentData.t); + currentHeight = 0; + lineWidth = 0; + len = finalText.length; + trackingOffset = documentData.tr / 1000 * documentData.finalSize; + var lastSpaceIndex = -1; + for (i = 0; i < len; i += 1) { + charCode = finalText[i].charCodeAt(0); + newLineFlag = false; + if (finalText[i] === ' ') { + lastSpaceIndex = i; + } else if (charCode === 13 || charCode === 3) { + lineWidth = 0; + newLineFlag = true; + currentHeight += documentData.finalLineHeight || documentData.finalSize * 1.2; + } + if (fontManager.chars) { + charData = fontManager.getCharData(finalText[i], fontData.fStyle, fontData.fFamily); + cLength = newLineFlag ? 0 : charData.w * documentData.finalSize / 100; + } else { + //tCanvasHelper.font = documentData.s + 'px '+ fontData.fFamily; + cLength = fontManager.measureText(finalText[i], documentData.f, documentData.finalSize); + } + if (lineWidth + cLength > boxWidth && finalText[i] !== ' ') { + if (lastSpaceIndex === -1) { + len += 1; + } else { + i = lastSpaceIndex; + } + currentHeight += documentData.finalLineHeight || documentData.finalSize * 1.2; + finalText.splice(i, lastSpaceIndex === i ? 1 : 0, "\r"); + //finalText = finalText.substr(0,i) + "\r" + finalText.substr(i === lastSpaceIndex ? i + 1 : i); + lastSpaceIndex = -1; + lineWidth = 0; + } else { + lineWidth += cLength; + lineWidth += trackingOffset; + } + } + currentHeight += fontData.ascent * documentData.finalSize / 100; + if (this.canResize && documentData.finalSize > this.minimumFontSize && boxHeight < currentHeight) { + documentData.finalSize -= 1; + documentData.finalLineHeight = documentData.finalSize * documentData.lh / documentData.s; + } else { + documentData.finalText = finalText; + len = documentData.finalText.length; + flag = false; + } + } + + } + lineWidth = - trackingOffset; + cLength = 0; + var uncollapsedSpaces = 0; + var currentChar; + for (i = 0; i < len; i += 1) { + newLineFlag = false; + currentChar = documentData.finalText[i]; + charCode = currentChar.charCodeAt(0); + if (charCode === 13 || charCode === 3) { + uncollapsedSpaces = 0; + lineWidths.push(lineWidth); + maxLineWidth = lineWidth > maxLineWidth ? lineWidth : maxLineWidth; + lineWidth = - 2 * trackingOffset; + val = ''; + newLineFlag = true; + currentLine += 1; + } else { + val = currentChar; + } + if (fontManager.chars) { + charData = fontManager.getCharData(currentChar, fontData.fStyle, fontManager.getFontByName(documentData.f).fFamily); + cLength = newLineFlag ? 0 : charData.w * documentData.finalSize / 100; + } else { + //var charWidth = fontManager.measureText(val, documentData.f, documentData.finalSize); + //tCanvasHelper.font = documentData.finalSize + 'px '+ fontManager.getFontByName(documentData.f).fFamily; + cLength = fontManager.measureText(val, documentData.f, documentData.finalSize); + } + + // + if (currentChar === ' ') { + uncollapsedSpaces += cLength + trackingOffset; + } else { + lineWidth += cLength + trackingOffset + uncollapsedSpaces; + uncollapsedSpaces = 0; + } + letters.push({ l: cLength, an: cLength, add: currentSize, n: newLineFlag, anIndexes: [], val: val, line: currentLine, animatorJustifyOffset: 0 }); + if (anchorGrouping == 2) { + currentSize += cLength; + if (val === '' || val === ' ' || i === len - 1) { + if (val === '' || val === ' ') { + currentSize -= cLength; + } + while (currentPos <= i) { + letters[currentPos].an = currentSize; + letters[currentPos].ind = index; + letters[currentPos].extra = cLength; + currentPos += 1; + } + index += 1; + currentSize = 0; + } + } else if (anchorGrouping == 3) { + currentSize += cLength; + if (val === '' || i === len - 1) { + if (val === '') { + currentSize -= cLength; + } + while (currentPos <= i) { + letters[currentPos].an = currentSize; + letters[currentPos].ind = index; + letters[currentPos].extra = cLength; + currentPos += 1; + } + currentSize = 0; + index += 1; + } + } else { + letters[index].ind = index; + letters[index].extra = 0; + index += 1; + } + } + documentData.l = letters; + maxLineWidth = lineWidth > maxLineWidth ? lineWidth : maxLineWidth; + lineWidths.push(lineWidth); + if (documentData.sz) { + documentData.boxWidth = documentData.sz[0]; + documentData.justifyOffset = 0; + } else { + documentData.boxWidth = maxLineWidth; + switch (documentData.j) { + case 1: + documentData.justifyOffset = - documentData.boxWidth; + break; + case 2: + documentData.justifyOffset = - documentData.boxWidth / 2; + break; + default: + documentData.justifyOffset = 0; + } + } + documentData.lineWidths = lineWidths; + + var animators = data.a, animatorData, letterData; + jLen = animators.length; + var based, ind, indexes = []; + for (j = 0; j < jLen; j += 1) { + animatorData = animators[j]; + if (animatorData.a.sc) { + documentData.strokeColorAnim = true; + } + if (animatorData.a.sw) { + documentData.strokeWidthAnim = true; + } + if (animatorData.a.fc || animatorData.a.fh || animatorData.a.fs || animatorData.a.fb) { + documentData.fillColorAnim = true; + } + ind = 0; + based = animatorData.s.b; + for (i = 0; i < len; i += 1) { + letterData = letters[i]; + letterData.anIndexes[j] = ind; + if ((based == 1 && letterData.val !== '') || (based == 2 && letterData.val !== '' && letterData.val !== ' ') || (based == 3 && (letterData.n || letterData.val == ' ' || i == len - 1)) || (based == 4 && (letterData.n || i == len - 1))) { + if (animatorData.s.rn === 1) { + indexes.push(ind); + } + ind += 1; + } + } + data.a[j].s.totalChars = ind; + var currentInd = -1, newInd; + if (animatorData.s.rn === 1) { + for (i = 0; i < len; i += 1) { + letterData = letters[i]; + if (currentInd != letterData.anIndexes[j]) { + currentInd = letterData.anIndexes[j]; + newInd = indexes.splice(Math.floor(Math.random() * indexes.length), 1)[0]; + } + letterData.anIndexes[j] = newInd; + } + } + } + documentData.yOffset = documentData.finalLineHeight || documentData.finalSize * 1.2; + documentData.ls = documentData.ls || 0; + documentData.ascent = fontData.ascent * documentData.finalSize / 100; + }; + + TextProperty.prototype.updateDocumentData = function (newData, index) { + index = index === undefined ? this.keysIndex : index; + var dData = this.copyData({}, this.data.d.k[index].s); + dData = this.copyData(dData, newData); + this.data.d.k[index].s = dData; + this.recalculate(index); + this.elem.addDynamicProperty(this); + }; + + TextProperty.prototype.recalculate = function (index) { + var dData = this.data.d.k[index].s; + dData.__complete = false; + this.keysIndex = 0; + this._isFirstFrame = true; + this.getValue(dData); + } + + TextProperty.prototype.canResizeFont = function (_canResize) { + this.canResize = _canResize; + this.recalculate(this.keysIndex); + this.elem.addDynamicProperty(this); + }; + + TextProperty.prototype.setMinimumFontSize = function (_fontValue) { + this.minimumFontSize = Math.floor(_fontValue) || 1; + this.recalculate(this.keysIndex); + this.elem.addDynamicProperty(this); + }; + + var TextSelectorProp = (function () { + var max = Math.max; + var min = Math.min; + var floor = Math.floor; + + function TextSelectorProp(elem, data) { + this._currentTextLength = -1; + this.k = false; + this.data = data; + this.elem = elem; + this.comp = elem.comp; + this.finalS = 0; + this.finalE = 0; + this.initDynamicPropertyContainer(elem); + this.s = PropertyFactory.getProp(elem, data.s || { k: 0 }, 0, 0, this); + if ('e' in data) { + this.e = PropertyFactory.getProp(elem, data.e, 0, 0, this); + } else { + this.e = { v: 100 }; + } + this.o = PropertyFactory.getProp(elem, data.o || { k: 0 }, 0, 0, this); + this.xe = PropertyFactory.getProp(elem, data.xe || { k: 0 }, 0, 0, this); + this.ne = PropertyFactory.getProp(elem, data.ne || { k: 0 }, 0, 0, this); + this.a = PropertyFactory.getProp(elem, data.a, 0, 0.01, this); + if (!this.dynamicProperties.length) { + this.getValue(); + } + } + + TextSelectorProp.prototype = { + getMult: function (ind) { + if (this._currentTextLength !== this.elem.textProperty.currentData.l.length) { + this.getValue(); + } + //var easer = bez.getEasingCurve(this.ne.v/100,0,1-this.xe.v/100,1); + var x1 = 0; + var y1 = 0; + var x2 = 1; + var y2 = 1; + if (this.ne.v > 0) { + x1 = this.ne.v / 100.0; + } + else { + y1 = -this.ne.v / 100.0; + } + if (this.xe.v > 0) { + x2 = 1.0 - this.xe.v / 100.0; + } + else { + y2 = 1.0 + this.xe.v / 100.0; + } + var easer = BezierFactory.getBezierEasing(x1, y1, x2, y2).get; + + var mult = 0; + var s = this.finalS; + var e = this.finalE; + var type = this.data.sh; + if (type === 2) { + if (e === s) { + mult = ind >= e ? 1 : 0; + } else { + mult = max(0, min(0.5 / (e - s) + (ind - s) / (e - s), 1)); + } + mult = easer(mult); + } else if (type === 3) { + if (e === s) { + mult = ind >= e ? 0 : 1; + } else { + mult = 1 - max(0, min(0.5 / (e - s) + (ind - s) / (e - s), 1)); + } + + mult = easer(mult); + } else if (type === 4) { + if (e === s) { + mult = 0; + } else { + mult = max(0, min(0.5 / (e - s) + (ind - s) / (e - s), 1)); + if (mult < 0.5) { + mult *= 2; + } else { + mult = 1 - 2 * (mult - 0.5); + } + } + mult = easer(mult); + } else if (type === 5) { + if (e === s) { + mult = 0; + } else { + var tot = e - s; + /*ind += 0.5; + mult = -4/(tot*tot)*(ind*ind)+(4/tot)*ind;*/ + ind = min(max(0, ind + 0.5 - s), e - s); + var x = -tot / 2 + ind; + var a = tot / 2; + mult = Math.sqrt(1 - (x * x) / (a * a)); + } + mult = easer(mult); + } else if (type === 6) { + if (e === s) { + mult = 0; + } else { + ind = min(max(0, ind + 0.5 - s), e - s); + mult = (1 + (Math.cos((Math.PI + Math.PI * 2 * (ind) / (e - s))))) / 2; + } + mult = easer(mult); + } else { + if (ind >= floor(s)) { + if (ind - s < 0) { + mult = max(0, min(min(e, 1) - (s - ind), 1)); + } else { + mult = max(0, min(e - ind, 1)); + } + } + mult = easer(mult); + } + return mult * this.a.v; + }, + getValue: function (newCharsFlag) { + this.iterateDynamicProperties(); + this._mdf = newCharsFlag || this._mdf; + this._currentTextLength = this.elem.textProperty.currentData.l.length || 0; + if (newCharsFlag && this.data.r === 2) { + this.e.v = this._currentTextLength; + } + var divisor = this.data.r === 2 ? 1 : 100 / this.data.totalChars; + var o = this.o.v / divisor; + var s = this.s.v / divisor + o; + var e = (this.e.v / divisor) + o; + if (s > e) { + var _s = s; + s = e; + e = _s; + } + this.finalS = s; + this.finalE = e; + } + } + extendPrototype([DynamicPropertyContainer], TextSelectorProp); + + function getTextSelectorProp(elem, data, arr) { + return new TextSelectorProp(elem, data, arr); + } + + return { + getTextSelectorProp: getTextSelectorProp + }; + }()); + + + var pool_factory = (function () { + return function (initialLength, _create, _release, _clone) { + + var _length = 0; + var _maxLength = initialLength; + var pool = createSizedArray(_maxLength); + + var ob = { + newElement: newElement, + release: release + }; + + function newElement() { + var element; + if (_length) { + _length -= 1; + element = pool[_length]; + } else { + element = _create(); + } + return element; + } + + function release(element) { + if (_length === _maxLength) { + pool = pooling.double(pool); + _maxLength = _maxLength * 2; + } + if (_release) { + _release(element); + } + pool[_length] = element; + _length += 1; + } + + function clone() { + var clonedElement = newElement(); + return _clone(clonedElement); + } + + return ob; + }; + }()); + + var pooling = (function () { + + function double(arr) { + return arr.concat(createSizedArray(arr.length)); + } + + return { + double: double + }; + }()); + var point_pool = (function () { + + function create() { + return createTypedArray('float32', 2); + } + return pool_factory(8, create); + }()); + var shape_pool = (function () { + + function create() { + return new ShapePath(); + } + + function release(shapePath) { + var len = shapePath._length, i; + for (i = 0; i < len; i += 1) { + point_pool.release(shapePath.v[i]); + point_pool.release(shapePath.i[i]); + point_pool.release(shapePath.o[i]); + shapePath.v[i] = null; + shapePath.i[i] = null; + shapePath.o[i] = null; + } + shapePath._length = 0; + shapePath.c = false; + } + + function clone(shape) { + var cloned = factory.newElement(); + var i, len = shape._length === undefined ? shape.v.length : shape._length; + cloned.setLength(len); + cloned.c = shape.c; + var pt; + + for (i = 0; i < len; i += 1) { + cloned.setTripleAt(shape.v[i][0], shape.v[i][1], shape.o[i][0], shape.o[i][1], shape.i[i][0], shape.i[i][1], i); + } + return cloned; + } + + var factory = pool_factory(4, create, release); + factory.clone = clone; + + return factory; + }()); + var shapeCollection_pool = (function () { + var ob = { + newShapeCollection: newShapeCollection, + release: release + }; + + var _length = 0; + var _maxLength = 4; + var pool = createSizedArray(_maxLength); + + function newShapeCollection() { + var shapeCollection; + if (_length) { + _length -= 1; + shapeCollection = pool[_length]; + } else { + shapeCollection = new ShapeCollection(); + } + return shapeCollection; + } + + function release(shapeCollection) { + var i, len = shapeCollection._length; + for (i = 0; i < len; i += 1) { + shape_pool.release(shapeCollection.shapes[i]); + } + shapeCollection._length = 0; + + if (_length === _maxLength) { + pool = pooling.double(pool); + _maxLength = _maxLength * 2; + } + pool[_length] = shapeCollection; + _length += 1; + } + + return ob; + }()); + var segments_length_pool = (function () { + + function create() { + return { + lengths: [], + totalLength: 0 + }; + } + + function release(element) { + var i, len = element.lengths.length; + for (i = 0; i < len; i += 1) { + bezier_length_pool.release(element.lengths[i]); + } + element.lengths.length = 0; + } + + return pool_factory(8, create, release); + }()); + var bezier_length_pool = (function () { + + function create() { + return { + addedLength: 0, + percents: createTypedArray('float32', defaultCurveSegments), + lengths: createTypedArray('float32', defaultCurveSegments), + }; + } + return pool_factory(8, create); + }()); + function BaseRenderer() { } + BaseRenderer.prototype.checkLayers = function (num) { + var i, len = this.layers.length, data; + this.completeLayers = true; + for (i = len - 1; i >= 0; i--) { + if (!this.elements[i]) { + data = this.layers[i]; + if (data.ip - data.st <= (num - this.layers[i].st) && data.op - data.st > (num - this.layers[i].st)) { + this.buildItem(i); + } + } + this.completeLayers = this.elements[i] ? this.completeLayers : false; + } + this.checkPendingElements(); + }; + + BaseRenderer.prototype.createItem = function (layer) { + switch (layer.ty) { + case 2: + return this.createImage(layer); + case 0: + return this.createComp(layer); + case 1: + return this.createSolid(layer); + case 3: + return this.createNull(layer); + case 4: + return this.createShape(layer); + case 5: + return this.createText(layer); + case 13: + return this.createCamera(layer); + } + return this.createNull(layer); + }; + + BaseRenderer.prototype.createCamera = function () { + throw new Error('You\'re using a 3d camera. Try the html renderer.'); + }; + + BaseRenderer.prototype.buildAllItems = function () { + var i, len = this.layers.length; + for (i = 0; i < len; i += 1) { + this.buildItem(i); + } + this.checkPendingElements(); + }; + + BaseRenderer.prototype.includeLayers = function (newLayers) { + this.completeLayers = false; + var i, len = newLayers.length; + var j, jLen = this.layers.length; + for (i = 0; i < len; i += 1) { + j = 0; + while (j < jLen) { + if (this.layers[j].id == newLayers[i].id) { + this.layers[j] = newLayers[i]; + break; + } + j += 1; + } + } + }; + + BaseRenderer.prototype.setProjectInterface = function (pInterface) { + this.globalData.projectInterface = pInterface; + }; + + BaseRenderer.prototype.initItems = function () { + if (!this.globalData.progressiveLoad) { + this.buildAllItems(); + } + }; + BaseRenderer.prototype.buildElementParenting = function (element, parentName, hierarchy) { + var elements = this.elements; + var layers = this.layers; + var i = 0, len = layers.length; + while (i < len) { + if (layers[i].ind == parentName) { + if (!elements[i] || elements[i] === true) { + this.buildItem(i); + this.addPendingElement(element); + } else { + hierarchy.push(elements[i]); + elements[i].setAsParent(); + if (layers[i].parent !== undefined) { + this.buildElementParenting(element, layers[i].parent, hierarchy); + } else { + element.setHierarchy(hierarchy); + } + } + } + i += 1; + } + }; + + BaseRenderer.prototype.addPendingElement = function (element) { + this.pendingElements.push(element); + }; + + BaseRenderer.prototype.searchExtraCompositions = function (assets) { + var i, len = assets.length; + for (i = 0; i < len; i += 1) { + if (assets[i].xt) { + var comp = this.createComp(assets[i]); + comp.initExpressions(); + this.globalData.projectInterface.registerComposition(comp); + } + } + }; + + BaseRenderer.prototype.setupGlobalData = function (animData, fontsContainer) { + this.globalData.fontManager = new FontManager(); + this.globalData.fontManager.addChars(animData.chars); + this.globalData.fontManager.addFonts(animData.fonts, fontsContainer); + this.globalData.getAssetData = this.animationItem.getAssetData.bind(this.animationItem); + this.globalData.getAssetsPath = this.animationItem.getAssetsPath.bind(this.animationItem); + this.globalData.imageLoader = this.animationItem.imagePreloader; + this.globalData.frameId = 0; + this.globalData.frameRate = animData.fr; + this.globalData.nm = animData.nm; + this.globalData.compSize = { + w: animData.w, + h: animData.h + } + } + function SVGRenderer(animationItem, config) { + this.animationItem = animationItem; + this.layers = null; + this.renderedFrame = -1; + this.svgElement = createNS('svg'); + var ariaLabel = ''; + if (config && config.title) { + var titleElement = createNS('title'); + var titleId = createElementID(); + titleElement.setAttribute('id', titleId); + titleElement.textContent = config.title; + this.svgElement.appendChild(titleElement); + ariaLabel += titleId; + } + if (config && config.description) { + var descElement = createNS('desc'); + var descId = createElementID(); + descElement.setAttribute('id', descId); + descElement.textContent = config.description; + this.svgElement.appendChild(descElement); + ariaLabel += ' ' + descId; + } + if (ariaLabel) { + this.svgElement.setAttribute('aria-labelledby', ariaLabel) + } + var defs = createNS('defs'); + this.svgElement.appendChild(defs); + var maskElement = createNS('g'); + this.svgElement.appendChild(maskElement); + this.layerElement = maskElement; + this.renderConfig = { + preserveAspectRatio: (config && config.preserveAspectRatio) || 'xMidYMid meet', + imagePreserveAspectRatio: (config && config.imagePreserveAspectRatio) || 'xMidYMid slice', + progressiveLoad: (config && config.progressiveLoad) || false, + hideOnTransparent: (config && config.hideOnTransparent === false) ? false : true, + viewBoxOnly: (config && config.viewBoxOnly) || false, + viewBoxSize: (config && config.viewBoxSize) || false, + className: (config && config.className) || '', + id: (config && config.id) || '', + focusable: config && config.focusable, + filterSize: { + width: config && config.filterSize && config.filterSize.width || '100%', + height: config && config.filterSize && config.filterSize.height || '100%', + x: config && config.filterSize && config.filterSize.x || '0%', + y: config && config.filterSize && config.filterSize.y || '0%', + } + }; + + this.globalData = { + _mdf: false, + frameNum: -1, + defs: defs, + renderConfig: this.renderConfig + }; + this.elements = []; + this.pendingElements = []; + this.destroyed = false; + this.rendererType = 'svg'; + + } + + extendPrototype([BaseRenderer], SVGRenderer); + + SVGRenderer.prototype.createNull = function (data) { + return new NullElement(data, this.globalData, this); + }; + + SVGRenderer.prototype.createShape = function (data) { + return new SVGShapeElement(data, this.globalData, this); + }; + + SVGRenderer.prototype.createText = function (data) { + return new SVGTextElement(data, this.globalData, this); + + }; + + SVGRenderer.prototype.createImage = function (data) { + return new IImageElement(data, this.globalData, this); + }; + + SVGRenderer.prototype.createComp = function (data) { + return new SVGCompElement(data, this.globalData, this); + + }; + + SVGRenderer.prototype.createSolid = function (data) { + return new ISolidElement(data, this.globalData, this); + }; + + SVGRenderer.prototype.configAnimation = function (animData) { + this.svgElement.setAttribute('xmlns', 'http://www.w3.org/2000/svg'); + if (this.renderConfig.viewBoxSize) { + this.svgElement.setAttribute('viewBox', this.renderConfig.viewBoxSize); + } else { + this.svgElement.setAttribute('viewBox', '0 0 ' + animData.w + ' ' + animData.h); + } + + if (!this.renderConfig.viewBoxOnly) { + this.svgElement.setAttribute('width', animData.w); + this.svgElement.setAttribute('height', animData.h); + this.svgElement.style.width = '100%'; + this.svgElement.style.height = '100%'; + this.svgElement.style.transform = 'translate3d(0,0,0)'; + } + if (this.renderConfig.className) { + this.svgElement.setAttribute('class', this.renderConfig.className); + } + if (this.renderConfig.id) { + this.svgElement.setAttribute('id', this.renderConfig.id); + } + if (this.renderConfig.focusable !== undefined) { + this.svgElement.setAttribute('focusable', this.renderConfig.focusable); + } + this.svgElement.setAttribute('preserveAspectRatio', this.renderConfig.preserveAspectRatio); + //this.layerElement.style.transform = 'translate3d(0,0,0)'; + //this.layerElement.style.transformOrigin = this.layerElement.style.mozTransformOrigin = this.layerElement.style.webkitTransformOrigin = this.layerElement.style['-webkit-transform'] = "0px 0px 0px"; + this.animationItem.wrapper.appendChild(this.svgElement); + //Mask animation + var defs = this.globalData.defs; + + this.setupGlobalData(animData, defs); + this.globalData.progressiveLoad = this.renderConfig.progressiveLoad; + this.data = animData; + + var maskElement = createNS('clipPath'); + var rect = createNS('rect'); + rect.setAttribute('width', animData.w); + rect.setAttribute('height', animData.h); + rect.setAttribute('x', 0); + rect.setAttribute('y', 0); + var maskId = createElementID(); + maskElement.setAttribute('id', maskId); + maskElement.appendChild(rect); + this.layerElement.setAttribute("clip-path", "url(" + locationHref + "#" + maskId + ")"); + + defs.appendChild(maskElement); + this.layers = animData.layers; + this.elements = createSizedArray(animData.layers.length); + }; + + + SVGRenderer.prototype.destroy = function () { + this.animationItem.wrapper.innerHTML = ''; + this.layerElement = null; + this.globalData.defs = null; + var i, len = this.layers ? this.layers.length : 0; + for (i = 0; i < len; i++) { + if (this.elements[i]) { + this.elements[i].destroy(); + } + } + this.elements.length = 0; + this.destroyed = true; + this.animationItem = null; + }; + + SVGRenderer.prototype.updateContainerSize = function () { + }; + + SVGRenderer.prototype.buildItem = function (pos) { + var elements = this.elements; + if (elements[pos] || this.layers[pos].ty == 99) { + return; + } + elements[pos] = true; + var element = this.createItem(this.layers[pos]); + + elements[pos] = element; + if (expressionsPlugin) { + if (this.layers[pos].ty === 0) { + this.globalData.projectInterface.registerComposition(element); + } + element.initExpressions(); + } + this.appendElementInPos(element, pos); + if (this.layers[pos].tt) { + if (!this.elements[pos - 1] || this.elements[pos - 1] === true) { + this.buildItem(pos - 1); + this.addPendingElement(element); + } else { + element.setMatte(elements[pos - 1].layerId); + } + } + }; + + SVGRenderer.prototype.checkPendingElements = function () { + while (this.pendingElements.length) { + var element = this.pendingElements.pop(); + element.checkParenting(); + if (element.data.tt) { + var i = 0, len = this.elements.length; + while (i < len) { + if (this.elements[i] === element) { + element.setMatte(this.elements[i - 1].layerId); + break; + } + i += 1; + } + } + } + }; + + SVGRenderer.prototype.renderFrame = function (num) { + if (this.renderedFrame === num || this.destroyed) { + return; + } + if (num === null) { + num = this.renderedFrame; + } else { + this.renderedFrame = num; + } + // console.log('-------'); + // console.log('FRAME ',num); + this.globalData.frameNum = num; + this.globalData.frameId += 1; + this.globalData.projectInterface.currentFrame = num; + this.globalData._mdf = false; + var i, len = this.layers.length; + if (!this.completeLayers) { + this.checkLayers(num); + } + for (i = len - 1; i >= 0; i--) { + if (this.completeLayers || this.elements[i]) { + this.elements[i].prepareFrame(num - this.layers[i].st); + } + } + if (this.globalData._mdf) { + for (i = 0; i < len; i += 1) { + if (this.completeLayers || this.elements[i]) { + this.elements[i].renderFrame(); + } + } + } + }; + + SVGRenderer.prototype.appendElementInPos = function (element, pos) { + var newElement = element.getBaseElement(); + if (!newElement) { + return; + } + var i = 0; + var nextElement; + while (i < pos) { + if (this.elements[i] && this.elements[i] !== true && this.elements[i].getBaseElement()) { + nextElement = this.elements[i].getBaseElement(); + } + i += 1; + } + if (nextElement) { + this.layerElement.insertBefore(newElement, nextElement); + } else { + this.layerElement.appendChild(newElement); + } + }; + + SVGRenderer.prototype.hide = function () { + this.layerElement.style.display = 'none'; + }; + + SVGRenderer.prototype.show = function () { + this.layerElement.style.display = 'block'; + }; + + function CanvasRenderer(animationItem, config) { + this.animationItem = animationItem; + this.renderConfig = { + clearCanvas: (config && config.clearCanvas !== undefined) ? config.clearCanvas : true, + context: (config && config.context) || null, + progressiveLoad: (config && config.progressiveLoad) || false, + preserveAspectRatio: (config && config.preserveAspectRatio) || 'xMidYMid meet', + imagePreserveAspectRatio: (config && config.imagePreserveAspectRatio) || 'xMidYMid slice', + className: (config && config.className) || '', + id: (config && config.id) || '', + }; + this.renderConfig.dpr = (config && config.dpr) || 1; + if (this.animationItem.wrapper) { + this.renderConfig.dpr = (config && config.dpr) || window.devicePixelRatio || 1; + } + this.renderedFrame = -1; + this.globalData = { + frameNum: -1, + _mdf: false, + renderConfig: this.renderConfig, + currentGlobalAlpha: -1 + }; + this.contextData = new CVContextData(); + this.elements = []; + this.pendingElements = []; + this.transformMat = new Matrix(); + this.completeLayers = false; + this.rendererType = 'canvas'; + } + extendPrototype([BaseRenderer], CanvasRenderer); + + CanvasRenderer.prototype.createShape = function (data) { + return new CVShapeElement(data, this.globalData, this); + }; + + CanvasRenderer.prototype.createText = function (data) { + return new CVTextElement(data, this.globalData, this); + }; + + CanvasRenderer.prototype.createImage = function (data) { + return new CVImageElement(data, this.globalData, this); + }; + + CanvasRenderer.prototype.createComp = function (data) { + return new CVCompElement(data, this.globalData, this); + }; + + CanvasRenderer.prototype.createSolid = function (data) { + return new CVSolidElement(data, this.globalData, this); + }; + + CanvasRenderer.prototype.createNull = SVGRenderer.prototype.createNull; + + CanvasRenderer.prototype.ctxTransform = function (props) { + if (props[0] === 1 && props[1] === 0 && props[4] === 0 && props[5] === 1 && props[12] === 0 && props[13] === 0) { + return; + } + if (!this.renderConfig.clearCanvas) { + this.canvasContext.transform(props[0], props[1], props[4], props[5], props[12], props[13]); + return; + } + this.transformMat.cloneFromProps(props); + var cProps = this.contextData.cTr.props; + this.transformMat.transform(cProps[0], cProps[1], cProps[2], cProps[3], cProps[4], cProps[5], cProps[6], cProps[7], cProps[8], cProps[9], cProps[10], cProps[11], cProps[12], cProps[13], cProps[14], cProps[15]); + //this.contextData.cTr.transform(props[0],props[1],props[2],props[3],props[4],props[5],props[6],props[7],props[8],props[9],props[10],props[11],props[12],props[13],props[14],props[15]); + this.contextData.cTr.cloneFromProps(this.transformMat.props); + var trProps = this.contextData.cTr.props; + this.canvasContext.setTransform(trProps[0], trProps[1], trProps[4], trProps[5], trProps[12], trProps[13]); + }; + + CanvasRenderer.prototype.ctxOpacity = function (op) { + /*if(op === 1){ + return; + }*/ + if (!this.renderConfig.clearCanvas) { + this.canvasContext.globalAlpha *= op < 0 ? 0 : op; + this.globalData.currentGlobalAlpha = this.contextData.cO; + return; + } + this.contextData.cO *= op < 0 ? 0 : op; + if (this.globalData.currentGlobalAlpha !== this.contextData.cO) { + this.canvasContext.globalAlpha = this.contextData.cO; + this.globalData.currentGlobalAlpha = this.contextData.cO; + } + }; + + CanvasRenderer.prototype.reset = function () { + if (!this.renderConfig.clearCanvas) { + this.canvasContext.restore(); + return; + } + this.contextData.reset(); + }; + + CanvasRenderer.prototype.save = function (actionFlag) { + if (!this.renderConfig.clearCanvas) { + this.canvasContext.save(); + return; + } + if (actionFlag) { + this.canvasContext.save(); + } + var props = this.contextData.cTr.props; + if (this.contextData._length <= this.contextData.cArrPos) { + this.contextData.duplicate(); + } + var i, arr = this.contextData.saved[this.contextData.cArrPos]; + for (i = 0; i < 16; i += 1) { + arr[i] = props[i]; + } + this.contextData.savedOp[this.contextData.cArrPos] = this.contextData.cO; + this.contextData.cArrPos += 1; + }; + + CanvasRenderer.prototype.restore = function (actionFlag) { + if (!this.renderConfig.clearCanvas) { + this.canvasContext.restore(); + return; + } + if (actionFlag) { + this.canvasContext.restore(); + this.globalData.blendMode = 'source-over'; + } + this.contextData.cArrPos -= 1; + var popped = this.contextData.saved[this.contextData.cArrPos]; + var i, arr = this.contextData.cTr.props; + for (i = 0; i < 16; i += 1) { + arr[i] = popped[i]; + } + this.canvasContext.setTransform(popped[0], popped[1], popped[4], popped[5], popped[12], popped[13]); + popped = this.contextData.savedOp[this.contextData.cArrPos]; + this.contextData.cO = popped; + if (this.globalData.currentGlobalAlpha !== popped) { + this.canvasContext.globalAlpha = popped; + this.globalData.currentGlobalAlpha = popped; + } + }; + + CanvasRenderer.prototype.configAnimation = function (animData) { + if (this.animationItem.wrapper) { + this.animationItem.container = createTag('canvas'); + this.animationItem.container.style.width = '100%'; + this.animationItem.container.style.height = '100%'; + //this.animationItem.container.style.transform = 'translate3d(0,0,0)'; + //this.animationItem.container.style.webkitTransform = 'translate3d(0,0,0)'; + this.animationItem.container.style.transformOrigin = this.animationItem.container.style.mozTransformOrigin = this.animationItem.container.style.webkitTransformOrigin = this.animationItem.container.style['-webkit-transform'] = "0px 0px 0px"; + this.animationItem.wrapper.appendChild(this.animationItem.container); + this.canvasContext = this.animationItem.container.getContext('2d'); + if (this.renderConfig.className) { + this.animationItem.container.setAttribute('class', this.renderConfig.className); + } + if (this.renderConfig.id) { + this.animationItem.container.setAttribute('id', this.renderConfig.id); + } + } else { + this.canvasContext = this.renderConfig.context; + } + this.data = animData; + this.layers = animData.layers; + this.transformCanvas = { + w: animData.w, + h: animData.h, + sx: 0, + sy: 0, + tx: 0, + ty: 0 + }; + this.setupGlobalData(animData, document.body); + this.globalData.canvasContext = this.canvasContext; + this.globalData.renderer = this; + this.globalData.isDashed = false; + this.globalData.progressiveLoad = this.renderConfig.progressiveLoad; + this.globalData.transformCanvas = this.transformCanvas; + this.elements = createSizedArray(animData.layers.length); + + this.updateContainerSize(); + }; + + CanvasRenderer.prototype.updateContainerSize = function () { + this.reset(); + var elementWidth, elementHeight; + if (this.animationItem.wrapper && this.animationItem.container) { + elementWidth = this.animationItem.wrapper.offsetWidth; + elementHeight = this.animationItem.wrapper.offsetHeight; + this.animationItem.container.setAttribute('width', elementWidth * this.renderConfig.dpr); + this.animationItem.container.setAttribute('height', elementHeight * this.renderConfig.dpr); + } else { + elementWidth = this.canvasContext.canvas.width * this.renderConfig.dpr; + elementHeight = this.canvasContext.canvas.height * this.renderConfig.dpr; + } + var elementRel, animationRel; + if (this.renderConfig.preserveAspectRatio.indexOf('meet') !== -1 || this.renderConfig.preserveAspectRatio.indexOf('slice') !== -1) { + var par = this.renderConfig.preserveAspectRatio.split(' '); + var fillType = par[1] || 'meet'; + var pos = par[0] || 'xMidYMid'; + var xPos = pos.substr(0, 4); + var yPos = pos.substr(4); + elementRel = elementWidth / elementHeight; + animationRel = this.transformCanvas.w / this.transformCanvas.h; + if (animationRel > elementRel && fillType === 'meet' || animationRel < elementRel && fillType === 'slice') { + this.transformCanvas.sx = elementWidth / (this.transformCanvas.w / this.renderConfig.dpr); + this.transformCanvas.sy = elementWidth / (this.transformCanvas.w / this.renderConfig.dpr); + } else { + this.transformCanvas.sx = elementHeight / (this.transformCanvas.h / this.renderConfig.dpr); + this.transformCanvas.sy = elementHeight / (this.transformCanvas.h / this.renderConfig.dpr); + } + + if (xPos === 'xMid' && ((animationRel < elementRel && fillType === 'meet') || (animationRel > elementRel && fillType === 'slice'))) { + this.transformCanvas.tx = (elementWidth - this.transformCanvas.w * (elementHeight / this.transformCanvas.h)) / 2 * this.renderConfig.dpr; + } else if (xPos === 'xMax' && ((animationRel < elementRel && fillType === 'meet') || (animationRel > elementRel && fillType === 'slice'))) { + this.transformCanvas.tx = (elementWidth - this.transformCanvas.w * (elementHeight / this.transformCanvas.h)) * this.renderConfig.dpr; + } else { + this.transformCanvas.tx = 0; + } + if (yPos === 'YMid' && ((animationRel > elementRel && fillType === 'meet') || (animationRel < elementRel && fillType === 'slice'))) { + this.transformCanvas.ty = ((elementHeight - this.transformCanvas.h * (elementWidth / this.transformCanvas.w)) / 2) * this.renderConfig.dpr; + } else if (yPos === 'YMax' && ((animationRel > elementRel && fillType === 'meet') || (animationRel < elementRel && fillType === 'slice'))) { + this.transformCanvas.ty = ((elementHeight - this.transformCanvas.h * (elementWidth / this.transformCanvas.w))) * this.renderConfig.dpr; + } else { + this.transformCanvas.ty = 0; + } + + } else if (this.renderConfig.preserveAspectRatio == 'none') { + this.transformCanvas.sx = elementWidth / (this.transformCanvas.w / this.renderConfig.dpr); + this.transformCanvas.sy = elementHeight / (this.transformCanvas.h / this.renderConfig.dpr); + this.transformCanvas.tx = 0; + this.transformCanvas.ty = 0; + } else { + this.transformCanvas.sx = this.renderConfig.dpr; + this.transformCanvas.sy = this.renderConfig.dpr; + this.transformCanvas.tx = 0; + this.transformCanvas.ty = 0; + } + this.transformCanvas.props = [this.transformCanvas.sx, 0, 0, 0, 0, this.transformCanvas.sy, 0, 0, 0, 0, 1, 0, this.transformCanvas.tx, this.transformCanvas.ty, 0, 1]; + /*var i, len = this.elements.length; + for(i=0;i= 0; i -= 1) { + if (this.elements[i]) { + this.elements[i].destroy(); + } + } + this.elements.length = 0; + this.globalData.canvasContext = null; + this.animationItem.container = null; + this.destroyed = true; + }; + + CanvasRenderer.prototype.renderFrame = function (num, forceRender) { + if ((this.renderedFrame === num && this.renderConfig.clearCanvas === true && !forceRender) || this.destroyed || num === -1) { + return; + } + this.renderedFrame = num; + this.globalData.frameNum = num - this.animationItem._isFirstFrame; + this.globalData.frameId += 1; + this.globalData._mdf = !this.renderConfig.clearCanvas || forceRender; + this.globalData.projectInterface.currentFrame = num; + + // console.log('--------'); + // console.log('NEW: ',num); + var i, len = this.layers.length; + if (!this.completeLayers) { + this.checkLayers(num); + } + + for (i = 0; i < len; i++) { + if (this.completeLayers || this.elements[i]) { + this.elements[i].prepareFrame(num - this.layers[i].st); + } + } + if (this.globalData._mdf) { + if (this.renderConfig.clearCanvas === true) { + this.canvasContext.clearRect(0, 0, this.transformCanvas.w, this.transformCanvas.h); + } else { + this.save(); + } + for (i = len - 1; i >= 0; i -= 1) { + if (this.completeLayers || this.elements[i]) { + this.elements[i].renderFrame(); + } + } + if (this.renderConfig.clearCanvas !== true) { + this.restore(); + } + } + }; + + CanvasRenderer.prototype.buildItem = function (pos) { + var elements = this.elements; + if (elements[pos] || this.layers[pos].ty == 99) { + return; + } + var element = this.createItem(this.layers[pos], this, this.globalData); + elements[pos] = element; + element.initExpressions(); + /*if(this.layers[pos].ty === 0){ + element.resize(this.globalData.transformCanvas); + }*/ + }; + + CanvasRenderer.prototype.checkPendingElements = function () { + while (this.pendingElements.length) { + var element = this.pendingElements.pop(); + element.checkParenting(); + } + }; + + CanvasRenderer.prototype.hide = function () { + this.animationItem.container.style.display = 'none'; + }; + + CanvasRenderer.prototype.show = function () { + this.animationItem.container.style.display = 'block'; + }; + + function HybridRenderer(animationItem, config) { + this.animationItem = animationItem; + this.layers = null; + this.renderedFrame = -1; + this.renderConfig = { + className: (config && config.className) || '', + imagePreserveAspectRatio: (config && config.imagePreserveAspectRatio) || 'xMidYMid slice', + hideOnTransparent: (config && config.hideOnTransparent === false) ? false : true, + filterSize: { + width: config && config.filterSize && config.filterSize.width || '400%', + height: config && config.filterSize && config.filterSize.height || '400%', + x: config && config.filterSize && config.filterSize.x || '-100%', + y: config && config.filterSize && config.filterSize.y || '-100%', + } + }; + this.globalData = { + _mdf: false, + frameNum: -1, + renderConfig: this.renderConfig + }; + this.pendingElements = []; + this.elements = []; + this.threeDElements = []; + this.destroyed = false; + this.camera = null; + this.supports3d = true; + this.rendererType = 'html'; + + } + + extendPrototype([BaseRenderer], HybridRenderer); + + HybridRenderer.prototype.buildItem = SVGRenderer.prototype.buildItem; + + HybridRenderer.prototype.checkPendingElements = function () { + while (this.pendingElements.length) { + var element = this.pendingElements.pop(); + element.checkParenting(); + } + }; + + HybridRenderer.prototype.appendElementInPos = function (element, pos) { + var newDOMElement = element.getBaseElement(); + if (!newDOMElement) { + return; + } + var layer = this.layers[pos]; + if (!layer.ddd || !this.supports3d) { + if (this.threeDElements) { + this.addTo3dContainer(newDOMElement, pos); + } else { + var i = 0; + var nextDOMElement, nextLayer, tmpDOMElement; + while (i < pos) { + if (this.elements[i] && this.elements[i] !== true && this.elements[i].getBaseElement) { + nextLayer = this.elements[i]; + tmpDOMElement = this.layers[i].ddd ? this.getThreeDContainerByPos(i) : nextLayer.getBaseElement(); + nextDOMElement = tmpDOMElement || nextDOMElement; + } + i += 1; + } + if (nextDOMElement) { + if (!layer.ddd || !this.supports3d) { + this.layerElement.insertBefore(newDOMElement, nextDOMElement); + } + } else { + if (!layer.ddd || !this.supports3d) { + this.layerElement.appendChild(newDOMElement); + } + } + } + + } else { + this.addTo3dContainer(newDOMElement, pos); + } + }; + + HybridRenderer.prototype.createShape = function (data) { + if (!this.supports3d) { + return new SVGShapeElement(data, this.globalData, this); + } + return new HShapeElement(data, this.globalData, this); + }; + + HybridRenderer.prototype.createText = function (data) { + if (!this.supports3d) { + return new SVGTextElement(data, this.globalData, this); + } + return new HTextElement(data, this.globalData, this); + }; + + HybridRenderer.prototype.createCamera = function (data) { + this.camera = new HCameraElement(data, this.globalData, this); + return this.camera; + }; + + HybridRenderer.prototype.createImage = function (data) { + if (!this.supports3d) { + return new IImageElement(data, this.globalData, this); + } + return new HImageElement(data, this.globalData, this); + }; + + HybridRenderer.prototype.createComp = function (data) { + if (!this.supports3d) { + return new SVGCompElement(data, this.globalData, this); + } + return new HCompElement(data, this.globalData, this); + + }; + + HybridRenderer.prototype.createSolid = function (data) { + if (!this.supports3d) { + return new ISolidElement(data, this.globalData, this); + } + return new HSolidElement(data, this.globalData, this); + }; + + HybridRenderer.prototype.createNull = SVGRenderer.prototype.createNull; + + HybridRenderer.prototype.getThreeDContainerByPos = function (pos) { + var i = 0, len = this.threeDElements.length; + while (i < len) { + if (this.threeDElements[i].startPos <= pos && this.threeDElements[i].endPos >= pos) { + return this.threeDElements[i].perspectiveElem; + } + i += 1; + } + }; + + HybridRenderer.prototype.createThreeDContainer = function (pos, type) { + var perspectiveElem = createTag('div'); + styleDiv(perspectiveElem); + var container = createTag('div'); + styleDiv(container); + if (type === '3d') { + perspectiveElem.style.width = this.globalData.compSize.w + 'px'; + perspectiveElem.style.height = this.globalData.compSize.h + 'px'; + perspectiveElem.style.transformOrigin = perspectiveElem.style.mozTransformOrigin = perspectiveElem.style.webkitTransformOrigin = "50% 50%"; + container.style.transform = container.style.webkitTransform = 'matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1)'; + } + + perspectiveElem.appendChild(container); + //this.resizerElem.appendChild(perspectiveElem); + var threeDContainerData = { + container: container, + perspectiveElem: perspectiveElem, + startPos: pos, + endPos: pos, + type: type + }; + this.threeDElements.push(threeDContainerData); + return threeDContainerData; + }; + + HybridRenderer.prototype.build3dContainers = function () { + var i, len = this.layers.length; + var lastThreeDContainerData; + var currentContainer = ''; + for (i = 0; i < len; i += 1) { + if (this.layers[i].ddd && this.layers[i].ty !== 3) { + if (currentContainer !== '3d') { + currentContainer = '3d'; + lastThreeDContainerData = this.createThreeDContainer(i, '3d'); + } + lastThreeDContainerData.endPos = Math.max(lastThreeDContainerData.endPos, i); + } else { + if (currentContainer !== '2d') { + currentContainer = '2d'; + lastThreeDContainerData = this.createThreeDContainer(i, '2d'); + } + lastThreeDContainerData.endPos = Math.max(lastThreeDContainerData.endPos, i); + } + } + len = this.threeDElements.length; + for (i = len - 1; i >= 0; i--) { + this.resizerElem.appendChild(this.threeDElements[i].perspectiveElem); + } + }; + + HybridRenderer.prototype.addTo3dContainer = function (elem, pos) { + var i = 0, len = this.threeDElements.length; + while (i < len) { + if (pos <= this.threeDElements[i].endPos) { + var j = this.threeDElements[i].startPos; + var nextElement; + while (j < pos) { + if (this.elements[j] && this.elements[j].getBaseElement) { + nextElement = this.elements[j].getBaseElement(); + } + j += 1; + } + if (nextElement) { + this.threeDElements[i].container.insertBefore(elem, nextElement); + } else { + this.threeDElements[i].container.appendChild(elem); + } + break; + } + i += 1; + } + }; + + HybridRenderer.prototype.configAnimation = function (animData) { + var resizerElem = createTag('div'); + var wrapper = this.animationItem.wrapper; + resizerElem.style.width = animData.w + 'px'; + resizerElem.style.height = animData.h + 'px'; + this.resizerElem = resizerElem; + styleDiv(resizerElem); + resizerElem.style.transformStyle = resizerElem.style.webkitTransformStyle = resizerElem.style.mozTransformStyle = "flat"; + if (this.renderConfig.className) { + resizerElem.setAttribute('class', this.renderConfig.className); + } + wrapper.appendChild(resizerElem); + + resizerElem.style.overflow = 'hidden'; + var svg = createNS('svg'); + svg.setAttribute('width', '1'); + svg.setAttribute('height', '1'); + styleDiv(svg); + this.resizerElem.appendChild(svg); + var defs = createNS('defs'); + svg.appendChild(defs); + this.data = animData; + //Mask animation + this.setupGlobalData(animData, svg); + this.globalData.defs = defs; + this.layers = animData.layers; + this.layerElement = this.resizerElem; + this.build3dContainers(); + this.updateContainerSize(); + }; + + HybridRenderer.prototype.destroy = function () { + this.animationItem.wrapper.innerHTML = ''; + this.animationItem.container = null; + this.globalData.defs = null; + var i, len = this.layers ? this.layers.length : 0; + for (i = 0; i < len; i++) { + this.elements[i].destroy(); + } + this.elements.length = 0; + this.destroyed = true; + this.animationItem = null; + }; + + HybridRenderer.prototype.updateContainerSize = function () { + var elementWidth = this.animationItem.wrapper.offsetWidth; + var elementHeight = this.animationItem.wrapper.offsetHeight; + var elementRel = elementWidth / elementHeight; + var animationRel = this.globalData.compSize.w / this.globalData.compSize.h; + var sx, sy, tx, ty; + if (animationRel > elementRel) { + sx = elementWidth / (this.globalData.compSize.w); + sy = elementWidth / (this.globalData.compSize.w); + tx = 0; + ty = ((elementHeight - this.globalData.compSize.h * (elementWidth / this.globalData.compSize.w)) / 2); + } else { + sx = elementHeight / (this.globalData.compSize.h); + sy = elementHeight / (this.globalData.compSize.h); + tx = (elementWidth - this.globalData.compSize.w * (elementHeight / this.globalData.compSize.h)) / 2; + ty = 0; + } + this.resizerElem.style.transform = this.resizerElem.style.webkitTransform = 'matrix3d(' + sx + ',0,0,0,0,' + sy + ',0,0,0,0,1,0,' + tx + ',' + ty + ',0,1)'; + }; + + HybridRenderer.prototype.renderFrame = SVGRenderer.prototype.renderFrame; + + HybridRenderer.prototype.hide = function () { + this.resizerElem.style.display = 'none'; + }; + + HybridRenderer.prototype.show = function () { + this.resizerElem.style.display = 'block'; + }; + + HybridRenderer.prototype.initItems = function () { + this.buildAllItems(); + if (this.camera) { + this.camera.setup(); + } else { + var cWidth = this.globalData.compSize.w; + var cHeight = this.globalData.compSize.h; + var i, len = this.threeDElements.length; + for (i = 0; i < len; i += 1) { + this.threeDElements[i].perspectiveElem.style.perspective = this.threeDElements[i].perspectiveElem.style.webkitPerspective = Math.sqrt(Math.pow(cWidth, 2) + Math.pow(cHeight, 2)) + 'px'; + } + } + }; + + HybridRenderer.prototype.searchExtraCompositions = function (assets) { + var i, len = assets.length; + var floatingContainer = createTag('div'); + for (i = 0; i < len; i += 1) { + if (assets[i].xt) { + var comp = this.createComp(assets[i], floatingContainer, this.globalData.comp, null); + comp.initExpressions(); + this.globalData.projectInterface.registerComposition(comp); + } + } + }; + + function MaskElement(data, element, globalData) { + this.data = data; + this.element = element; + this.globalData = globalData; + this.storedData = []; + this.masksProperties = this.data.masksProperties || []; + this.maskElement = null; + var defs = this.globalData.defs; + var i, len = this.masksProperties ? this.masksProperties.length : 0; + this.viewData = createSizedArray(len); + this.solidPath = ''; + + + var path, properties = this.masksProperties; + var count = 0; + var currentMasks = []; + var j, jLen; + var layerId = createElementID(); + var rect, expansor, feMorph, x; + var maskType = 'clipPath', maskRef = 'clip-path'; + for (i = 0; i < len; i++) { + if ((properties[i].mode !== 'a' && properties[i].mode !== 'n') || properties[i].inv || properties[i].o.k !== 100 || properties[i].o.x) { + maskType = 'mask'; + maskRef = 'mask'; + } + + if ((properties[i].mode == 's' || properties[i].mode == 'i') && count === 0) { + rect = createNS('rect'); + rect.setAttribute('fill', '#ffffff'); + rect.setAttribute('width', this.element.comp.data.w || 0); + rect.setAttribute('height', this.element.comp.data.h || 0); + currentMasks.push(rect); + } else { + rect = null; + } + + path = createNS('path'); + if (properties[i].mode == 'n') { + // TODO move this to a factory or to a constructor + this.viewData[i] = { + op: PropertyFactory.getProp(this.element, properties[i].o, 0, 0.01, this.element), + prop: ShapePropertyFactory.getShapeProp(this.element, properties[i], 3), + elem: path, + lastPath: '' + }; + defs.appendChild(path); + continue; + } + count += 1; + + path.setAttribute('fill', properties[i].mode === 's' ? '#000000' : '#ffffff'); + path.setAttribute('clip-rule', 'nonzero'); + var filterID; + + if (properties[i].x.k !== 0) { + maskType = 'mask'; + maskRef = 'mask'; + x = PropertyFactory.getProp(this.element, properties[i].x, 0, null, this.element); + filterID = createElementID(); + expansor = createNS('filter'); + expansor.setAttribute('id', filterID); + feMorph = createNS('feMorphology'); + feMorph.setAttribute('operator', 'erode'); + feMorph.setAttribute('in', 'SourceGraphic'); + feMorph.setAttribute('radius', '0'); + expansor.appendChild(feMorph); + defs.appendChild(expansor); + path.setAttribute('stroke', properties[i].mode === 's' ? '#000000' : '#ffffff'); + } else { + feMorph = null; + x = null; + } + + // TODO move this to a factory or to a constructor + this.storedData[i] = { + elem: path, + x: x, + expan: feMorph, + lastPath: '', + lastOperator: '', + filterId: filterID, + lastRadius: 0 + }; + if (properties[i].mode == 'i') { + jLen = currentMasks.length; + var g = createNS('g'); + for (j = 0; j < jLen; j += 1) { + g.appendChild(currentMasks[j]); + } + var mask = createNS('mask'); + mask.setAttribute('mask-type', 'alpha'); + mask.setAttribute('id', layerId + '_' + count); + mask.appendChild(path); + defs.appendChild(mask); + g.setAttribute('mask', 'url(' + locationHref + '#' + layerId + '_' + count + ')'); + + currentMasks.length = 0; + currentMasks.push(g); + } else { + currentMasks.push(path); + } + if (properties[i].inv && !this.solidPath) { + this.solidPath = this.createLayerSolidPath(); + } + // TODO move this to a factory or to a constructor + this.viewData[i] = { + elem: path, + lastPath: '', + op: PropertyFactory.getProp(this.element, properties[i].o, 0, 0.01, this.element), + prop: ShapePropertyFactory.getShapeProp(this.element, properties[i], 3), + invRect: rect + }; + if (!this.viewData[i].prop.k) { + this.drawPath(properties[i], this.viewData[i].prop.v, this.viewData[i]); + } + } + + this.maskElement = createNS(maskType); + + len = currentMasks.length; + for (i = 0; i < len; i += 1) { + this.maskElement.appendChild(currentMasks[i]); + } + + if (count > 0) { + this.maskElement.setAttribute('id', layerId); + this.element.maskedElement.setAttribute(maskRef, "url(" + locationHref + "#" + layerId + ")"); + defs.appendChild(this.maskElement); + } + if (this.viewData.length) { + this.element.addRenderableComponent(this); + } + + } + + MaskElement.prototype.getMaskProperty = function (pos) { + return this.viewData[pos].prop; + }; + + MaskElement.prototype.renderFrame = function (isFirstFrame) { + var finalMat = this.element.finalTransform.mat; + var i, len = this.masksProperties.length; + for (i = 0; i < len; i++) { + if (this.viewData[i].prop._mdf || isFirstFrame) { + this.drawPath(this.masksProperties[i], this.viewData[i].prop.v, this.viewData[i]); + } + if (this.viewData[i].op._mdf || isFirstFrame) { + this.viewData[i].elem.setAttribute('fill-opacity', this.viewData[i].op.v); + } + if (this.masksProperties[i].mode !== 'n') { + if (this.viewData[i].invRect && (this.element.finalTransform.mProp._mdf || isFirstFrame)) { + this.viewData[i].invRect.setAttribute('transform', finalMat.getInverseMatrix().to2dCSS()) + } + if (this.storedData[i].x && (this.storedData[i].x._mdf || isFirstFrame)) { + var feMorph = this.storedData[i].expan; + if (this.storedData[i].x.v < 0) { + if (this.storedData[i].lastOperator !== 'erode') { + this.storedData[i].lastOperator = 'erode'; + this.storedData[i].elem.setAttribute('filter', 'url(' + locationHref + '#' + this.storedData[i].filterId + ')'); + } + feMorph.setAttribute('radius', -this.storedData[i].x.v); + } else { + if (this.storedData[i].lastOperator !== 'dilate') { + this.storedData[i].lastOperator = 'dilate'; + this.storedData[i].elem.setAttribute('filter', null); + } + this.storedData[i].elem.setAttribute('stroke-width', this.storedData[i].x.v * 2); + + } + } + } + } + }; + + MaskElement.prototype.getMaskelement = function () { + return this.maskElement; + }; + + MaskElement.prototype.createLayerSolidPath = function () { + var path = 'M0,0 '; + path += ' h' + this.globalData.compSize.w; + path += ' v' + this.globalData.compSize.h; + path += ' h-' + this.globalData.compSize.w; + path += ' v-' + this.globalData.compSize.h + ' '; + return path; + }; + + MaskElement.prototype.drawPath = function (pathData, pathNodes, viewData) { + var pathString = " M" + pathNodes.v[0][0] + ',' + pathNodes.v[0][1]; + var i, len; + len = pathNodes._length; + for (i = 1; i < len; i += 1) { + //pathString += " C"+pathNodes.o[i-1][0]+','+pathNodes.o[i-1][1] + " "+pathNodes.i[i][0]+','+pathNodes.i[i][1] + " "+pathNodes.v[i][0]+','+pathNodes.v[i][1]; + pathString += " C" + pathNodes.o[i - 1][0] + ',' + pathNodes.o[i - 1][1] + " " + pathNodes.i[i][0] + ',' + pathNodes.i[i][1] + " " + pathNodes.v[i][0] + ',' + pathNodes.v[i][1]; + } + //pathString += " C"+pathNodes.o[i-1][0]+','+pathNodes.o[i-1][1] + " "+pathNodes.i[0][0]+','+pathNodes.i[0][1] + " "+pathNodes.v[0][0]+','+pathNodes.v[0][1]; + if (pathNodes.c && len > 1) { + pathString += " C" + pathNodes.o[i - 1][0] + ',' + pathNodes.o[i - 1][1] + " " + pathNodes.i[0][0] + ',' + pathNodes.i[0][1] + " " + pathNodes.v[0][0] + ',' + pathNodes.v[0][1]; + } + //pathNodes.__renderedString = pathString; + + if (viewData.lastPath !== pathString) { + var pathShapeValue = ''; + if (viewData.elem) { + if (pathNodes.c) { + pathShapeValue = pathData.inv ? this.solidPath + pathString : pathString; + } + viewData.elem.setAttribute('d', pathShapeValue); + } + viewData.lastPath = pathString; + } + }; + + MaskElement.prototype.destroy = function () { + this.element = null; + this.globalData = null; + this.maskElement = null; + this.data = null; + this.masksProperties = null; + }; + + /** + * @file + * Handles AE's layer parenting property. + * + */ + + function HierarchyElement() { } + + HierarchyElement.prototype = { + /** + * @function + * Initializes hierarchy properties + * + */ + initHierarchy: function () { + //element's parent list + this.hierarchy = []; + //if element is parent of another layer _isParent will be true + this._isParent = false; + this.checkParenting(); + }, + /** + * @function + * Sets layer's hierarchy. + * @param {array} hierarch + * layer's parent list + * + */ + setHierarchy: function (hierarchy) { + this.hierarchy = hierarchy; + }, + /** + * @function + * Sets layer as parent. + * + */ + setAsParent: function () { + this._isParent = true; + }, + /** + * @function + * Searches layer's parenting chain + * + */ + checkParenting: function () { + if (this.data.parent !== undefined) { + this.comp.buildElementParenting(this, this.data.parent, []); + } + } + }; + /** + * @file + * Handles element's layer frame update. + * Checks layer in point and out point + * + */ + + function FrameElement() { } + + FrameElement.prototype = { + /** + * @function + * Initializes frame related properties. + * + */ + initFrame: function () { + //set to true when inpoint is rendered + this._isFirstFrame = false; + //list of animated properties + this.dynamicProperties = []; + // If layer has been modified in current tick this will be true + this._mdf = false; + }, + /** + * @function + * Calculates all dynamic values + * + * @param {number} num + * current frame number in Layer's time + * @param {boolean} isVisible + * if layers is currently in range + * + */ + prepareProperties: function (num, isVisible) { + var i, len = this.dynamicProperties.length; + for (i = 0; i < len; i += 1) { + if (isVisible || (this._isParent && this.dynamicProperties[i].propType === 'transform')) { + this.dynamicProperties[i].getValue(); + if (this.dynamicProperties[i]._mdf) { + this.globalData._mdf = true; + this._mdf = true; + } + } + } + }, + addDynamicProperty: function (prop) { + if (this.dynamicProperties.indexOf(prop) === -1) { + this.dynamicProperties.push(prop); + } + } + }; + function TransformElement() { } + + TransformElement.prototype = { + initTransform: function () { + this.finalTransform = { + mProp: this.data.ks ? TransformPropertyFactory.getTransformProperty(this, this.data.ks, this) : { o: 0 }, + _matMdf: false, + _opMdf: false, + mat: new Matrix() + }; + if (this.data.ao) { + this.finalTransform.mProp.autoOriented = true; + } + + //TODO: check TYPE 11: Guided elements + if (this.data.ty !== 11) { + //this.createElements(); + } + }, + renderTransform: function () { + + this.finalTransform._opMdf = this.finalTransform.mProp.o._mdf || this._isFirstFrame; + this.finalTransform._matMdf = this.finalTransform.mProp._mdf || this._isFirstFrame; + + if (this.hierarchy) { + var mat; + var finalMat = this.finalTransform.mat; + var i = 0, len = this.hierarchy.length; + //Checking if any of the transformation matrices in the hierarchy chain has changed. + if (!this.finalTransform._matMdf) { + while (i < len) { + if (this.hierarchy[i].finalTransform.mProp._mdf) { + this.finalTransform._matMdf = true; + break; + } + i += 1; + } + } + + if (this.finalTransform._matMdf) { + mat = this.finalTransform.mProp.v.props; + finalMat.cloneFromProps(mat); + for (i = 0; i < len; i += 1) { + mat = this.hierarchy[i].finalTransform.mProp.v.props; + finalMat.transform(mat[0], mat[1], mat[2], mat[3], mat[4], mat[5], mat[6], mat[7], mat[8], mat[9], mat[10], mat[11], mat[12], mat[13], mat[14], mat[15]); + } + } + } + }, + globalToLocal: function (pt) { + var transforms = []; + transforms.push(this.finalTransform); + var flag = true; + var comp = this.comp; + while (flag) { + if (comp.finalTransform) { + if (comp.data.hasMask) { + transforms.splice(0, 0, comp.finalTransform); + } + comp = comp.comp; + } else { + flag = false; + } + } + var i, len = transforms.length, ptNew; + for (i = 0; i < len; i += 1) { + ptNew = transforms[i].mat.applyToPointArray(0, 0, 0); + //ptNew = transforms[i].mat.applyToPointArray(pt[0],pt[1],pt[2]); + pt = [pt[0] - ptNew[0], pt[1] - ptNew[1], 0]; + } + return pt; + }, + mHelper: new Matrix() + }; + function RenderableElement() { + + } + + RenderableElement.prototype = { + initRenderable: function () { + //layer's visibility related to inpoint and outpoint. Rename isVisible to isInRange + this.isInRange = false; + //layer's display state + this.hidden = false; + // If layer's transparency equals 0, it can be hidden + this.isTransparent = false; + //list of animated components + this.renderableComponents = []; + }, + addRenderableComponent: function (component) { + if (this.renderableComponents.indexOf(component) === -1) { + this.renderableComponents.push(component); + } + }, + removeRenderableComponent: function (component) { + if (this.renderableComponents.indexOf(component) !== -1) { + this.renderableComponents.splice(this.renderableComponents.indexOf(component), 1); + } + }, + prepareRenderableFrame: function (num) { + this.checkLayerLimits(num); + }, + checkTransparency: function () { + if (this.finalTransform.mProp.o.v <= 0) { + if (!this.isTransparent && this.globalData.renderConfig.hideOnTransparent) { + this.isTransparent = true; + this.hide(); + } + } else if (this.isTransparent) { + this.isTransparent = false; + this.show(); + } + }, + /** + * @function + * Initializes frame related properties. + * + * @param {number} num + * current frame number in Layer's time + * + */ + checkLayerLimits: function (num) { + if (this.data.ip - this.data.st <= num && this.data.op - this.data.st > num) { + if (this.isInRange !== true) { + this.globalData._mdf = true; + this._mdf = true; + this.isInRange = true; + this.show(); + } + } else { + if (this.isInRange !== false) { + this.globalData._mdf = true; + this.isInRange = false; + this.hide(); + } + } + }, + renderRenderable: function () { + var i, len = this.renderableComponents.length; + for (i = 0; i < len; i += 1) { + this.renderableComponents[i].renderFrame(this._isFirstFrame); + } + /*this.maskManager.renderFrame(this.finalTransform.mat); + this.renderableEffectsManager.renderFrame(this._isFirstFrame);*/ + }, + sourceRectAtTime: function () { + return { + top: 0, + left: 0, + width: 100, + height: 100 + }; + }, + getLayerSize: function () { + if (this.data.ty === 5) { + return { w: this.data.textData.width, h: this.data.textData.height }; + } else { + return { w: this.data.width, h: this.data.height }; + } + } + }; + function RenderableDOMElement() { } + + (function () { + var _prototype = { + initElement: function (data, globalData, comp) { + this.initFrame(); + this.initBaseData(data, globalData, comp); + this.initTransform(data, globalData, comp); + this.initHierarchy(); + this.initRenderable(); + this.initRendererElement(); + this.createContainerElements(); + this.createRenderableComponents(); + this.createContent(); + this.hide(); + }, + hide: function () { + if (!this.hidden && (!this.isInRange || this.isTransparent)) { + var elem = this.baseElement || this.layerElement; + elem.style.display = 'none'; + this.hidden = true; + } + }, + show: function () { + if (this.isInRange && !this.isTransparent) { + if (!this.data.hd) { + var elem = this.baseElement || this.layerElement; + elem.style.display = 'block'; + } + this.hidden = false; + this._isFirstFrame = true; + } + }, + renderFrame: function () { + //If it is exported as hidden (data.hd === true) no need to render + //If it is not visible no need to render + if (this.data.hd || this.hidden) { + return; + } + this.renderTransform(); + this.renderRenderable(); + this.renderElement(); + this.renderInnerContent(); + if (this._isFirstFrame) { + this._isFirstFrame = false; + } + }, + renderInnerContent: function () { }, + prepareFrame: function (num) { + this._mdf = false; + this.prepareRenderableFrame(num); + this.prepareProperties(num, this.isInRange); + this.checkTransparency(); + }, + destroy: function () { + this.innerElem = null; + this.destroyBaseElement(); + } + }; + extendPrototype([RenderableElement, createProxyFunction(_prototype)], RenderableDOMElement); + }()); + function ProcessedElement(element, position) { + this.elem = element; + this.pos = position; + } + function SVGStyleData(data, level) { + this.data = data; + this.type = data.ty; + this.d = ''; + this.lvl = level; + this._mdf = false; + this.closed = data.hd === true; + this.pElem = createNS('path'); + this.msElem = null; + } + + SVGStyleData.prototype.reset = function () { + this.d = ''; + this._mdf = false; + }; + function SVGShapeData(transformers, level, shape) { + this.caches = []; + this.styles = []; + this.transformers = transformers; + this.lStr = ''; + this.sh = shape; + this.lvl = level; + //TODO find if there are some cases where _isAnimated can be false. + // For now, since shapes add up with other shapes. They have to be calculated every time. + // One way of finding out is checking if all styles associated to this shape depend only of this shape + this._isAnimated = !!shape.k; + // TODO: commenting this for now since all shapes are animated + var i = 0, len = transformers.length; + while (i < len) { + if (transformers[i].mProps.dynamicProperties.length) { + this._isAnimated = true; + break; + } + i += 1; + } + } + + SVGShapeData.prototype.setAsAnimated = function () { + this._isAnimated = true; + } + function SVGTransformData(mProps, op, container) { + this.transform = { + mProps: mProps, + op: op, + container: container + }; + this.elements = []; + this._isAnimated = this.transform.mProps.dynamicProperties.length || this.transform.op.effectsSequence.length; + } + function SVGStrokeStyleData(elem, data, styleOb) { + this.initDynamicPropertyContainer(elem); + this.getValue = this.iterateDynamicProperties; + this.o = PropertyFactory.getProp(elem, data.o, 0, 0.01, this); + this.w = PropertyFactory.getProp(elem, data.w, 0, null, this); + this.d = new DashProperty(elem, data.d || {}, 'svg', this); + this.c = PropertyFactory.getProp(elem, data.c, 1, 255, this); + this.style = styleOb; + this._isAnimated = !!this._isAnimated; + } + + extendPrototype([DynamicPropertyContainer], SVGStrokeStyleData); + function SVGFillStyleData(elem, data, styleOb) { + this.initDynamicPropertyContainer(elem); + this.getValue = this.iterateDynamicProperties; + this.o = PropertyFactory.getProp(elem, data.o, 0, 0.01, this); + this.c = PropertyFactory.getProp(elem, data.c, 1, 255, this); + this.style = styleOb; + } + + extendPrototype([DynamicPropertyContainer], SVGFillStyleData); + function SVGGradientFillStyleData(elem, data, styleOb) { + this.initDynamicPropertyContainer(elem); + this.getValue = this.iterateDynamicProperties; + this.initGradientData(elem, data, styleOb); + } + + SVGGradientFillStyleData.prototype.initGradientData = function (elem, data, styleOb) { + this.o = PropertyFactory.getProp(elem, data.o, 0, 0.01, this); + this.s = PropertyFactory.getProp(elem, data.s, 1, null, this); + this.e = PropertyFactory.getProp(elem, data.e, 1, null, this); + this.h = PropertyFactory.getProp(elem, data.h || { k: 0 }, 0, 0.01, this); + this.a = PropertyFactory.getProp(elem, data.a || { k: 0 }, 0, degToRads, this); + this.g = new GradientProperty(elem, data.g, this); + this.style = styleOb; + this.stops = []; + this.setGradientData(styleOb.pElem, data); + this.setGradientOpacity(data, styleOb); + this._isAnimated = !!this._isAnimated; + + }; + + SVGGradientFillStyleData.prototype.setGradientData = function (pathElement, data) { + + var gradientId = createElementID(); + var gfill = createNS(data.t === 1 ? 'linearGradient' : 'radialGradient'); + gfill.setAttribute('id', gradientId); + gfill.setAttribute('spreadMethod', 'pad'); + gfill.setAttribute('gradientUnits', 'userSpaceOnUse'); + var stops = []; + var stop, j, jLen; + jLen = data.g.p * 4; + for (j = 0; j < jLen; j += 4) { + stop = createNS('stop'); + gfill.appendChild(stop); + stops.push(stop); + } + pathElement.setAttribute(data.ty === 'gf' ? 'fill' : 'stroke', 'url(' + locationHref + '#' + gradientId + ')'); + + this.gf = gfill; + this.cst = stops; + }; + + SVGGradientFillStyleData.prototype.setGradientOpacity = function (data, styleOb) { + if (this.g._hasOpacity && !this.g._collapsable) { + var stop, j, jLen; + var mask = createNS("mask"); + var maskElement = createNS('path'); + mask.appendChild(maskElement); + var opacityId = createElementID(); + var maskId = createElementID(); + mask.setAttribute('id', maskId); + var opFill = createNS(data.t === 1 ? 'linearGradient' : 'radialGradient'); + opFill.setAttribute('id', opacityId); + opFill.setAttribute('spreadMethod', 'pad'); + opFill.setAttribute('gradientUnits', 'userSpaceOnUse'); + jLen = data.g.k.k[0].s ? data.g.k.k[0].s.length : data.g.k.k.length; + var stops = this.stops; + for (j = data.g.p * 4; j < jLen; j += 2) { + stop = createNS('stop'); + stop.setAttribute('stop-color', 'rgb(255,255,255)'); + opFill.appendChild(stop); + stops.push(stop); + } + maskElement.setAttribute(data.ty === 'gf' ? 'fill' : 'stroke', 'url(' + locationHref + '#' + opacityId + ')'); + this.of = opFill; + this.ms = mask; + this.ost = stops; + this.maskId = maskId; + styleOb.msElem = maskElement; + } + }; + + extendPrototype([DynamicPropertyContainer], SVGGradientFillStyleData); + function SVGGradientStrokeStyleData(elem, data, styleOb) { + this.initDynamicPropertyContainer(elem); + this.getValue = this.iterateDynamicProperties; + this.w = PropertyFactory.getProp(elem, data.w, 0, null, this); + this.d = new DashProperty(elem, data.d || {}, 'svg', this); + this.initGradientData(elem, data, styleOb); + this._isAnimated = !!this._isAnimated; + } + + extendPrototype([SVGGradientFillStyleData, DynamicPropertyContainer], SVGGradientStrokeStyleData); + function ShapeGroupData() { + this.it = []; + this.prevViewData = []; + this.gr = createNS('g'); + } + var SVGElementsRenderer = (function () { + var _identityMatrix = new Matrix(); + var _matrixHelper = new Matrix(); + + var ob = { + createRenderFunction: createRenderFunction + } + + function createRenderFunction(data) { + var ty = data.ty; + switch (data.ty) { + case 'fl': + return renderFill; + case 'gf': + return renderGradient; + case 'gs': + return renderGradientStroke; + case 'st': + return renderStroke; + case 'sh': + case 'el': + case 'rc': + case 'sr': + return renderPath; + case 'tr': + return renderContentTransform; + } + } + + function renderContentTransform(styleData, itemData, isFirstFrame) { + if (isFirstFrame || itemData.transform.op._mdf) { + itemData.transform.container.setAttribute('opacity', itemData.transform.op.v); + } + if (isFirstFrame || itemData.transform.mProps._mdf) { + itemData.transform.container.setAttribute('transform', itemData.transform.mProps.v.to2dCSS()); + } + } + + function renderPath(styleData, itemData, isFirstFrame) { + var j, jLen, pathStringTransformed, redraw, pathNodes, l, lLen = itemData.styles.length; + var lvl = itemData.lvl; + var paths, mat, props, iterations, k; + for (l = 0; l < lLen; l += 1) { + redraw = itemData.sh._mdf || isFirstFrame; + if (itemData.styles[l].lvl < lvl) { + mat = _matrixHelper.reset(); + iterations = lvl - itemData.styles[l].lvl; + k = itemData.transformers.length - 1; + while (!redraw && iterations > 0) { + redraw = itemData.transformers[k].mProps._mdf || redraw; + iterations--; + k--; + } + if (redraw) { + iterations = lvl - itemData.styles[l].lvl; + k = itemData.transformers.length - 1; + while (iterations > 0) { + props = itemData.transformers[k].mProps.v.props; + mat.transform(props[0], props[1], props[2], props[3], props[4], props[5], props[6], props[7], props[8], props[9], props[10], props[11], props[12], props[13], props[14], props[15]); + iterations--; + k--; + } + } + } else { + mat = _identityMatrix; + } + paths = itemData.sh.paths; + jLen = paths._length; + if (redraw) { + pathStringTransformed = ''; + for (j = 0; j < jLen; j += 1) { + pathNodes = paths.shapes[j]; + if (pathNodes && pathNodes._length) { + pathStringTransformed += buildShapeString(pathNodes, pathNodes._length, pathNodes.c, mat); + } + } + itemData.caches[l] = pathStringTransformed; + } else { + pathStringTransformed = itemData.caches[l]; + } + itemData.styles[l].d += styleData.hd === true ? '' : pathStringTransformed; + itemData.styles[l]._mdf = redraw || itemData.styles[l]._mdf; + } + } + + function renderFill(styleData, itemData, isFirstFrame) { + var styleElem = itemData.style; + + if (itemData.c._mdf || isFirstFrame) { + styleElem.pElem.setAttribute('fill', 'rgb(' + bm_floor(itemData.c.v[0]) + ',' + bm_floor(itemData.c.v[1]) + ',' + bm_floor(itemData.c.v[2]) + ')'); + } + if (itemData.o._mdf || isFirstFrame) { + styleElem.pElem.setAttribute('fill-opacity', itemData.o.v); + } + }; + + function renderGradientStroke(styleData, itemData, isFirstFrame) { + renderGradient(styleData, itemData, isFirstFrame); + renderStroke(styleData, itemData, isFirstFrame); + } + + function renderGradient(styleData, itemData, isFirstFrame) { + var gfill = itemData.gf; + var hasOpacity = itemData.g._hasOpacity; + var pt1 = itemData.s.v, pt2 = itemData.e.v; + + if (itemData.o._mdf || isFirstFrame) { + var attr = styleData.ty === 'gf' ? 'fill-opacity' : 'stroke-opacity'; + itemData.style.pElem.setAttribute(attr, itemData.o.v); + } + if (itemData.s._mdf || isFirstFrame) { + var attr1 = styleData.t === 1 ? 'x1' : 'cx'; + var attr2 = attr1 === 'x1' ? 'y1' : 'cy'; + gfill.setAttribute(attr1, pt1[0]); + gfill.setAttribute(attr2, pt1[1]); + if (hasOpacity && !itemData.g._collapsable) { + itemData.of.setAttribute(attr1, pt1[0]); + itemData.of.setAttribute(attr2, pt1[1]); + } + } + var stops, i, len, stop; + if (itemData.g._cmdf || isFirstFrame) { + stops = itemData.cst; + var cValues = itemData.g.c; + len = stops.length; + for (i = 0; i < len; i += 1) { + stop = stops[i]; + stop.setAttribute('offset', cValues[i * 4] + '%'); + stop.setAttribute('stop-color', 'rgb(' + cValues[i * 4 + 1] + ',' + cValues[i * 4 + 2] + ',' + cValues[i * 4 + 3] + ')'); + } + } + if (hasOpacity && (itemData.g._omdf || isFirstFrame)) { + var oValues = itemData.g.o; + if (itemData.g._collapsable) { + stops = itemData.cst; + } else { + stops = itemData.ost; + } + len = stops.length; + for (i = 0; i < len; i += 1) { + stop = stops[i]; + if (!itemData.g._collapsable) { + stop.setAttribute('offset', oValues[i * 2] + '%'); + } + stop.setAttribute('stop-opacity', oValues[i * 2 + 1]); + } + } + if (styleData.t === 1) { + if (itemData.e._mdf || isFirstFrame) { + gfill.setAttribute('x2', pt2[0]); + gfill.setAttribute('y2', pt2[1]); + if (hasOpacity && !itemData.g._collapsable) { + itemData.of.setAttribute('x2', pt2[0]); + itemData.of.setAttribute('y2', pt2[1]); + } + } + } else { + var rad; + if (itemData.s._mdf || itemData.e._mdf || isFirstFrame) { + rad = Math.sqrt(Math.pow(pt1[0] - pt2[0], 2) + Math.pow(pt1[1] - pt2[1], 2)); + gfill.setAttribute('r', rad); + if (hasOpacity && !itemData.g._collapsable) { + itemData.of.setAttribute('r', rad); + } + } + if (itemData.e._mdf || itemData.h._mdf || itemData.a._mdf || isFirstFrame) { + if (!rad) { + rad = Math.sqrt(Math.pow(pt1[0] - pt2[0], 2) + Math.pow(pt1[1] - pt2[1], 2)); + } + var ang = Math.atan2(pt2[1] - pt1[1], pt2[0] - pt1[0]); + + var percent = itemData.h.v >= 1 ? 0.99 : itemData.h.v <= -1 ? -0.99 : itemData.h.v; + var dist = rad * percent; + var x = Math.cos(ang + itemData.a.v) * dist + pt1[0]; + var y = Math.sin(ang + itemData.a.v) * dist + pt1[1]; + gfill.setAttribute('fx', x); + gfill.setAttribute('fy', y); + if (hasOpacity && !itemData.g._collapsable) { + itemData.of.setAttribute('fx', x); + itemData.of.setAttribute('fy', y); + } + } + //gfill.setAttribute('fy','200'); + } + }; + + function renderStroke(styleData, itemData, isFirstFrame) { + var styleElem = itemData.style; + var d = itemData.d; + if (d && (d._mdf || isFirstFrame) && d.dashStr) { + styleElem.pElem.setAttribute('stroke-dasharray', d.dashStr); + styleElem.pElem.setAttribute('stroke-dashoffset', d.dashoffset[0]); + } + if (itemData.c && (itemData.c._mdf || isFirstFrame)) { + styleElem.pElem.setAttribute('stroke', 'rgb(' + bm_floor(itemData.c.v[0]) + ',' + bm_floor(itemData.c.v[1]) + ',' + bm_floor(itemData.c.v[2]) + ')'); + } + if (itemData.o._mdf || isFirstFrame) { + styleElem.pElem.setAttribute('stroke-opacity', itemData.o.v); + } + if (itemData.w._mdf || isFirstFrame) { + styleElem.pElem.setAttribute('stroke-width', itemData.w.v); + if (styleElem.msElem) { + styleElem.msElem.setAttribute('stroke-width', itemData.w.v); + } + } + }; + + return ob; + }()) + function ShapeTransformManager() { + this.sequences = {}; + this.sequenceList = []; + this.transform_key_count = 0; + } + + ShapeTransformManager.prototype = { + addTransformSequence: function (transforms) { + var i, len = transforms.length; + var key = '_'; + for (i = 0; i < len; i += 1) { + key += transforms[i].transform.key + '_'; + } + var sequence = this.sequences[key]; + if (!sequence) { + sequence = { + transforms: [].concat(transforms), + finalTransform: new Matrix(), + _mdf: false + }; + this.sequences[key] = sequence; + this.sequenceList.push(sequence); + } + return sequence; + }, + processSequence: function (sequence, isFirstFrame) { + var i = 0, len = sequence.transforms.length, _mdf = isFirstFrame; + while (i < len && !isFirstFrame) { + if (sequence.transforms[i].transform.mProps._mdf) { + _mdf = true; + break; + } + i += 1 + } + if (_mdf) { + var props; + sequence.finalTransform.reset(); + for (i = len - 1; i >= 0; i -= 1) { + props = sequence.transforms[i].transform.mProps.v.props; + sequence.finalTransform.transform(props[0], props[1], props[2], props[3], props[4], props[5], props[6], props[7], props[8], props[9], props[10], props[11], props[12], props[13], props[14], props[15]); + } + } + sequence._mdf = _mdf; + + }, + processSequences: function (isFirstFrame) { + var i, len = this.sequenceList.length; + for (i = 0; i < len; i += 1) { + this.processSequence(this.sequenceList[i], isFirstFrame); + } + + }, + getNewKey: function () { + return '_' + this.transform_key_count++; + } + } + function CVShapeData(element, data, styles, transformsManager) { + this.styledShapes = []; + this.tr = [0, 0, 0, 0, 0, 0]; + var ty = 4; + if (data.ty == 'rc') { + ty = 5; + } else if (data.ty == 'el') { + ty = 6; + } else if (data.ty == 'sr') { + ty = 7; + } + this.sh = ShapePropertyFactory.getShapeProp(element, data, ty, element); + var i, len = styles.length, styledShape; + for (i = 0; i < len; i += 1) { + if (!styles[i].closed) { + styledShape = { + transforms: transformsManager.addTransformSequence(styles[i].transforms), + trNodes: [] + } + this.styledShapes.push(styledShape); + styles[i].elements.push(styledShape); + } + } + } + + CVShapeData.prototype.setAsAnimated = SVGShapeData.prototype.setAsAnimated; + function BaseElement() { + } + + BaseElement.prototype = { + checkMasks: function () { + if (!this.data.hasMask) { + return false; + } + var i = 0, len = this.data.masksProperties.length; + while (i < len) { + if ((this.data.masksProperties[i].mode !== 'n' && this.data.masksProperties[i].cl !== false)) { + return true; + } + i += 1; + } + return false; + }, + initExpressions: function () { + this.layerInterface = LayerExpressionInterface(this); + if (this.data.hasMask && this.maskManager) { + this.layerInterface.registerMaskInterface(this.maskManager); + } + var effectsInterface = EffectsExpressionInterface.createEffectsInterface(this, this.layerInterface); + this.layerInterface.registerEffectsInterface(effectsInterface); + + if (this.data.ty === 0 || this.data.xt) { + this.compInterface = CompExpressionInterface(this); + } else if (this.data.ty === 4) { + this.layerInterface.shapeInterface = ShapeExpressionInterface(this.shapesData, this.itemsData, this.layerInterface); + this.layerInterface.content = this.layerInterface.shapeInterface; + } else if (this.data.ty === 5) { + this.layerInterface.textInterface = TextExpressionInterface(this); + this.layerInterface.text = this.layerInterface.textInterface; + } + }, + setBlendMode: function () { + var blendModeValue = getBlendMode(this.data.bm); + var elem = this.baseElement || this.layerElement; + + elem.style['mix-blend-mode'] = blendModeValue; + }, + initBaseData: function (data, globalData, comp) { + this.globalData = globalData; + this.comp = comp; + this.data = data; + this.layerId = createElementID(); + + //Stretch factor for old animations missing this property. + if (!this.data.sr) { + this.data.sr = 1; + } + // effects manager + this.effectsManager = new EffectsManager(this.data, this, this.dynamicProperties); + + }, + getType: function () { + return this.type; + } + , sourceRectAtTime: function () { } + } + function NullElement(data, globalData, comp) { + this.initFrame(); + this.initBaseData(data, globalData, comp); + this.initFrame(); + this.initTransform(data, globalData, comp); + this.initHierarchy(); + } + + NullElement.prototype.prepareFrame = function (num) { + this.prepareProperties(num, true); + }; + + NullElement.prototype.renderFrame = function () { + }; + + NullElement.prototype.getBaseElement = function () { + return null; + }; + + NullElement.prototype.destroy = function () { + }; + + NullElement.prototype.sourceRectAtTime = function () { + }; + + NullElement.prototype.hide = function () { + }; + + extendPrototype([BaseElement, TransformElement, HierarchyElement, FrameElement], NullElement); + + function SVGBaseElement() { + } + + SVGBaseElement.prototype = { + initRendererElement: function () { + this.layerElement = createNS('g'); + }, + createContainerElements: function () { + this.matteElement = createNS('g'); + this.transformedElement = this.layerElement; + this.maskedElement = this.layerElement; + this._sizeChanged = false; + var layerElementParent = null; + //If this layer acts as a mask for the following layer + var filId, fil, gg; + if (this.data.td) { + if (this.data.td == 3 || this.data.td == 1) { + var masker = createNS('mask'); + masker.setAttribute('id', this.layerId); + masker.setAttribute('mask-type', this.data.td == 3 ? 'luminance' : 'alpha'); + masker.appendChild(this.layerElement); + layerElementParent = masker; + this.globalData.defs.appendChild(masker); + // This is only for IE and Edge when mask if of type alpha + if (!featureSupport.maskType && this.data.td == 1) { + masker.setAttribute('mask-type', 'luminance'); + filId = createElementID(); + fil = filtersFactory.createFilter(filId); + this.globalData.defs.appendChild(fil); + fil.appendChild(filtersFactory.createAlphaToLuminanceFilter()); + gg = createNS('g'); + gg.appendChild(this.layerElement); + layerElementParent = gg; + masker.appendChild(gg); + gg.setAttribute('filter', 'url(' + locationHref + '#' + filId + ')'); + } + } else if (this.data.td == 2) { + var maskGroup = createNS('mask'); + maskGroup.setAttribute('id', this.layerId); + maskGroup.setAttribute('mask-type', 'alpha'); + var maskGrouper = createNS('g'); + maskGroup.appendChild(maskGrouper); + filId = createElementID(); + fil = filtersFactory.createFilter(filId); + //// + + // This solution doesn't work on Android when meta tag with viewport attribute is set + /*var feColorMatrix = createNS('feColorMatrix'); + feColorMatrix.setAttribute('type', 'matrix'); + feColorMatrix.setAttribute('color-interpolation-filters', 'sRGB'); + feColorMatrix.setAttribute('values','1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 -1 1'); + fil.appendChild(feColorMatrix);*/ + //// + var feCTr = createNS('feComponentTransfer'); + feCTr.setAttribute('in', 'SourceGraphic'); + fil.appendChild(feCTr); + var feFunc = createNS('feFuncA'); + feFunc.setAttribute('type', 'table'); + feFunc.setAttribute('tableValues', '1.0 0.0'); + feCTr.appendChild(feFunc); + //// + this.globalData.defs.appendChild(fil); + var alphaRect = createNS('rect'); + alphaRect.setAttribute('width', this.comp.data.w); + alphaRect.setAttribute('height', this.comp.data.h); + alphaRect.setAttribute('x', '0'); + alphaRect.setAttribute('y', '0'); + alphaRect.setAttribute('fill', '#ffffff'); + alphaRect.setAttribute('opacity', '0'); + maskGrouper.setAttribute('filter', 'url(' + locationHref + '#' + filId + ')'); + maskGrouper.appendChild(alphaRect); + maskGrouper.appendChild(this.layerElement); + layerElementParent = maskGrouper; + if (!featureSupport.maskType) { + maskGroup.setAttribute('mask-type', 'luminance'); + fil.appendChild(filtersFactory.createAlphaToLuminanceFilter()); + gg = createNS('g'); + maskGrouper.appendChild(alphaRect); + gg.appendChild(this.layerElement); + layerElementParent = gg; + maskGrouper.appendChild(gg); + } + this.globalData.defs.appendChild(maskGroup); + } + } else if (this.data.tt) { + this.matteElement.appendChild(this.layerElement); + layerElementParent = this.matteElement; + this.baseElement = this.matteElement; + } else { + this.baseElement = this.layerElement; + } + if (this.data.ln) { + this.layerElement.setAttribute('id', this.data.ln); + } + if (this.data.cl) { + this.layerElement.setAttribute('class', this.data.cl); + } + //Clipping compositions to hide content that exceeds boundaries. If collapsed transformations is on, component should not be clipped + if (this.data.ty === 0 && !this.data.hd) { + var cp = createNS('clipPath'); + var pt = createNS('path'); + pt.setAttribute('d', 'M0,0 L' + this.data.w + ',0' + ' L' + this.data.w + ',' + this.data.h + ' L0,' + this.data.h + 'z'); + var clipId = createElementID(); + cp.setAttribute('id', clipId); + cp.appendChild(pt); + this.globalData.defs.appendChild(cp); + + if (this.checkMasks()) { + var cpGroup = createNS('g'); + cpGroup.setAttribute('clip-path', 'url(' + locationHref + '#' + clipId + ')'); + cpGroup.appendChild(this.layerElement); + this.transformedElement = cpGroup; + if (layerElementParent) { + layerElementParent.appendChild(this.transformedElement); + } else { + this.baseElement = this.transformedElement; + } + } else { + this.layerElement.setAttribute('clip-path', 'url(' + locationHref + '#' + clipId + ')'); + } + + } + if (this.data.bm !== 0) { + this.setBlendMode(); + } + + }, + renderElement: function () { + if (this.finalTransform._matMdf) { + this.transformedElement.setAttribute('transform', this.finalTransform.mat.to2dCSS()); + } + if (this.finalTransform._opMdf) { + this.transformedElement.setAttribute('opacity', this.finalTransform.mProp.o.v); + } + }, + destroyBaseElement: function () { + this.layerElement = null; + this.matteElement = null; + this.maskManager.destroy(); + }, + getBaseElement: function () { + if (this.data.hd) { + return null; + } + return this.baseElement; + }, + createRenderableComponents: function () { + this.maskManager = new MaskElement(this.data, this, this.globalData); + this.renderableEffectsManager = new SVGEffects(this); + }, + setMatte: function (id) { + if (!this.matteElement) { + return; + } + this.matteElement.setAttribute("mask", "url(" + locationHref + "#" + id + ")"); + } + }; + function IShapeElement() { + } + + IShapeElement.prototype = { + addShapeToModifiers: function (data) { + var i, len = this.shapeModifiers.length; + for (i = 0; i < len; i += 1) { + this.shapeModifiers[i].addShape(data); + } + }, + isShapeInAnimatedModifiers: function (data) { + var i = 0, len = this.shapeModifiers.length; + while (i < len) { + if (this.shapeModifiers[i].isAnimatedWithShape(data)) { + return true; + } + } + return false; + }, + renderModifiers: function () { + if (!this.shapeModifiers.length) { + return; + } + var i, len = this.shapes.length; + for (i = 0; i < len; i += 1) { + this.shapes[i].sh.reset(); + } + + len = this.shapeModifiers.length; + for (i = len - 1; i >= 0; i -= 1) { + this.shapeModifiers[i].processShapes(this._isFirstFrame); + } + }, + lcEnum: { + '1': 'butt', + '2': 'round', + '3': 'square' + }, + ljEnum: { + '1': 'miter', + '2': 'round', + '3': 'bevel' + }, + searchProcessedElement: function (elem) { + var elements = this.processedElements; + var i = 0, len = elements.length; + while (i < len) { + if (elements[i].elem === elem) { + return elements[i].pos; + } + i += 1; + } + return 0; + }, + addProcessedElement: function (elem, pos) { + var elements = this.processedElements; + var i = elements.length; + while (i) { + i -= 1; + if (elements[i].elem === elem) { + elements[i].pos = pos; + return; + } + } + elements.push(new ProcessedElement(elem, pos)); + }, + prepareFrame: function (num) { + this.prepareRenderableFrame(num); + this.prepareProperties(num, this.isInRange); + } + }; + function ITextElement() { + } + + ITextElement.prototype.initElement = function (data, globalData, comp) { + this.lettersChangedFlag = true; + this.initFrame(); + this.initBaseData(data, globalData, comp); + this.textProperty = new TextProperty(this, data.t, this.dynamicProperties); + this.textAnimator = new TextAnimatorProperty(data.t, this.renderType, this); + this.initTransform(data, globalData, comp); + this.initHierarchy(); + this.initRenderable(); + this.initRendererElement(); + this.createContainerElements(); + this.createRenderableComponents(); + this.createContent(); + this.hide(); + this.textAnimator.searchProperties(this.dynamicProperties); + }; + + ITextElement.prototype.prepareFrame = function (num) { + this._mdf = false; + this.prepareRenderableFrame(num); + this.prepareProperties(num, this.isInRange); + if (this.textProperty._mdf || this.textProperty._isFirstFrame) { + this.buildNewText(); + this.textProperty._isFirstFrame = false; + this.textProperty._mdf = false; + } + }; + + ITextElement.prototype.createPathShape = function (matrixHelper, shapes) { + var j, jLen = shapes.length; + var k, kLen, pathNodes; + var shapeStr = ''; + for (j = 0; j < jLen; j += 1) { + pathNodes = shapes[j].ks.k; + shapeStr += buildShapeString(pathNodes, pathNodes.i.length, true, matrixHelper); + } + return shapeStr; + }; + + ITextElement.prototype.updateDocumentData = function (newData, index) { + this.textProperty.updateDocumentData(newData, index); + }; + + ITextElement.prototype.canResizeFont = function (_canResize) { + this.textProperty.canResizeFont(_canResize); + }; + + ITextElement.prototype.setMinimumFontSize = function (_fontSize) { + this.textProperty.setMinimumFontSize(_fontSize); + }; + + ITextElement.prototype.applyTextPropertiesToMatrix = function (documentData, matrixHelper, lineNumber, xPos, yPos) { + if (documentData.ps) { + matrixHelper.translate(documentData.ps[0], documentData.ps[1] + documentData.ascent, 0); + } + matrixHelper.translate(0, -documentData.ls, 0); + switch (documentData.j) { + case 1: + matrixHelper.translate(documentData.justifyOffset + (documentData.boxWidth - documentData.lineWidths[lineNumber]), 0, 0); + break; + case 2: + matrixHelper.translate(documentData.justifyOffset + (documentData.boxWidth - documentData.lineWidths[lineNumber]) / 2, 0, 0); + break; + } + matrixHelper.translate(xPos, yPos, 0); + }; + + + ITextElement.prototype.buildColor = function (colorData) { + return 'rgb(' + Math.round(colorData[0] * 255) + ',' + Math.round(colorData[1] * 255) + ',' + Math.round(colorData[2] * 255) + ')'; + }; + + ITextElement.prototype.emptyProp = new LetterProps(); + + ITextElement.prototype.destroy = function () { + + }; + function ICompElement() { } + + extendPrototype([BaseElement, TransformElement, HierarchyElement, FrameElement, RenderableDOMElement], ICompElement); + + ICompElement.prototype.initElement = function (data, globalData, comp) { + this.initFrame(); + this.initBaseData(data, globalData, comp); + this.initTransform(data, globalData, comp); + this.initRenderable(); + this.initHierarchy(); + this.initRendererElement(); + this.createContainerElements(); + this.createRenderableComponents(); + if (this.data.xt || !globalData.progressiveLoad) { + this.buildAllItems(); + } + this.hide(); + }; + + /*ICompElement.prototype.hide = function(){ + if(!this.hidden){ + this.hideElement(); + var i,len = this.elements.length; + for( i = 0; i < len; i+=1 ){ + if(this.elements[i]){ + this.elements[i].hide(); + } + } + } + };*/ + + ICompElement.prototype.prepareFrame = function (num) { + this._mdf = false; + this.prepareRenderableFrame(num); + this.prepareProperties(num, this.isInRange); + if (!this.isInRange && !this.data.xt) { + return; + } + + if (!this.tm._placeholder) { + var timeRemapped = this.tm.v; + if (timeRemapped === this.data.op) { + timeRemapped = this.data.op - 1; + } + this.renderedFrame = timeRemapped; + } else { + this.renderedFrame = num / this.data.sr; + } + var i, len = this.elements.length; + if (!this.completeLayers) { + this.checkLayers(this.renderedFrame); + } + //This iteration needs to be backwards because of how expressions connect between each other + for (i = len - 1; i >= 0; i -= 1) { + if (this.completeLayers || this.elements[i]) { + this.elements[i].prepareFrame(this.renderedFrame - this.layers[i].st); + if (this.elements[i]._mdf) { + this._mdf = true; + } + } + } + }; + + ICompElement.prototype.renderInnerContent = function () { + var i, len = this.layers.length; + for (i = 0; i < len; i += 1) { + if (this.completeLayers || this.elements[i]) { + this.elements[i].renderFrame(); + } + } + }; + + ICompElement.prototype.setElements = function (elems) { + this.elements = elems; + }; + + ICompElement.prototype.getElements = function () { + return this.elements; + }; + + ICompElement.prototype.destroyElements = function () { + var i, len = this.layers.length; + for (i = 0; i < len; i += 1) { + if (this.elements[i]) { + this.elements[i].destroy(); + } + } + }; + + ICompElement.prototype.destroy = function () { + this.destroyElements(); + this.destroyBaseElement(); + }; + + function IImageElement(data, globalData, comp) { + this.assetData = globalData.getAssetData(data.refId); + this.initElement(data, globalData, comp); + this.sourceRect = { top: 0, left: 0, width: this.assetData.w, height: this.assetData.h }; + } + + extendPrototype([BaseElement, TransformElement, SVGBaseElement, HierarchyElement, FrameElement, RenderableDOMElement], IImageElement); + + IImageElement.prototype.createContent = function () { + + var assetPath = this.globalData.getAssetsPath(this.assetData); + + this.innerElem = createNS('image'); + this.innerElem.setAttribute('width', this.assetData.w + "px"); + this.innerElem.setAttribute('height', this.assetData.h + "px"); + this.innerElem.setAttribute('preserveAspectRatio', this.assetData.pr || this.globalData.renderConfig.imagePreserveAspectRatio); + this.innerElem.setAttributeNS('http://www.w3.org/1999/xlink', 'href', assetPath); + + this.layerElement.appendChild(this.innerElem); + }; + + IImageElement.prototype.sourceRectAtTime = function () { + return this.sourceRect; + } + function ISolidElement(data, globalData, comp) { + this.initElement(data, globalData, comp); + } + extendPrototype([IImageElement], ISolidElement); + + ISolidElement.prototype.createContent = function () { + + var rect = createNS('rect'); + ////rect.style.width = this.data.sw; + ////rect.style.height = this.data.sh; + ////rect.style.fill = this.data.sc; + rect.setAttribute('width', this.data.sw); + rect.setAttribute('height', this.data.sh); + rect.setAttribute('fill', this.data.sc); + this.layerElement.appendChild(rect); + }; + function SVGCompElement(data, globalData, comp) { + this.layers = data.layers; + this.supports3d = true; + this.completeLayers = false; + this.pendingElements = []; + this.elements = this.layers ? createSizedArray(this.layers.length) : []; + //this.layerElement = createNS('g'); + this.initElement(data, globalData, comp); + this.tm = data.tm ? PropertyFactory.getProp(this, data.tm, 0, globalData.frameRate, this) : { _placeholder: true }; + } + + extendPrototype([SVGRenderer, ICompElement, SVGBaseElement], SVGCompElement); + function SVGTextElement(data, globalData, comp) { + this.textSpans = []; + this.renderType = 'svg'; + this.initElement(data, globalData, comp); + } + + extendPrototype([BaseElement, TransformElement, SVGBaseElement, HierarchyElement, FrameElement, RenderableDOMElement, ITextElement], SVGTextElement); + + SVGTextElement.prototype.createContent = function () { + + if (this.data.singleShape && !this.globalData.fontManager.chars) { + this.textContainer = createNS('text'); + } + }; + + SVGTextElement.prototype.buildTextContents = function (textArray) { + var i = 0, len = textArray.length; + var textContents = [], currentTextContent = ''; + while (i < len) { + if (textArray[i] === String.fromCharCode(13) || textArray[i] === String.fromCharCode(3)) { + textContents.push(currentTextContent); + currentTextContent = ''; + } else { + currentTextContent += textArray[i]; + } + i += 1; + } + textContents.push(currentTextContent); + return textContents; + } + + SVGTextElement.prototype.buildNewText = function () { + var i, len; + + var documentData = this.textProperty.currentData; + this.renderedLetters = createSizedArray(documentData ? documentData.l.length : 0); + if (documentData.fc) { + this.layerElement.setAttribute('fill', this.buildColor(documentData.fc)); + } else { + this.layerElement.setAttribute('fill', 'rgba(0,0,0,0)'); + } + if (documentData.sc) { + this.layerElement.setAttribute('stroke', this.buildColor(documentData.sc)); + this.layerElement.setAttribute('stroke-width', documentData.sw); + } + this.layerElement.setAttribute('font-size', documentData.finalSize); + var fontData = this.globalData.fontManager.getFontByName(documentData.f); + if (fontData.fClass) { + this.layerElement.setAttribute('class', fontData.fClass); + } else { + this.layerElement.setAttribute('font-family', fontData.fFamily); + var fWeight = documentData.fWeight, fStyle = documentData.fStyle; + this.layerElement.setAttribute('font-style', fStyle); + this.layerElement.setAttribute('font-weight', fWeight); + } + this.layerElement.setAttribute('aria-label', documentData.t); + + var letters = documentData.l || []; + var usesGlyphs = !!this.globalData.fontManager.chars; + len = letters.length; + + var tSpan; + var matrixHelper = this.mHelper; + var shapes, shapeStr = '', singleShape = this.data.singleShape; + var xPos = 0, yPos = 0, firstLine = true; + var trackingOffset = documentData.tr / 1000 * documentData.finalSize; + if (singleShape && !usesGlyphs && !documentData.sz) { + var tElement = this.textContainer; + var justify = 'start'; + switch (documentData.j) { + case 1: + justify = 'end'; + break; + case 2: + justify = 'middle'; + break; + } + tElement.setAttribute('text-anchor', justify); + tElement.setAttribute('letter-spacing', trackingOffset); + var textContent = this.buildTextContents(documentData.finalText); + len = textContent.length; + yPos = documentData.ps ? documentData.ps[1] + documentData.ascent : 0; + for (i = 0; i < len; i += 1) { + tSpan = this.textSpans[i] || createNS('tspan'); + tSpan.textContent = textContent[i]; + tSpan.setAttribute('x', 0); + tSpan.setAttribute('y', yPos); + tSpan.style.display = 'inherit'; + tElement.appendChild(tSpan); + this.textSpans[i] = tSpan; + yPos += documentData.finalLineHeight; + } + + this.layerElement.appendChild(tElement); + } else { + var cachedSpansLength = this.textSpans.length; + var shapeData, charData; + for (i = 0; i < len; i += 1) { + if (!usesGlyphs || !singleShape || i === 0) { + tSpan = cachedSpansLength > i ? this.textSpans[i] : createNS(usesGlyphs ? 'path' : 'text'); + if (cachedSpansLength <= i) { + tSpan.setAttribute('stroke-linecap', 'butt'); + tSpan.setAttribute('stroke-linejoin', 'round'); + tSpan.setAttribute('stroke-miterlimit', '4'); + this.textSpans[i] = tSpan; + this.layerElement.appendChild(tSpan); + } + tSpan.style.display = 'inherit'; + } + + matrixHelper.reset(); + matrixHelper.scale(documentData.finalSize / 100, documentData.finalSize / 100); + if (singleShape) { + if (letters[i].n) { + xPos = -trackingOffset; + yPos += documentData.yOffset; + yPos += firstLine ? 1 : 0; + firstLine = false; + } + this.applyTextPropertiesToMatrix(documentData, matrixHelper, letters[i].line, xPos, yPos); + xPos += letters[i].l || 0; + //xPos += letters[i].val === ' ' ? 0 : trackingOffset; + xPos += trackingOffset; + } + if (usesGlyphs) { + charData = this.globalData.fontManager.getCharData(documentData.finalText[i], fontData.fStyle, this.globalData.fontManager.getFontByName(documentData.f).fFamily); + shapeData = charData && charData.data || {}; + shapes = shapeData.shapes ? shapeData.shapes[0].it : []; + if (!singleShape) { + tSpan.setAttribute('d', this.createPathShape(matrixHelper, shapes)); + } else { + shapeStr += this.createPathShape(matrixHelper, shapes); + } + } else { + if (singleShape) { + tSpan.setAttribute("transform", "translate(" + matrixHelper.props[12] + "," + matrixHelper.props[13] + ")"); + } + tSpan.textContent = letters[i].val; + tSpan.setAttributeNS("http://www.w3.org/XML/1998/namespace", "xml:space", "preserve"); + } + // + } + if (singleShape && tSpan) { + tSpan.setAttribute('d', shapeStr); + } + } + while (i < this.textSpans.length) { + this.textSpans[i].style.display = 'none'; + i += 1; + } + + this._sizeChanged = true; + }; + + SVGTextElement.prototype.sourceRectAtTime = function (time) { + this.prepareFrame(this.comp.renderedFrame - this.data.st); + this.renderInnerContent(); + if (this._sizeChanged) { + this._sizeChanged = false; + var textBox = this.layerElement.getBBox(); + this.bbox = { + top: textBox.y, + left: textBox.x, + width: textBox.width, + height: textBox.height + }; + } + return this.bbox; + }; + + SVGTextElement.prototype.renderInnerContent = function () { + + if (!this.data.singleShape) { + this.textAnimator.getMeasures(this.textProperty.currentData, this.lettersChangedFlag); + if (this.lettersChangedFlag || this.textAnimator.lettersChangedFlag) { + this._sizeChanged = true; + var i, len; + var renderedLetters = this.textAnimator.renderedLetters; + + var letters = this.textProperty.currentData.l; + + len = letters.length; + var renderedLetter, textSpan; + for (i = 0; i < len; i += 1) { + if (letters[i].n) { + continue; + } + renderedLetter = renderedLetters[i]; + textSpan = this.textSpans[i]; + if (renderedLetter._mdf.m) { + textSpan.setAttribute('transform', renderedLetter.m); + } + if (renderedLetter._mdf.o) { + textSpan.setAttribute('opacity', renderedLetter.o); + } + if (renderedLetter._mdf.sw) { + textSpan.setAttribute('stroke-width', renderedLetter.sw); + } + if (renderedLetter._mdf.sc) { + textSpan.setAttribute('stroke', renderedLetter.sc); + } + if (renderedLetter._mdf.fc) { + textSpan.setAttribute('fill', renderedLetter.fc); + } + } + } + } + }; + + function SVGShapeElement(data, globalData, comp) { + //List of drawable elements + this.shapes = []; + // Full shape data + this.shapesData = data.shapes; + //List of styles that will be applied to shapes + this.stylesList = []; + //List of modifiers that will be applied to shapes + this.shapeModifiers = []; + //List of items in shape tree + this.itemsData = []; + //List of items in previous shape tree + this.processedElements = []; + // List of animated components + this.animatedContents = []; + this.initElement(data, globalData, comp); + //Moving any property that doesn't get too much access after initialization because of v8 way of handling more than 10 properties. + // List of elements that have been created + this.prevViewData = []; + //Moving any property that doesn't get too much access after initialization because of v8 way of handling more than 10 properties. + } + + extendPrototype([BaseElement, TransformElement, SVGBaseElement, IShapeElement, HierarchyElement, FrameElement, RenderableDOMElement], SVGShapeElement); + + SVGShapeElement.prototype.initSecondaryElement = function () { + }; + + SVGShapeElement.prototype.identityMatrix = new Matrix(); + + SVGShapeElement.prototype.buildExpressionInterface = function () { }; + + SVGShapeElement.prototype.createContent = function () { + this.searchShapes(this.shapesData, this.itemsData, this.prevViewData, this.layerElement, 0, [], true); + this.filterUniqueShapes(); + }; + + /* + This method searches for multiple shapes that affect a single element and one of them is animated + */ + SVGShapeElement.prototype.filterUniqueShapes = function () { + var i, len = this.shapes.length, shape; + var j, jLen = this.stylesList.length; + var style, count = 0; + var tempShapes = []; + var areAnimated = false; + for (j = 0; j < jLen; j += 1) { + style = this.stylesList[j]; + areAnimated = false; + tempShapes.length = 0; + for (i = 0; i < len; i += 1) { + shape = this.shapes[i]; + if (shape.styles.indexOf(style) !== -1) { + tempShapes.push(shape); + areAnimated = shape._isAnimated || areAnimated; + } + } + if (tempShapes.length > 1 && areAnimated) { + this.setShapesAsAnimated(tempShapes); + } + } + } + + SVGShapeElement.prototype.setShapesAsAnimated = function (shapes) { + var i, len = shapes.length; + for (i = 0; i < len; i += 1) { + shapes[i].setAsAnimated(); + } + } + + SVGShapeElement.prototype.createStyleElement = function (data, level) { + //TODO: prevent drawing of hidden styles + var elementData; + var styleOb = new SVGStyleData(data, level); + + var pathElement = styleOb.pElem; + if (data.ty === 'st') { + elementData = new SVGStrokeStyleData(this, data, styleOb); + } else if (data.ty === 'fl') { + elementData = new SVGFillStyleData(this, data, styleOb); + } else if (data.ty === 'gf' || data.ty === 'gs') { + var gradientConstructor = data.ty === 'gf' ? SVGGradientFillStyleData : SVGGradientStrokeStyleData; + elementData = new gradientConstructor(this, data, styleOb); + this.globalData.defs.appendChild(elementData.gf); + if (elementData.maskId) { + this.globalData.defs.appendChild(elementData.ms); + this.globalData.defs.appendChild(elementData.of); + pathElement.setAttribute('mask', 'url(' + locationHref + '#' + elementData.maskId + ')'); + } + } + + if (data.ty === 'st' || data.ty === 'gs') { + pathElement.setAttribute('stroke-linecap', this.lcEnum[data.lc] || 'round'); + pathElement.setAttribute('stroke-linejoin', this.ljEnum[data.lj] || 'round'); + pathElement.setAttribute('fill-opacity', '0'); + if (data.lj === 1) { + pathElement.setAttribute('stroke-miterlimit', data.ml); + } + } + + if (data.r === 2) { + pathElement.setAttribute('fill-rule', 'evenodd'); + } + + if (data.ln) { + pathElement.setAttribute('id', data.ln); + } + if (data.cl) { + pathElement.setAttribute('class', data.cl); + } + if (data.bm) { + pathElement.style['mix-blend-mode'] = getBlendMode(data.bm); + } + this.stylesList.push(styleOb); + this.addToAnimatedContents(data, elementData); + return elementData; + }; + + SVGShapeElement.prototype.createGroupElement = function (data) { + var elementData = new ShapeGroupData(); + if (data.ln) { + elementData.gr.setAttribute('id', data.ln); + } + if (data.cl) { + elementData.gr.setAttribute('class', data.cl); + } + if (data.bm) { + elementData.gr.style['mix-blend-mode'] = getBlendMode(data.bm); + } + return elementData; + }; + + SVGShapeElement.prototype.createTransformElement = function (data, container) { + var transformProperty = TransformPropertyFactory.getTransformProperty(this, data, this); + var elementData = new SVGTransformData(transformProperty, transformProperty.o, container); + this.addToAnimatedContents(data, elementData); + return elementData; + }; + + SVGShapeElement.prototype.createShapeElement = function (data, ownTransformers, level) { + var ty = 4; + if (data.ty === 'rc') { + ty = 5; + } else if (data.ty === 'el') { + ty = 6; + } else if (data.ty === 'sr') { + ty = 7; + } + var shapeProperty = ShapePropertyFactory.getShapeProp(this, data, ty, this); + var elementData = new SVGShapeData(ownTransformers, level, shapeProperty); + this.shapes.push(elementData); + this.addShapeToModifiers(elementData); + this.addToAnimatedContents(data, elementData); + return elementData; + }; + + SVGShapeElement.prototype.addToAnimatedContents = function (data, element) { + var i = 0, len = this.animatedContents.length; + while (i < len) { + if (this.animatedContents[i].element === element) { + return; + } + i += 1; + } + this.animatedContents.push({ + fn: SVGElementsRenderer.createRenderFunction(data), + element: element, + data: data + }); + }; + + SVGShapeElement.prototype.setElementStyles = function (elementData) { + var arr = elementData.styles; + var j, jLen = this.stylesList.length; + for (j = 0; j < jLen; j += 1) { + if (!this.stylesList[j].closed) { + arr.push(this.stylesList[j]); + } + } + }; + + SVGShapeElement.prototype.reloadShapes = function () { + this._isFirstFrame = true; + var i, len = this.itemsData.length; + for (i = 0; i < len; i += 1) { + this.prevViewData[i] = this.itemsData[i]; + } + this.searchShapes(this.shapesData, this.itemsData, this.prevViewData, this.layerElement, 0, [], true); + this.filterUniqueShapes(); + len = this.dynamicProperties.length; + for (i = 0; i < len; i += 1) { + this.dynamicProperties[i].getValue(); + } + this.renderModifiers(); + }; + + SVGShapeElement.prototype.searchShapes = function (arr, itemsData, prevViewData, container, level, transformers, render) { + var ownTransformers = [].concat(transformers); + var i, len = arr.length - 1; + var j, jLen; + var ownStyles = [], ownModifiers = [], styleOb, currentTransform, modifier, processedPos; + for (i = len; i >= 0; i -= 1) { + processedPos = this.searchProcessedElement(arr[i]); + if (!processedPos) { + arr[i]._render = render; + } else { + itemsData[i] = prevViewData[processedPos - 1]; + } + if (arr[i].ty == 'fl' || arr[i].ty == 'st' || arr[i].ty == 'gf' || arr[i].ty == 'gs') { + if (!processedPos) { + itemsData[i] = this.createStyleElement(arr[i], level); + } else { + itemsData[i].style.closed = false; + } + if (arr[i]._render) { + container.appendChild(itemsData[i].style.pElem); + } + ownStyles.push(itemsData[i].style); + } else if (arr[i].ty == 'gr') { + if (!processedPos) { + itemsData[i] = this.createGroupElement(arr[i]); + } else { + jLen = itemsData[i].it.length; + for (j = 0; j < jLen; j += 1) { + itemsData[i].prevViewData[j] = itemsData[i].it[j]; + } + } + this.searchShapes(arr[i].it, itemsData[i].it, itemsData[i].prevViewData, itemsData[i].gr, level + 1, ownTransformers, render); + if (arr[i]._render) { + container.appendChild(itemsData[i].gr); + } + } else if (arr[i].ty == 'tr') { + if (!processedPos) { + itemsData[i] = this.createTransformElement(arr[i], container); + } + currentTransform = itemsData[i].transform; + ownTransformers.push(currentTransform); + } else if (arr[i].ty == 'sh' || arr[i].ty == 'rc' || arr[i].ty == 'el' || arr[i].ty == 'sr') { + if (!processedPos) { + itemsData[i] = this.createShapeElement(arr[i], ownTransformers, level); + } + this.setElementStyles(itemsData[i]); + + } else if (arr[i].ty == 'tm' || arr[i].ty == 'rd' || arr[i].ty == 'ms') { + if (!processedPos) { + modifier = ShapeModifiers.getModifier(arr[i].ty); + modifier.init(this, arr[i]); + itemsData[i] = modifier; + this.shapeModifiers.push(modifier); + } else { + modifier = itemsData[i]; + modifier.closed = false; + } + ownModifiers.push(modifier); + } else if (arr[i].ty == 'rp') { + if (!processedPos) { + modifier = ShapeModifiers.getModifier(arr[i].ty); + itemsData[i] = modifier; + modifier.init(this, arr, i, itemsData); + this.shapeModifiers.push(modifier); + render = false; + } else { + modifier = itemsData[i]; + modifier.closed = true; + } + ownModifiers.push(modifier); + } + this.addProcessedElement(arr[i], i + 1); + } + len = ownStyles.length; + for (i = 0; i < len; i += 1) { + ownStyles[i].closed = true; + } + len = ownModifiers.length; + for (i = 0; i < len; i += 1) { + ownModifiers[i].closed = true; + } + }; + + SVGShapeElement.prototype.renderInnerContent = function () { + this.renderModifiers(); + var i, len = this.stylesList.length; + for (i = 0; i < len; i += 1) { + this.stylesList[i].reset(); + } + this.renderShape(); + + for (i = 0; i < len; i += 1) { + if (this.stylesList[i]._mdf || this._isFirstFrame) { + if (this.stylesList[i].msElem) { + this.stylesList[i].msElem.setAttribute('d', this.stylesList[i].d); + //Adding M0 0 fixes same mask bug on all browsers + this.stylesList[i].d = 'M0 0' + this.stylesList[i].d; + } + this.stylesList[i].pElem.setAttribute('d', this.stylesList[i].d || 'M0 0'); + } + } + }; + + SVGShapeElement.prototype.renderShape = function () { + var i, len = this.animatedContents.length; + var animatedContent; + for (i = 0; i < len; i += 1) { + animatedContent = this.animatedContents[i]; + if ((this._isFirstFrame || animatedContent.element._isAnimated) && animatedContent.data !== true) { + animatedContent.fn(animatedContent.data, animatedContent.element, this._isFirstFrame); + } + } + } + + SVGShapeElement.prototype.destroy = function () { + this.destroyBaseElement(); + this.shapesData = null; + this.itemsData = null; + }; + + function SVGTintFilter(filter, filterManager) { + this.filterManager = filterManager; + var feColorMatrix = createNS('feColorMatrix'); + feColorMatrix.setAttribute('type', 'matrix'); + feColorMatrix.setAttribute('color-interpolation-filters', 'linearRGB'); + feColorMatrix.setAttribute('values', '0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0'); + feColorMatrix.setAttribute('result', 'f1'); + filter.appendChild(feColorMatrix); + feColorMatrix = createNS('feColorMatrix'); + feColorMatrix.setAttribute('type', 'matrix'); + feColorMatrix.setAttribute('color-interpolation-filters', 'sRGB'); + feColorMatrix.setAttribute('values', '1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0'); + feColorMatrix.setAttribute('result', 'f2'); + filter.appendChild(feColorMatrix); + this.matrixFilter = feColorMatrix; + if (filterManager.effectElements[2].p.v !== 100 || filterManager.effectElements[2].p.k) { + var feMerge = createNS('feMerge'); + filter.appendChild(feMerge); + var feMergeNode; + feMergeNode = createNS('feMergeNode'); + feMergeNode.setAttribute('in', 'SourceGraphic'); + feMerge.appendChild(feMergeNode); + feMergeNode = createNS('feMergeNode'); + feMergeNode.setAttribute('in', 'f2'); + feMerge.appendChild(feMergeNode); + } + } + + SVGTintFilter.prototype.renderFrame = function (forceRender) { + if (forceRender || this.filterManager._mdf) { + var colorBlack = this.filterManager.effectElements[0].p.v; + var colorWhite = this.filterManager.effectElements[1].p.v; + var opacity = this.filterManager.effectElements[2].p.v / 100; + this.matrixFilter.setAttribute('values', (colorWhite[0] - colorBlack[0]) + ' 0 0 0 ' + colorBlack[0] + ' ' + (colorWhite[1] - colorBlack[1]) + ' 0 0 0 ' + colorBlack[1] + ' ' + (colorWhite[2] - colorBlack[2]) + ' 0 0 0 ' + colorBlack[2] + ' 0 0 0 ' + opacity + ' 0'); + } + }; + function SVGFillFilter(filter, filterManager) { + this.filterManager = filterManager; + var feColorMatrix = createNS('feColorMatrix'); + feColorMatrix.setAttribute('type', 'matrix'); + feColorMatrix.setAttribute('color-interpolation-filters', 'sRGB'); + feColorMatrix.setAttribute('values', '1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0'); + filter.appendChild(feColorMatrix); + this.matrixFilter = feColorMatrix; + } + SVGFillFilter.prototype.renderFrame = function (forceRender) { + if (forceRender || this.filterManager._mdf) { + var color = this.filterManager.effectElements[2].p.v; + var opacity = this.filterManager.effectElements[6].p.v; + this.matrixFilter.setAttribute('values', '0 0 0 0 ' + color[0] + ' 0 0 0 0 ' + color[1] + ' 0 0 0 0 ' + color[2] + ' 0 0 0 ' + opacity + ' 0'); + } + }; + function SVGGaussianBlurEffect(filter, filterManager) { + // Outset the filter region by 100% on all sides to accommodate blur expansion. + filter.setAttribute('x', '-100%'); + filter.setAttribute('y', '-100%'); + filter.setAttribute('width', '300%'); + filter.setAttribute('height', '300%'); + + this.filterManager = filterManager; + var feGaussianBlur = createNS('feGaussianBlur'); + filter.appendChild(feGaussianBlur); + this.feGaussianBlur = feGaussianBlur; + } + + SVGGaussianBlurEffect.prototype.renderFrame = function (forceRender) { + if (forceRender || this.filterManager._mdf) { + // Empirical value, matching AE's blur appearance. + var kBlurrinessToSigma = 0.3; + var sigma = this.filterManager.effectElements[0].p.v * kBlurrinessToSigma; + + // Dimensions mapping: + // + // 1 -> horizontal & vertical + // 2 -> horizontal only + // 3 -> vertical only + // + var dimensions = this.filterManager.effectElements[1].p.v; + var sigmaX = (dimensions == 3) ? 0 : sigma; + var sigmaY = (dimensions == 2) ? 0 : sigma; + + this.feGaussianBlur.setAttribute('stdDeviation', sigmaX + " " + sigmaY); + + // Repeat edges mapping: + // + // 0 -> off -> duplicate + // 1 -> on -> wrap + var edgeMode = (this.filterManager.effectElements[2].p.v == 1) ? 'wrap' : 'duplicate'; + this.feGaussianBlur.setAttribute('edgeMode', edgeMode); + } + } + function SVGStrokeEffect(elem, filterManager) { + this.initialized = false; + this.filterManager = filterManager; + this.elem = elem; + this.paths = []; + } + + SVGStrokeEffect.prototype.initialize = function () { + + var elemChildren = this.elem.layerElement.children || this.elem.layerElement.childNodes; + var path, groupPath, i, len; + if (this.filterManager.effectElements[1].p.v === 1) { + len = this.elem.maskManager.masksProperties.length; + i = 0; + } else { + i = this.filterManager.effectElements[0].p.v - 1; + len = i + 1; + } + groupPath = createNS('g'); + groupPath.setAttribute('fill', 'none'); + groupPath.setAttribute('stroke-linecap', 'round'); + groupPath.setAttribute('stroke-dashoffset', 1); + for (i; i < len; i += 1) { + path = createNS('path'); + groupPath.appendChild(path); + this.paths.push({ p: path, m: i }); + } + if (this.filterManager.effectElements[10].p.v === 3) { + var mask = createNS('mask'); + var id = createElementID(); + mask.setAttribute('id', id); + mask.setAttribute('mask-type', 'alpha'); + mask.appendChild(groupPath); + this.elem.globalData.defs.appendChild(mask); + var g = createNS('g'); + g.setAttribute('mask', 'url(' + locationHref + '#' + id + ')'); + while (elemChildren[0]) { + g.appendChild(elemChildren[0]); + } + this.elem.layerElement.appendChild(g); + this.masker = mask; + groupPath.setAttribute('stroke', '#fff'); + } else if (this.filterManager.effectElements[10].p.v === 1 || this.filterManager.effectElements[10].p.v === 2) { + if (this.filterManager.effectElements[10].p.v === 2) { + elemChildren = this.elem.layerElement.children || this.elem.layerElement.childNodes; + while (elemChildren.length) { + this.elem.layerElement.removeChild(elemChildren[0]); + } + } + this.elem.layerElement.appendChild(groupPath); + this.elem.layerElement.removeAttribute('mask'); + groupPath.setAttribute('stroke', '#fff'); + } + this.initialized = true; + this.pathMasker = groupPath; + }; + + SVGStrokeEffect.prototype.renderFrame = function (forceRender) { + if (!this.initialized) { + this.initialize(); + } + var i, len = this.paths.length; + var mask, path; + for (i = 0; i < len; i += 1) { + if (this.paths[i].m === -1) { + continue; + } + mask = this.elem.maskManager.viewData[this.paths[i].m]; + path = this.paths[i].p; + if (forceRender || this.filterManager._mdf || mask.prop._mdf) { + path.setAttribute('d', mask.lastPath); + } + if (forceRender || this.filterManager.effectElements[9].p._mdf || this.filterManager.effectElements[4].p._mdf || this.filterManager.effectElements[7].p._mdf || this.filterManager.effectElements[8].p._mdf || mask.prop._mdf) { + var dasharrayValue; + if (this.filterManager.effectElements[7].p.v !== 0 || this.filterManager.effectElements[8].p.v !== 100) { + var s = Math.min(this.filterManager.effectElements[7].p.v, this.filterManager.effectElements[8].p.v) / 100; + var e = Math.max(this.filterManager.effectElements[7].p.v, this.filterManager.effectElements[8].p.v) / 100; + var l = path.getTotalLength(); + dasharrayValue = '0 0 0 ' + l * s + ' '; + var lineLength = l * (e - s); + var segment = 1 + this.filterManager.effectElements[4].p.v * 2 * this.filterManager.effectElements[9].p.v / 100; + var units = Math.floor(lineLength / segment); + var j; + for (j = 0; j < units; j += 1) { + dasharrayValue += '1 ' + this.filterManager.effectElements[4].p.v * 2 * this.filterManager.effectElements[9].p.v / 100 + ' '; + } + dasharrayValue += '0 ' + l * 10 + ' 0 0'; + } else { + dasharrayValue = '1 ' + this.filterManager.effectElements[4].p.v * 2 * this.filterManager.effectElements[9].p.v / 100; + } + path.setAttribute('stroke-dasharray', dasharrayValue); + } + } + if (forceRender || this.filterManager.effectElements[4].p._mdf) { + this.pathMasker.setAttribute('stroke-width', this.filterManager.effectElements[4].p.v * 2); + } + + if (forceRender || this.filterManager.effectElements[6].p._mdf) { + this.pathMasker.setAttribute('opacity', this.filterManager.effectElements[6].p.v); + } + if (this.filterManager.effectElements[10].p.v === 1 || this.filterManager.effectElements[10].p.v === 2) { + if (forceRender || this.filterManager.effectElements[3].p._mdf) { + var color = this.filterManager.effectElements[3].p.v; + this.pathMasker.setAttribute('stroke', 'rgb(' + bm_floor(color[0] * 255) + ',' + bm_floor(color[1] * 255) + ',' + bm_floor(color[2] * 255) + ')'); + } + } + }; + function SVGTritoneFilter(filter, filterManager) { + this.filterManager = filterManager; + var feColorMatrix = createNS('feColorMatrix'); + feColorMatrix.setAttribute('type', 'matrix'); + feColorMatrix.setAttribute('color-interpolation-filters', 'linearRGB'); + feColorMatrix.setAttribute('values', '0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0'); + feColorMatrix.setAttribute('result', 'f1'); + filter.appendChild(feColorMatrix); + var feComponentTransfer = createNS('feComponentTransfer'); + feComponentTransfer.setAttribute('color-interpolation-filters', 'sRGB'); + filter.appendChild(feComponentTransfer); + this.matrixFilter = feComponentTransfer; + var feFuncR = createNS('feFuncR'); + feFuncR.setAttribute('type', 'table'); + feComponentTransfer.appendChild(feFuncR); + this.feFuncR = feFuncR; + var feFuncG = createNS('feFuncG'); + feFuncG.setAttribute('type', 'table'); + feComponentTransfer.appendChild(feFuncG); + this.feFuncG = feFuncG; + var feFuncB = createNS('feFuncB'); + feFuncB.setAttribute('type', 'table'); + feComponentTransfer.appendChild(feFuncB); + this.feFuncB = feFuncB; + } + + SVGTritoneFilter.prototype.renderFrame = function (forceRender) { + if (forceRender || this.filterManager._mdf) { + var color1 = this.filterManager.effectElements[0].p.v; + var color2 = this.filterManager.effectElements[1].p.v; + var color3 = this.filterManager.effectElements[2].p.v; + var tableR = color3[0] + ' ' + color2[0] + ' ' + color1[0]; + var tableG = color3[1] + ' ' + color2[1] + ' ' + color1[1]; + var tableB = color3[2] + ' ' + color2[2] + ' ' + color1[2]; + this.feFuncR.setAttribute('tableValues', tableR); + this.feFuncG.setAttribute('tableValues', tableG); + this.feFuncB.setAttribute('tableValues', tableB); + //var opacity = this.filterManager.effectElements[2].p.v/100; + //this.matrixFilter.setAttribute('values',(colorWhite[0]- colorBlack[0])+' 0 0 0 '+ colorBlack[0] +' '+ (colorWhite[1]- colorBlack[1]) +' 0 0 0 '+ colorBlack[1] +' '+ (colorWhite[2]- colorBlack[2]) +' 0 0 0 '+ colorBlack[2] +' 0 0 0 ' + opacity + ' 0'); + } + }; + function SVGProLevelsFilter(filter, filterManager) { + this.filterManager = filterManager; + var effectElements = this.filterManager.effectElements; + var feComponentTransfer = createNS('feComponentTransfer'); + var feFuncR, feFuncG, feFuncB; + + if (effectElements[10].p.k || effectElements[10].p.v !== 0 || effectElements[11].p.k || effectElements[11].p.v !== 1 || effectElements[12].p.k || effectElements[12].p.v !== 1 || effectElements[13].p.k || effectElements[13].p.v !== 0 || effectElements[14].p.k || effectElements[14].p.v !== 1) { + this.feFuncR = this.createFeFunc('feFuncR', feComponentTransfer); + } + if (effectElements[17].p.k || effectElements[17].p.v !== 0 || effectElements[18].p.k || effectElements[18].p.v !== 1 || effectElements[19].p.k || effectElements[19].p.v !== 1 || effectElements[20].p.k || effectElements[20].p.v !== 0 || effectElements[21].p.k || effectElements[21].p.v !== 1) { + this.feFuncG = this.createFeFunc('feFuncG', feComponentTransfer); + } + if (effectElements[24].p.k || effectElements[24].p.v !== 0 || effectElements[25].p.k || effectElements[25].p.v !== 1 || effectElements[26].p.k || effectElements[26].p.v !== 1 || effectElements[27].p.k || effectElements[27].p.v !== 0 || effectElements[28].p.k || effectElements[28].p.v !== 1) { + this.feFuncB = this.createFeFunc('feFuncB', feComponentTransfer); + } + if (effectElements[31].p.k || effectElements[31].p.v !== 0 || effectElements[32].p.k || effectElements[32].p.v !== 1 || effectElements[33].p.k || effectElements[33].p.v !== 1 || effectElements[34].p.k || effectElements[34].p.v !== 0 || effectElements[35].p.k || effectElements[35].p.v !== 1) { + this.feFuncA = this.createFeFunc('feFuncA', feComponentTransfer); + } + + if (this.feFuncR || this.feFuncG || this.feFuncB || this.feFuncA) { + feComponentTransfer.setAttribute('color-interpolation-filters', 'sRGB'); + filter.appendChild(feComponentTransfer); + feComponentTransfer = createNS('feComponentTransfer'); + } + + if (effectElements[3].p.k || effectElements[3].p.v !== 0 || effectElements[4].p.k || effectElements[4].p.v !== 1 || effectElements[5].p.k || effectElements[5].p.v !== 1 || effectElements[6].p.k || effectElements[6].p.v !== 0 || effectElements[7].p.k || effectElements[7].p.v !== 1) { + + feComponentTransfer.setAttribute('color-interpolation-filters', 'sRGB'); + filter.appendChild(feComponentTransfer); + this.feFuncRComposed = this.createFeFunc('feFuncR', feComponentTransfer); + this.feFuncGComposed = this.createFeFunc('feFuncG', feComponentTransfer); + this.feFuncBComposed = this.createFeFunc('feFuncB', feComponentTransfer); + } + } + + SVGProLevelsFilter.prototype.createFeFunc = function (type, feComponentTransfer) { + var feFunc = createNS(type); + feFunc.setAttribute('type', 'table'); + feComponentTransfer.appendChild(feFunc); + return feFunc; + }; + + SVGProLevelsFilter.prototype.getTableValue = function (inputBlack, inputWhite, gamma, outputBlack, outputWhite) { + var cnt = 0; + var segments = 256; + var perc; + var min = Math.min(inputBlack, inputWhite); + var max = Math.max(inputBlack, inputWhite); + var table = Array.call(null, { length: segments }); + var colorValue; + var pos = 0; + var outputDelta = outputWhite - outputBlack; + var inputDelta = inputWhite - inputBlack; + while (cnt <= 256) { + perc = cnt / 256; + if (perc <= min) { + colorValue = inputDelta < 0 ? outputWhite : outputBlack; + } else if (perc >= max) { + colorValue = inputDelta < 0 ? outputBlack : outputWhite; + } else { + colorValue = (outputBlack + outputDelta * Math.pow((perc - inputBlack) / inputDelta, 1 / gamma)); + } + table[pos++] = colorValue; + cnt += 256 / (segments - 1); + } + return table.join(' '); + }; + + SVGProLevelsFilter.prototype.renderFrame = function (forceRender) { + if (forceRender || this.filterManager._mdf) { + var val, cnt, perc, bezier; + var effectElements = this.filterManager.effectElements; + if (this.feFuncRComposed && (forceRender || effectElements[3].p._mdf || effectElements[4].p._mdf || effectElements[5].p._mdf || effectElements[6].p._mdf || effectElements[7].p._mdf)) { + val = this.getTableValue(effectElements[3].p.v, effectElements[4].p.v, effectElements[5].p.v, effectElements[6].p.v, effectElements[7].p.v); + this.feFuncRComposed.setAttribute('tableValues', val); + this.feFuncGComposed.setAttribute('tableValues', val); + this.feFuncBComposed.setAttribute('tableValues', val); + } + + + if (this.feFuncR && (forceRender || effectElements[10].p._mdf || effectElements[11].p._mdf || effectElements[12].p._mdf || effectElements[13].p._mdf || effectElements[14].p._mdf)) { + val = this.getTableValue(effectElements[10].p.v, effectElements[11].p.v, effectElements[12].p.v, effectElements[13].p.v, effectElements[14].p.v); + this.feFuncR.setAttribute('tableValues', val); + } + + if (this.feFuncG && (forceRender || effectElements[17].p._mdf || effectElements[18].p._mdf || effectElements[19].p._mdf || effectElements[20].p._mdf || effectElements[21].p._mdf)) { + val = this.getTableValue(effectElements[17].p.v, effectElements[18].p.v, effectElements[19].p.v, effectElements[20].p.v, effectElements[21].p.v); + this.feFuncG.setAttribute('tableValues', val); + } + + if (this.feFuncB && (forceRender || effectElements[24].p._mdf || effectElements[25].p._mdf || effectElements[26].p._mdf || effectElements[27].p._mdf || effectElements[28].p._mdf)) { + val = this.getTableValue(effectElements[24].p.v, effectElements[25].p.v, effectElements[26].p.v, effectElements[27].p.v, effectElements[28].p.v); + this.feFuncB.setAttribute('tableValues', val); + } + + if (this.feFuncA && (forceRender || effectElements[31].p._mdf || effectElements[32].p._mdf || effectElements[33].p._mdf || effectElements[34].p._mdf || effectElements[35].p._mdf)) { + val = this.getTableValue(effectElements[31].p.v, effectElements[32].p.v, effectElements[33].p.v, effectElements[34].p.v, effectElements[35].p.v); + this.feFuncA.setAttribute('tableValues', val); + } + + } + }; + function SVGDropShadowEffect(filter, filterManager) { + var filterSize = filterManager.container.globalData.renderConfig.filterSize + filter.setAttribute('x', filterSize.x); + filter.setAttribute('y', filterSize.y); + filter.setAttribute('width', filterSize.width); + filter.setAttribute('height', filterSize.height); + this.filterManager = filterManager; + + var feGaussianBlur = createNS('feGaussianBlur'); + feGaussianBlur.setAttribute('in', 'SourceAlpha'); + feGaussianBlur.setAttribute('result', 'drop_shadow_1'); + feGaussianBlur.setAttribute('stdDeviation', '0'); + this.feGaussianBlur = feGaussianBlur; + filter.appendChild(feGaussianBlur); + + var feOffset = createNS('feOffset'); + feOffset.setAttribute('dx', '25'); + feOffset.setAttribute('dy', '0'); + feOffset.setAttribute('in', 'drop_shadow_1'); + feOffset.setAttribute('result', 'drop_shadow_2'); + this.feOffset = feOffset; + filter.appendChild(feOffset); + var feFlood = createNS('feFlood'); + feFlood.setAttribute('flood-color', '#00ff00'); + feFlood.setAttribute('flood-opacity', '1'); + feFlood.setAttribute('result', 'drop_shadow_3'); + this.feFlood = feFlood; + filter.appendChild(feFlood); + + var feComposite = createNS('feComposite'); + feComposite.setAttribute('in', 'drop_shadow_3'); + feComposite.setAttribute('in2', 'drop_shadow_2'); + feComposite.setAttribute('operator', 'in'); + feComposite.setAttribute('result', 'drop_shadow_4'); + filter.appendChild(feComposite); + + + var feMerge = createNS('feMerge'); + filter.appendChild(feMerge); + var feMergeNode; + feMergeNode = createNS('feMergeNode'); + feMerge.appendChild(feMergeNode); + feMergeNode = createNS('feMergeNode'); + feMergeNode.setAttribute('in', 'SourceGraphic'); + this.feMergeNode = feMergeNode; + this.feMerge = feMerge; + this.originalNodeAdded = false; + feMerge.appendChild(feMergeNode); + } + + SVGDropShadowEffect.prototype.renderFrame = function (forceRender) { + if (forceRender || this.filterManager._mdf) { + if (forceRender || this.filterManager.effectElements[4].p._mdf) { + this.feGaussianBlur.setAttribute('stdDeviation', this.filterManager.effectElements[4].p.v / 4); + } + if (forceRender || this.filterManager.effectElements[0].p._mdf) { + var col = this.filterManager.effectElements[0].p.v; + this.feFlood.setAttribute('flood-color', rgbToHex(Math.round(col[0] * 255), Math.round(col[1] * 255), Math.round(col[2] * 255))); + } + if (forceRender || this.filterManager.effectElements[1].p._mdf) { + this.feFlood.setAttribute('flood-opacity', this.filterManager.effectElements[1].p.v / 255); + } + if (forceRender || this.filterManager.effectElements[2].p._mdf || this.filterManager.effectElements[3].p._mdf) { + var distance = this.filterManager.effectElements[3].p.v; + var angle = (this.filterManager.effectElements[2].p.v - 90) * degToRads; + var x = distance * Math.cos(angle); + var y = distance * Math.sin(angle); + this.feOffset.setAttribute('dx', x); + this.feOffset.setAttribute('dy', y); + } + /*if(forceRender || this.filterManager.effectElements[5].p._mdf){ + if(this.filterManager.effectElements[5].p.v === 1 && this.originalNodeAdded) { + this.feMerge.removeChild(this.feMergeNode); + this.originalNodeAdded = false; + } else if(this.filterManager.effectElements[5].p.v === 0 && !this.originalNodeAdded) { + this.feMerge.appendChild(this.feMergeNode); + this.originalNodeAdded = true; + } + }*/ + } + }; + var _svgMatteSymbols = []; + + function SVGMatte3Effect(filterElem, filterManager, elem) { + this.initialized = false; + this.filterManager = filterManager; + this.filterElem = filterElem; + this.elem = elem; + elem.matteElement = createNS('g'); + elem.matteElement.appendChild(elem.layerElement); + elem.matteElement.appendChild(elem.transformedElement); + elem.baseElement = elem.matteElement; + } + + SVGMatte3Effect.prototype.findSymbol = function (mask) { + var i = 0, len = _svgMatteSymbols.length; + while (i < len) { + if (_svgMatteSymbols[i] === mask) { + return _svgMatteSymbols[i]; + } + i += 1; + } + return null; + }; + + SVGMatte3Effect.prototype.replaceInParent = function (mask, symbolId) { + var parentNode = mask.layerElement.parentNode; + if (!parentNode) { + return; + } + var children = parentNode.children; + var i = 0, len = children.length; + while (i < len) { + if (children[i] === mask.layerElement) { + break; + } + i += 1; + } + var nextChild; + if (i <= len - 2) { + nextChild = children[i + 1]; + } + var useElem = createNS('use'); + useElem.setAttribute('href', '#' + symbolId); + if (nextChild) { + parentNode.insertBefore(useElem, nextChild); + } else { + parentNode.appendChild(useElem); + } + }; + + SVGMatte3Effect.prototype.setElementAsMask = function (elem, mask) { + if (!this.findSymbol(mask)) { + var symbolId = createElementID(); + var masker = createNS('mask'); + masker.setAttribute('id', mask.layerId); + masker.setAttribute('mask-type', 'alpha'); + _svgMatteSymbols.push(mask); + var defs = elem.globalData.defs; + defs.appendChild(masker); + var symbol = createNS('symbol'); + symbol.setAttribute('id', symbolId); + this.replaceInParent(mask, symbolId); + symbol.appendChild(mask.layerElement); + defs.appendChild(symbol); + var useElem = createNS('use'); + useElem.setAttribute('href', '#' + symbolId); + masker.appendChild(useElem); + mask.data.hd = false; + mask.show(); + } + elem.setMatte(mask.layerId); + }; + + SVGMatte3Effect.prototype.initialize = function () { + var ind = this.filterManager.effectElements[0].p.v; + var elements = this.elem.comp.elements; + var i = 0, len = elements.length; + while (i < len) { + if (elements[i] && elements[i].data.ind === ind) { + this.setElementAsMask(this.elem, elements[i]); + } + i += 1; + } + this.initialized = true; + }; + + SVGMatte3Effect.prototype.renderFrame = function () { + if (!this.initialized) { + this.initialize(); + } + }; + function SVGEffects(elem) { + var i, len = elem.data.ef ? elem.data.ef.length : 0; + var filId = createElementID(); + var fil = filtersFactory.createFilter(filId); + var count = 0; + this.filters = []; + var filterManager; + for (i = 0; i < len; i += 1) { + filterManager = null; + if (elem.data.ef[i].ty === 20) { + count += 1; + filterManager = new SVGTintFilter(fil, elem.effectsManager.effectElements[i]); + } else if (elem.data.ef[i].ty === 21) { + count += 1; + filterManager = new SVGFillFilter(fil, elem.effectsManager.effectElements[i]); + } else if (elem.data.ef[i].ty === 22) { + filterManager = new SVGStrokeEffect(elem, elem.effectsManager.effectElements[i]); + } else if (elem.data.ef[i].ty === 23) { + count += 1; + filterManager = new SVGTritoneFilter(fil, elem.effectsManager.effectElements[i]); + } else if (elem.data.ef[i].ty === 24) { + count += 1; + filterManager = new SVGProLevelsFilter(fil, elem.effectsManager.effectElements[i]); + } else if (elem.data.ef[i].ty === 25) { + count += 1; + filterManager = new SVGDropShadowEffect(fil, elem.effectsManager.effectElements[i]); + } else if (elem.data.ef[i].ty === 28) { + //count += 1; + filterManager = new SVGMatte3Effect(fil, elem.effectsManager.effectElements[i], elem); + } else if (elem.data.ef[i].ty === 29) { + count += 1; + filterManager = new SVGGaussianBlurEffect(fil, elem.effectsManager.effectElements[i]); + } + if (filterManager) { + this.filters.push(filterManager); + } + } + if (count) { + elem.globalData.defs.appendChild(fil); + elem.layerElement.setAttribute('filter', 'url(' + locationHref + '#' + filId + ')'); + } + if (this.filters.length) { + elem.addRenderableComponent(this); + } + } + + SVGEffects.prototype.renderFrame = function (_isFirstFrame) { + var i, len = this.filters.length; + for (i = 0; i < len; i += 1) { + this.filters[i].renderFrame(_isFirstFrame); + } + }; + function CVContextData() { + this.saved = []; + this.cArrPos = 0; + this.cTr = new Matrix(); + this.cO = 1; + var i, len = 15; + this.savedOp = createTypedArray('float32', len); + for (i = 0; i < len; i += 1) { + this.saved[i] = createTypedArray('float32', 16); + } + this._length = len; + } + + CVContextData.prototype.duplicate = function () { + var newLength = this._length * 2; + var currentSavedOp = this.savedOp; + this.savedOp = createTypedArray('float32', newLength); + this.savedOp.set(currentSavedOp); + var i = 0; + for (i = this._length; i < newLength; i += 1) { + this.saved[i] = createTypedArray('float32', 16); + } + this._length = newLength; + }; + + CVContextData.prototype.reset = function () { + this.cArrPos = 0; + this.cTr.reset(); + this.cO = 1; + }; + function CVBaseElement() { + } + + CVBaseElement.prototype = { + createElements: function () { }, + initRendererElement: function () { }, + createContainerElements: function () { + this.canvasContext = this.globalData.canvasContext; + this.renderableEffectsManager = new CVEffects(this); + }, + createContent: function () { }, + setBlendMode: function () { + var globalData = this.globalData; + if (globalData.blendMode !== this.data.bm) { + globalData.blendMode = this.data.bm; + var blendModeValue = getBlendMode(this.data.bm); + globalData.canvasContext.globalCompositeOperation = blendModeValue; + } + }, + createRenderableComponents: function () { + this.maskManager = new CVMaskElement(this.data, this); + }, + hideElement: function () { + if (!this.hidden && (!this.isInRange || this.isTransparent)) { + this.hidden = true; + } + }, + showElement: function () { + if (this.isInRange && !this.isTransparent) { + this.hidden = false; + this._isFirstFrame = true; + this.maskManager._isFirstFrame = true; + } + }, + renderFrame: function () { + if (this.hidden || this.data.hd) { + return; + } + this.renderTransform(); + this.renderRenderable(); + this.setBlendMode(); + var forceRealStack = this.data.ty === 0; + this.globalData.renderer.save(forceRealStack); + this.globalData.renderer.ctxTransform(this.finalTransform.mat.props); + this.globalData.renderer.ctxOpacity(this.finalTransform.mProp.o.v); + this.renderInnerContent(); + this.globalData.renderer.restore(forceRealStack); + if (this.maskManager.hasMasks) { + this.globalData.renderer.restore(true); + } + if (this._isFirstFrame) { + this._isFirstFrame = false; + } + }, + destroy: function () { + this.canvasContext = null; + this.data = null; + this.globalData = null; + this.maskManager.destroy(); + }, + mHelper: new Matrix() + }; + CVBaseElement.prototype.hide = CVBaseElement.prototype.hideElement; + CVBaseElement.prototype.show = CVBaseElement.prototype.showElement; + + function CVImageElement(data, globalData, comp) { + this.assetData = globalData.getAssetData(data.refId); + this.img = globalData.imageLoader.getImage(this.assetData); + this.initElement(data, globalData, comp); + } + extendPrototype([BaseElement, TransformElement, CVBaseElement, HierarchyElement, FrameElement, RenderableElement], CVImageElement); + + CVImageElement.prototype.initElement = SVGShapeElement.prototype.initElement; + CVImageElement.prototype.prepareFrame = IImageElement.prototype.prepareFrame; + + CVImageElement.prototype.createContent = function () { + + if (this.img.width && (this.assetData.w !== this.img.width || this.assetData.h !== this.img.height)) { + var canvas = createTag('canvas'); + canvas.width = this.assetData.w; + canvas.height = this.assetData.h; + var ctx = canvas.getContext('2d'); + + var imgW = this.img.width; + var imgH = this.img.height; + var imgRel = imgW / imgH; + var canvasRel = this.assetData.w / this.assetData.h; + var widthCrop, heightCrop; + var par = this.assetData.pr || this.globalData.renderConfig.imagePreserveAspectRatio; + if ((imgRel > canvasRel && par === 'xMidYMid slice') || (imgRel < canvasRel && par !== 'xMidYMid slice')) { + heightCrop = imgH; + widthCrop = heightCrop * canvasRel; + } else { + widthCrop = imgW; + heightCrop = widthCrop / canvasRel; + } + ctx.drawImage(this.img, (imgW - widthCrop) / 2, (imgH - heightCrop) / 2, widthCrop, heightCrop, 0, 0, this.assetData.w, this.assetData.h); + this.img = canvas; + } + + }; + + CVImageElement.prototype.renderInnerContent = function (parentMatrix) { + this.canvasContext.drawImage(this.img, 0, 0); + }; + + CVImageElement.prototype.destroy = function () { + this.img = null; + }; + function CVCompElement(data, globalData, comp) { + this.completeLayers = false; + this.layers = data.layers; + this.pendingElements = []; + this.elements = createSizedArray(this.layers.length); + this.initElement(data, globalData, comp); + this.tm = data.tm ? PropertyFactory.getProp(this, data.tm, 0, globalData.frameRate, this) : { _placeholder: true }; + } + + extendPrototype([CanvasRenderer, ICompElement, CVBaseElement], CVCompElement); + + CVCompElement.prototype.renderInnerContent = function () { + var ctx = this.canvasContext; + ctx.beginPath(); + ctx.moveTo(0, 0); + ctx.lineTo(this.data.w, 0); + ctx.lineTo(this.data.w, this.data.h); + ctx.lineTo(0, this.data.h); + ctx.lineTo(0, 0); + ctx.clip(); + var i, len = this.layers.length; + for (i = len - 1; i >= 0; i -= 1) { + if (this.completeLayers || this.elements[i]) { + this.elements[i].renderFrame(); + } + } + }; + + CVCompElement.prototype.destroy = function () { + var i, len = this.layers.length; + for (i = len - 1; i >= 0; i -= 1) { + if (this.elements[i]) { + this.elements[i].destroy(); + } + } + this.layers = null; + this.elements = null; + }; + + function CVMaskElement(data, element) { + this.data = data; + this.element = element; + this.masksProperties = this.data.masksProperties || []; + this.viewData = createSizedArray(this.masksProperties.length); + var i, len = this.masksProperties.length, hasMasks = false; + for (i = 0; i < len; i++) { + if (this.masksProperties[i].mode !== 'n') { + hasMasks = true; + } + this.viewData[i] = ShapePropertyFactory.getShapeProp(this.element, this.masksProperties[i], 3); + } + this.hasMasks = hasMasks; + if (hasMasks) { + this.element.addRenderableComponent(this); + } + } + + CVMaskElement.prototype.renderFrame = function () { + if (!this.hasMasks) { + return; + } + var transform = this.element.finalTransform.mat; + var ctx = this.element.canvasContext; + var i, len = this.masksProperties.length; + var pt, pts, data; + ctx.beginPath(); + for (i = 0; i < len; i++) { + if (this.masksProperties[i].mode !== 'n') { + if (this.masksProperties[i].inv) { + ctx.moveTo(0, 0); + ctx.lineTo(this.element.globalData.compSize.w, 0); + ctx.lineTo(this.element.globalData.compSize.w, this.element.globalData.compSize.h); + ctx.lineTo(0, this.element.globalData.compSize.h); + ctx.lineTo(0, 0); + } + data = this.viewData[i].v; + pt = transform.applyToPointArray(data.v[0][0], data.v[0][1], 0); + ctx.moveTo(pt[0], pt[1]); + var j, jLen = data._length; + for (j = 1; j < jLen; j++) { + pts = transform.applyToTriplePoints(data.o[j - 1], data.i[j], data.v[j]); + ctx.bezierCurveTo(pts[0], pts[1], pts[2], pts[3], pts[4], pts[5]); + } + pts = transform.applyToTriplePoints(data.o[j - 1], data.i[0], data.v[0]); + ctx.bezierCurveTo(pts[0], pts[1], pts[2], pts[3], pts[4], pts[5]); + } + } + this.element.globalData.renderer.save(true); + ctx.clip(); + }; + + CVMaskElement.prototype.getMaskProperty = MaskElement.prototype.getMaskProperty; + + CVMaskElement.prototype.destroy = function () { + this.element = null; + }; + function CVShapeElement(data, globalData, comp) { + this.shapes = []; + this.shapesData = data.shapes; + this.stylesList = []; + this.itemsData = []; + this.prevViewData = []; + this.shapeModifiers = []; + this.processedElements = []; + this.transformsManager = new ShapeTransformManager(); + this.initElement(data, globalData, comp); + } + + extendPrototype([BaseElement, TransformElement, CVBaseElement, IShapeElement, HierarchyElement, FrameElement, RenderableElement], CVShapeElement); + + CVShapeElement.prototype.initElement = RenderableDOMElement.prototype.initElement; + + CVShapeElement.prototype.transformHelper = { opacity: 1, _opMdf: false }; + + CVShapeElement.prototype.dashResetter = []; + + CVShapeElement.prototype.createContent = function () { + this.searchShapes(this.shapesData, this.itemsData, this.prevViewData, true, []); + }; + + CVShapeElement.prototype.createStyleElement = function (data, transforms) { + var styleElem = { + data: data, + type: data.ty, + preTransforms: this.transformsManager.addTransformSequence(transforms), + transforms: [], + elements: [], + closed: data.hd === true + }; + var elementData = {}; + if (data.ty == 'fl' || data.ty == 'st') { + elementData.c = PropertyFactory.getProp(this, data.c, 1, 255, this); + if (!elementData.c.k) { + styleElem.co = 'rgb(' + bm_floor(elementData.c.v[0]) + ',' + bm_floor(elementData.c.v[1]) + ',' + bm_floor(elementData.c.v[2]) + ')'; + } + } else if (data.ty === 'gf' || data.ty === 'gs') { + elementData.s = PropertyFactory.getProp(this, data.s, 1, null, this); + elementData.e = PropertyFactory.getProp(this, data.e, 1, null, this); + elementData.h = PropertyFactory.getProp(this, data.h || { k: 0 }, 0, 0.01, this); + elementData.a = PropertyFactory.getProp(this, data.a || { k: 0 }, 0, degToRads, this); + elementData.g = new GradientProperty(this, data.g, this); + } + elementData.o = PropertyFactory.getProp(this, data.o, 0, 0.01, this); + if (data.ty == 'st' || data.ty == 'gs') { + styleElem.lc = this.lcEnum[data.lc] || 'round'; + styleElem.lj = this.ljEnum[data.lj] || 'round'; + if (data.lj == 1) { + styleElem.ml = data.ml; + } + elementData.w = PropertyFactory.getProp(this, data.w, 0, null, this); + if (!elementData.w.k) { + styleElem.wi = elementData.w.v; + } + if (data.d) { + var d = new DashProperty(this, data.d, 'canvas', this); + elementData.d = d; + if (!elementData.d.k) { + styleElem.da = elementData.d.dashArray; + styleElem.do = elementData.d.dashoffset[0]; + } + } + } else { + styleElem.r = data.r === 2 ? 'evenodd' : 'nonzero'; + } + this.stylesList.push(styleElem); + elementData.style = styleElem; + return elementData; + }; + + CVShapeElement.prototype.createGroupElement = function (data) { + var elementData = { + it: [], + prevViewData: [] + }; + return elementData; + }; + + CVShapeElement.prototype.createTransformElement = function (data) { + var elementData = { + transform: { + opacity: 1, + _opMdf: false, + key: this.transformsManager.getNewKey(), + op: PropertyFactory.getProp(this, data.o, 0, 0.01, this), + mProps: TransformPropertyFactory.getTransformProperty(this, data, this) + } + }; + return elementData; + }; + + CVShapeElement.prototype.createShapeElement = function (data) { + var elementData = new CVShapeData(this, data, this.stylesList, this.transformsManager); + + this.shapes.push(elementData); + this.addShapeToModifiers(elementData); + return elementData; + }; + + CVShapeElement.prototype.reloadShapes = function () { + this._isFirstFrame = true; + var i, len = this.itemsData.length; + for (i = 0; i < len; i += 1) { + this.prevViewData[i] = this.itemsData[i]; + } + this.searchShapes(this.shapesData, this.itemsData, this.prevViewData, true, []); + len = this.dynamicProperties.length; + for (i = 0; i < len; i += 1) { + this.dynamicProperties[i].getValue(); + } + this.renderModifiers(); + this.transformsManager.processSequences(this._isFirstFrame); + }; + + CVShapeElement.prototype.addTransformToStyleList = function (transform) { + var i, len = this.stylesList.length; + for (i = 0; i < len; i += 1) { + if (!this.stylesList[i].closed) { + this.stylesList[i].transforms.push(transform); + } + } + } + + CVShapeElement.prototype.removeTransformFromStyleList = function () { + var i, len = this.stylesList.length; + for (i = 0; i < len; i += 1) { + if (!this.stylesList[i].closed) { + this.stylesList[i].transforms.pop(); + } + } + } + + CVShapeElement.prototype.closeStyles = function (styles) { + var i, len = styles.length, j, jLen; + for (i = 0; i < len; i += 1) { + styles[i].closed = true; + } + } + + CVShapeElement.prototype.searchShapes = function (arr, itemsData, prevViewData, shouldRender, transforms) { + var i, len = arr.length - 1; + var j, jLen; + var ownStyles = [], ownModifiers = [], processedPos, modifier, currentTransform; + var ownTransforms = [].concat(transforms); + for (i = len; i >= 0; i -= 1) { + processedPos = this.searchProcessedElement(arr[i]); + if (!processedPos) { + arr[i]._shouldRender = shouldRender; + } else { + itemsData[i] = prevViewData[processedPos - 1]; + } + if (arr[i].ty == 'fl' || arr[i].ty == 'st' || arr[i].ty == 'gf' || arr[i].ty == 'gs') { + if (!processedPos) { + itemsData[i] = this.createStyleElement(arr[i], ownTransforms); + } else { + itemsData[i].style.closed = false; + } + + ownStyles.push(itemsData[i].style); + } else if (arr[i].ty == 'gr') { + if (!processedPos) { + itemsData[i] = this.createGroupElement(arr[i]); + } else { + jLen = itemsData[i].it.length; + for (j = 0; j < jLen; j += 1) { + itemsData[i].prevViewData[j] = itemsData[i].it[j]; + } + } + this.searchShapes(arr[i].it, itemsData[i].it, itemsData[i].prevViewData, shouldRender, ownTransforms); + } else if (arr[i].ty == 'tr') { + if (!processedPos) { + currentTransform = this.createTransformElement(arr[i]); + itemsData[i] = currentTransform; + } + ownTransforms.push(itemsData[i]); + this.addTransformToStyleList(itemsData[i]); + } else if (arr[i].ty == 'sh' || arr[i].ty == 'rc' || arr[i].ty == 'el' || arr[i].ty == 'sr') { + if (!processedPos) { + itemsData[i] = this.createShapeElement(arr[i]); + } + + } else if (arr[i].ty == 'tm' || arr[i].ty == 'rd') { + if (!processedPos) { + modifier = ShapeModifiers.getModifier(arr[i].ty); + modifier.init(this, arr[i]); + itemsData[i] = modifier; + this.shapeModifiers.push(modifier); + } else { + modifier = itemsData[i]; + modifier.closed = false; + } + ownModifiers.push(modifier); + } else if (arr[i].ty == 'rp') { + if (!processedPos) { + modifier = ShapeModifiers.getModifier(arr[i].ty); + itemsData[i] = modifier; + modifier.init(this, arr, i, itemsData); + this.shapeModifiers.push(modifier); + shouldRender = false; + } else { + modifier = itemsData[i]; + modifier.closed = true; + } + ownModifiers.push(modifier); + } + this.addProcessedElement(arr[i], i + 1); + } + this.removeTransformFromStyleList(); + this.closeStyles(ownStyles); + len = ownModifiers.length; + for (i = 0; i < len; i += 1) { + ownModifiers[i].closed = true; + } + }; + + CVShapeElement.prototype.renderInnerContent = function () { + this.transformHelper.opacity = 1; + this.transformHelper._opMdf = false; + this.renderModifiers(); + this.transformsManager.processSequences(this._isFirstFrame); + this.renderShape(this.transformHelper, this.shapesData, this.itemsData, true); + }; + + CVShapeElement.prototype.renderShapeTransform = function (parentTransform, groupTransform) { + var props, groupMatrix; + if (parentTransform._opMdf || groupTransform.op._mdf || this._isFirstFrame) { + groupTransform.opacity = parentTransform.opacity; + groupTransform.opacity *= groupTransform.op.v; + groupTransform._opMdf = true; + } + }; + + CVShapeElement.prototype.drawLayer = function () { + var i, len = this.stylesList.length; + var j, jLen, k, kLen, elems, nodes, renderer = this.globalData.renderer, ctx = this.globalData.canvasContext, type, currentStyle; + for (i = 0; i < len; i += 1) { + currentStyle = this.stylesList[i]; + type = currentStyle.type; + + //Skipping style when + //Stroke width equals 0 + //style should not be rendered (extra unused repeaters) + //current opacity equals 0 + //global opacity equals 0 + if (((type === 'st' || type === 'gs') && currentStyle.wi === 0) || !currentStyle.data._shouldRender || currentStyle.coOp === 0 || this.globalData.currentGlobalAlpha === 0) { + continue; + } + renderer.save(); + elems = currentStyle.elements; + if (type === 'st' || type === 'gs') { + ctx.strokeStyle = type === 'st' ? currentStyle.co : currentStyle.grd; + ctx.lineWidth = currentStyle.wi; + ctx.lineCap = currentStyle.lc; + ctx.lineJoin = currentStyle.lj; + ctx.miterLimit = currentStyle.ml || 0; + } else { + ctx.fillStyle = type === 'fl' ? currentStyle.co : currentStyle.grd; + } + renderer.ctxOpacity(currentStyle.coOp); + if (type !== 'st' && type !== 'gs') { + ctx.beginPath(); + } + renderer.ctxTransform(currentStyle.preTransforms.finalTransform.props); + jLen = elems.length; + for (j = 0; j < jLen; j += 1) { + if (type === 'st' || type === 'gs') { + ctx.beginPath(); + if (currentStyle.da) { + ctx.setLineDash(currentStyle.da); + ctx.lineDashOffset = currentStyle.do; + } + } + nodes = elems[j].trNodes; + kLen = nodes.length; + + for (k = 0; k < kLen; k += 1) { + if (nodes[k].t == 'm') { + ctx.moveTo(nodes[k].p[0], nodes[k].p[1]); + } else if (nodes[k].t == 'c') { + ctx.bezierCurveTo(nodes[k].pts[0], nodes[k].pts[1], nodes[k].pts[2], nodes[k].pts[3], nodes[k].pts[4], nodes[k].pts[5]); + } else { + ctx.closePath(); + } + } + if (type === 'st' || type === 'gs') { + ctx.stroke(); + if (currentStyle.da) { + ctx.setLineDash(this.dashResetter); + } + } + } + if (type !== 'st' && type !== 'gs') { + ctx.fill(currentStyle.r); + } + renderer.restore(); + } + }; + + CVShapeElement.prototype.renderShape = function (parentTransform, items, data, isMain) { + var i, len = items.length - 1; + var groupTransform; + groupTransform = parentTransform; + for (i = len; i >= 0; i -= 1) { + if (items[i].ty == 'tr') { + groupTransform = data[i].transform; + this.renderShapeTransform(parentTransform, groupTransform); + } else if (items[i].ty == 'sh' || items[i].ty == 'el' || items[i].ty == 'rc' || items[i].ty == 'sr') { + this.renderPath(items[i], data[i]); + } else if (items[i].ty == 'fl') { + this.renderFill(items[i], data[i], groupTransform); + } else if (items[i].ty == 'st') { + this.renderStroke(items[i], data[i], groupTransform); + } else if (items[i].ty == 'gf' || items[i].ty == 'gs') { + this.renderGradientFill(items[i], data[i], groupTransform); + } else if (items[i].ty == 'gr') { + this.renderShape(groupTransform, items[i].it, data[i].it); + } else if (items[i].ty == 'tm') { + // + } + } + if (isMain) { + this.drawLayer(); + } + + }; + + CVShapeElement.prototype.renderStyledShape = function (styledShape, shape) { + if (this._isFirstFrame || shape._mdf || styledShape.transforms._mdf) { + var shapeNodes = styledShape.trNodes; + var paths = shape.paths; + var i, len, j, jLen = paths._length; + shapeNodes.length = 0; + var groupTransformMat = styledShape.transforms.finalTransform; + for (j = 0; j < jLen; j += 1) { + var pathNodes = paths.shapes[j]; + if (pathNodes && pathNodes.v) { + len = pathNodes._length; + for (i = 1; i < len; i += 1) { + if (i === 1) { + shapeNodes.push({ + t: 'm', + p: groupTransformMat.applyToPointArray(pathNodes.v[0][0], pathNodes.v[0][1], 0) + }); + } + shapeNodes.push({ + t: 'c', + pts: groupTransformMat.applyToTriplePoints(pathNodes.o[i - 1], pathNodes.i[i], pathNodes.v[i]) + }); + } + if (len === 1) { + shapeNodes.push({ + t: 'm', + p: groupTransformMat.applyToPointArray(pathNodes.v[0][0], pathNodes.v[0][1], 0) + }); + } + if (pathNodes.c && len) { + shapeNodes.push({ + t: 'c', + pts: groupTransformMat.applyToTriplePoints(pathNodes.o[i - 1], pathNodes.i[0], pathNodes.v[0]) + }); + shapeNodes.push({ + t: 'z' + }); + } + } + } + styledShape.trNodes = shapeNodes; + } + } + + CVShapeElement.prototype.renderPath = function (pathData, itemData) { + if (pathData.hd !== true && pathData._shouldRender) { + var i, len = itemData.styledShapes.length; + for (i = 0; i < len; i += 1) { + this.renderStyledShape(itemData.styledShapes[i], itemData.sh); + } + } + }; + + CVShapeElement.prototype.renderFill = function (styleData, itemData, groupTransform) { + var styleElem = itemData.style; + + if (itemData.c._mdf || this._isFirstFrame) { + styleElem.co = 'rgb(' + + bm_floor(itemData.c.v[0]) + ',' + + bm_floor(itemData.c.v[1]) + ',' + + bm_floor(itemData.c.v[2]) + ')'; + } + if (itemData.o._mdf || groupTransform._opMdf || this._isFirstFrame) { + styleElem.coOp = itemData.o.v * groupTransform.opacity; + } + }; + + CVShapeElement.prototype.renderGradientFill = function (styleData, itemData, groupTransform) { + var styleElem = itemData.style; + if (!styleElem.grd || itemData.g._mdf || itemData.s._mdf || itemData.e._mdf || (styleData.t !== 1 && (itemData.h._mdf || itemData.a._mdf))) { + var ctx = this.globalData.canvasContext; + var grd; + var pt1 = itemData.s.v, pt2 = itemData.e.v; + if (styleData.t === 1) { + grd = ctx.createLinearGradient(pt1[0], pt1[1], pt2[0], pt2[1]); + } else { + var rad = Math.sqrt(Math.pow(pt1[0] - pt2[0], 2) + Math.pow(pt1[1] - pt2[1], 2)); + var ang = Math.atan2(pt2[1] - pt1[1], pt2[0] - pt1[0]); + + var percent = itemData.h.v >= 1 ? 0.99 : itemData.h.v <= -1 ? -0.99 : itemData.h.v; + var dist = rad * percent; + var x = Math.cos(ang + itemData.a.v) * dist + pt1[0]; + var y = Math.sin(ang + itemData.a.v) * dist + pt1[1]; + var grd = ctx.createRadialGradient(x, y, 0, pt1[0], pt1[1], rad); + } + + var i, len = styleData.g.p; + var cValues = itemData.g.c; + var opacity = 1; + + for (i = 0; i < len; i += 1) { + if (itemData.g._hasOpacity && itemData.g._collapsable) { + opacity = itemData.g.o[i * 2 + 1]; + } + grd.addColorStop(cValues[i * 4] / 100, 'rgba(' + cValues[i * 4 + 1] + ',' + cValues[i * 4 + 2] + ',' + cValues[i * 4 + 3] + ',' + opacity + ')'); + } + styleElem.grd = grd; + } + styleElem.coOp = itemData.o.v * groupTransform.opacity; + + }; + + CVShapeElement.prototype.renderStroke = function (styleData, itemData, groupTransform) { + var styleElem = itemData.style; + var d = itemData.d; + if (d && (d._mdf || this._isFirstFrame)) { + styleElem.da = d.dashArray; + styleElem.do = d.dashoffset[0]; + } + if (itemData.c._mdf || this._isFirstFrame) { + styleElem.co = 'rgb(' + bm_floor(itemData.c.v[0]) + ',' + bm_floor(itemData.c.v[1]) + ',' + bm_floor(itemData.c.v[2]) + ')'; + } + if (itemData.o._mdf || groupTransform._opMdf || this._isFirstFrame) { + styleElem.coOp = itemData.o.v * groupTransform.opacity; + } + if (itemData.w._mdf || this._isFirstFrame) { + styleElem.wi = itemData.w.v; + } + }; + + + CVShapeElement.prototype.destroy = function () { + this.shapesData = null; + this.globalData = null; + this.canvasContext = null; + this.stylesList.length = 0; + this.itemsData.length = 0; + }; + + + function CVSolidElement(data, globalData, comp) { + this.initElement(data, globalData, comp); + } + extendPrototype([BaseElement, TransformElement, CVBaseElement, HierarchyElement, FrameElement, RenderableElement], CVSolidElement); + + CVSolidElement.prototype.initElement = SVGShapeElement.prototype.initElement; + CVSolidElement.prototype.prepareFrame = IImageElement.prototype.prepareFrame; + + CVSolidElement.prototype.renderInnerContent = function () { + var ctx = this.canvasContext; + ctx.fillStyle = this.data.sc; + ctx.fillRect(0, 0, this.data.sw, this.data.sh); + // + }; + function CVTextElement(data, globalData, comp) { + this.textSpans = []; + this.yOffset = 0; + this.fillColorAnim = false; + this.strokeColorAnim = false; + this.strokeWidthAnim = false; + this.stroke = false; + this.fill = false; + this.justifyOffset = 0; + this.currentRender = null; + this.renderType = 'canvas'; + this.values = { + fill: 'rgba(0,0,0,0)', + stroke: 'rgba(0,0,0,0)', + sWidth: 0, + fValue: '' + }; + this.initElement(data, globalData, comp); + } + extendPrototype([BaseElement, TransformElement, CVBaseElement, HierarchyElement, FrameElement, RenderableElement, ITextElement], CVTextElement); + + CVTextElement.prototype.tHelper = createTag('canvas').getContext('2d'); + + CVTextElement.prototype.buildNewText = function () { + var documentData = this.textProperty.currentData; + this.renderedLetters = createSizedArray(documentData.l ? documentData.l.length : 0); + + var hasFill = false; + if (documentData.fc) { + hasFill = true; + this.values.fill = this.buildColor(documentData.fc); + } else { + this.values.fill = 'rgba(0,0,0,0)'; + } + this.fill = hasFill; + var hasStroke = false; + if (documentData.sc) { + hasStroke = true; + this.values.stroke = this.buildColor(documentData.sc); + this.values.sWidth = documentData.sw; + } + var fontData = this.globalData.fontManager.getFontByName(documentData.f); + var i, len; + var letters = documentData.l; + var matrixHelper = this.mHelper; + this.stroke = hasStroke; + this.values.fValue = documentData.finalSize + 'px ' + this.globalData.fontManager.getFontByName(documentData.f).fFamily; + len = documentData.finalText.length; + //this.tHelper.font = this.values.fValue; + var charData, shapeData, k, kLen, shapes, j, jLen, pathNodes, commands, pathArr, singleShape = this.data.singleShape; + var trackingOffset = documentData.tr / 1000 * documentData.finalSize; + var xPos = 0, yPos = 0, firstLine = true; + var cnt = 0; + for (i = 0; i < len; i += 1) { + charData = this.globalData.fontManager.getCharData(documentData.finalText[i], fontData.fStyle, this.globalData.fontManager.getFontByName(documentData.f).fFamily); + shapeData = charData && charData.data || {}; + matrixHelper.reset(); + if (singleShape && letters[i].n) { + xPos = -trackingOffset; + yPos += documentData.yOffset; + yPos += firstLine ? 1 : 0; + firstLine = false; + } + + shapes = shapeData.shapes ? shapeData.shapes[0].it : []; + jLen = shapes.length; + matrixHelper.scale(documentData.finalSize / 100, documentData.finalSize / 100); + if (singleShape) { + this.applyTextPropertiesToMatrix(documentData, matrixHelper, letters[i].line, xPos, yPos); + } + commands = createSizedArray(jLen); + for (j = 0; j < jLen; j += 1) { + kLen = shapes[j].ks.k.i.length; + pathNodes = shapes[j].ks.k; + pathArr = []; + for (k = 1; k < kLen; k += 1) { + if (k == 1) { + pathArr.push(matrixHelper.applyToX(pathNodes.v[0][0], pathNodes.v[0][1], 0), matrixHelper.applyToY(pathNodes.v[0][0], pathNodes.v[0][1], 0)); + } + pathArr.push(matrixHelper.applyToX(pathNodes.o[k - 1][0], pathNodes.o[k - 1][1], 0), matrixHelper.applyToY(pathNodes.o[k - 1][0], pathNodes.o[k - 1][1], 0), matrixHelper.applyToX(pathNodes.i[k][0], pathNodes.i[k][1], 0), matrixHelper.applyToY(pathNodes.i[k][0], pathNodes.i[k][1], 0), matrixHelper.applyToX(pathNodes.v[k][0], pathNodes.v[k][1], 0), matrixHelper.applyToY(pathNodes.v[k][0], pathNodes.v[k][1], 0)); + } + pathArr.push(matrixHelper.applyToX(pathNodes.o[k - 1][0], pathNodes.o[k - 1][1], 0), matrixHelper.applyToY(pathNodes.o[k - 1][0], pathNodes.o[k - 1][1], 0), matrixHelper.applyToX(pathNodes.i[0][0], pathNodes.i[0][1], 0), matrixHelper.applyToY(pathNodes.i[0][0], pathNodes.i[0][1], 0), matrixHelper.applyToX(pathNodes.v[0][0], pathNodes.v[0][1], 0), matrixHelper.applyToY(pathNodes.v[0][0], pathNodes.v[0][1], 0)); + commands[j] = pathArr; + } + if (singleShape) { + xPos += letters[i].l; + xPos += trackingOffset; + } + if (this.textSpans[cnt]) { + this.textSpans[cnt].elem = commands; + } else { + this.textSpans[cnt] = { elem: commands }; + } + cnt += 1; + } + }; + + CVTextElement.prototype.renderInnerContent = function () { + var ctx = this.canvasContext; + var finalMat = this.finalTransform.mat.props; + ctx.font = this.values.fValue; + ctx.lineCap = 'butt'; + ctx.lineJoin = 'miter'; + ctx.miterLimit = 4; + + if (!this.data.singleShape) { + this.textAnimator.getMeasures(this.textProperty.currentData, this.lettersChangedFlag); + } + + var i, len, j, jLen, k, kLen; + var renderedLetters = this.textAnimator.renderedLetters; + + var letters = this.textProperty.currentData.l; + + len = letters.length; + var renderedLetter; + var lastFill = null, lastStroke = null, lastStrokeW = null, commands, pathArr; + for (i = 0; i < len; i += 1) { + if (letters[i].n) { + continue; + } + renderedLetter = renderedLetters[i]; + if (renderedLetter) { + this.globalData.renderer.save(); + this.globalData.renderer.ctxTransform(renderedLetter.p); + this.globalData.renderer.ctxOpacity(renderedLetter.o); + } + if (this.fill) { + if (renderedLetter && renderedLetter.fc) { + if (lastFill !== renderedLetter.fc) { + lastFill = renderedLetter.fc; + ctx.fillStyle = renderedLetter.fc; + } + } else if (lastFill !== this.values.fill) { + lastFill = this.values.fill; + ctx.fillStyle = this.values.fill; + } + commands = this.textSpans[i].elem; + jLen = commands.length; + this.globalData.canvasContext.beginPath(); + for (j = 0; j < jLen; j += 1) { + pathArr = commands[j]; + kLen = pathArr.length; + this.globalData.canvasContext.moveTo(pathArr[0], pathArr[1]); + for (k = 2; k < kLen; k += 6) { + this.globalData.canvasContext.bezierCurveTo(pathArr[k], pathArr[k + 1], pathArr[k + 2], pathArr[k + 3], pathArr[k + 4], pathArr[k + 5]); + } + } + this.globalData.canvasContext.closePath(); + this.globalData.canvasContext.fill(); + ///ctx.fillText(this.textSpans[i].val,0,0); + } + if (this.stroke) { + if (renderedLetter && renderedLetter.sw) { + if (lastStrokeW !== renderedLetter.sw) { + lastStrokeW = renderedLetter.sw; + ctx.lineWidth = renderedLetter.sw; + } + } else if (lastStrokeW !== this.values.sWidth) { + lastStrokeW = this.values.sWidth; + ctx.lineWidth = this.values.sWidth; + } + if (renderedLetter && renderedLetter.sc) { + if (lastStroke !== renderedLetter.sc) { + lastStroke = renderedLetter.sc; + ctx.strokeStyle = renderedLetter.sc; + } + } else if (lastStroke !== this.values.stroke) { + lastStroke = this.values.stroke; + ctx.strokeStyle = this.values.stroke; + } + commands = this.textSpans[i].elem; + jLen = commands.length; + this.globalData.canvasContext.beginPath(); + for (j = 0; j < jLen; j += 1) { + pathArr = commands[j]; + kLen = pathArr.length; + this.globalData.canvasContext.moveTo(pathArr[0], pathArr[1]); + for (k = 2; k < kLen; k += 6) { + this.globalData.canvasContext.bezierCurveTo(pathArr[k], pathArr[k + 1], pathArr[k + 2], pathArr[k + 3], pathArr[k + 4], pathArr[k + 5]); + } + } + this.globalData.canvasContext.closePath(); + this.globalData.canvasContext.stroke(); + ///ctx.strokeText(letters[i].val,0,0); + } + if (renderedLetter) { + this.globalData.renderer.restore(); + } + } + }; + function CVEffects() { + + } + CVEffects.prototype.renderFrame = function () { }; + function HBaseElement(data, globalData, comp) { } + HBaseElement.prototype = { + checkBlendMode: function () { }, + initRendererElement: function () { + this.baseElement = createTag(this.data.tg || 'div'); + if (this.data.hasMask) { + this.svgElement = createNS('svg'); + this.layerElement = createNS('g'); + this.maskedElement = this.layerElement; + this.svgElement.appendChild(this.layerElement); + this.baseElement.appendChild(this.svgElement); + } else { + this.layerElement = this.baseElement; + } + styleDiv(this.baseElement); + }, + createContainerElements: function () { + this.renderableEffectsManager = new CVEffects(this); + this.transformedElement = this.baseElement; + this.maskedElement = this.layerElement; + if (this.data.ln) { + this.layerElement.setAttribute('id', this.data.ln); + } + if (this.data.cl) { + this.layerElement.setAttribute('class', this.data.cl); + } + if (this.data.bm !== 0) { + this.setBlendMode(); + } + }, + renderElement: function () { + if (this.finalTransform._matMdf) { + this.transformedElement.style.transform = this.transformedElement.style.webkitTransform = this.finalTransform.mat.toCSS(); + } + if (this.finalTransform._opMdf) { + this.transformedElement.style.opacity = this.finalTransform.mProp.o.v; + } + }, + renderFrame: function () { + //If it is exported as hidden (data.hd === true) no need to render + //If it is not visible no need to render + if (this.data.hd || this.hidden) { + return; + } + this.renderTransform(); + this.renderRenderable(); + this.renderElement(); + this.renderInnerContent(); + if (this._isFirstFrame) { + this._isFirstFrame = false; + } + }, + destroy: function () { + this.layerElement = null; + this.transformedElement = null; + if (this.matteElement) { + this.matteElement = null; + } + if (this.maskManager) { + this.maskManager.destroy(); + this.maskManager = null; + } + }, + createRenderableComponents: function () { + this.maskManager = new MaskElement(this.data, this, this.globalData); + }, + addEffects: function () { + }, + setMatte: function () { } + }; + HBaseElement.prototype.getBaseElement = SVGBaseElement.prototype.getBaseElement; + HBaseElement.prototype.destroyBaseElement = HBaseElement.prototype.destroy; + HBaseElement.prototype.buildElementParenting = HybridRenderer.prototype.buildElementParenting; + function HSolidElement(data, globalData, comp) { + this.initElement(data, globalData, comp); + } + extendPrototype([BaseElement, TransformElement, HBaseElement, HierarchyElement, FrameElement, RenderableDOMElement], HSolidElement); + + HSolidElement.prototype.createContent = function () { + var rect; + if (this.data.hasMask) { + rect = createNS('rect'); + rect.setAttribute('width', this.data.sw); + rect.setAttribute('height', this.data.sh); + rect.setAttribute('fill', this.data.sc); + this.svgElement.setAttribute('width', this.data.sw); + this.svgElement.setAttribute('height', this.data.sh); + } else { + rect = createTag('div'); + rect.style.width = this.data.sw + 'px'; + rect.style.height = this.data.sh + 'px'; + rect.style.backgroundColor = this.data.sc; + } + this.layerElement.appendChild(rect); + }; + + function HCompElement(data, globalData, comp) { + this.layers = data.layers; + this.supports3d = !data.hasMask; + this.completeLayers = false; + this.pendingElements = []; + this.elements = this.layers ? createSizedArray(this.layers.length) : []; + this.initElement(data, globalData, comp); + this.tm = data.tm ? PropertyFactory.getProp(this, data.tm, 0, globalData.frameRate, this) : { _placeholder: true }; + } + + extendPrototype([HybridRenderer, ICompElement, HBaseElement], HCompElement); + HCompElement.prototype._createBaseContainerElements = HCompElement.prototype.createContainerElements; + + HCompElement.prototype.createContainerElements = function () { + this._createBaseContainerElements(); + //divElement.style.clip = 'rect(0px, '+this.data.w+'px, '+this.data.h+'px, 0px)'; + if (this.data.hasMask) { + this.svgElement.setAttribute('width', this.data.w); + this.svgElement.setAttribute('height', this.data.h); + this.transformedElement = this.baseElement; + } else { + this.transformedElement = this.layerElement; + } + }; + + HCompElement.prototype.addTo3dContainer = function (elem, pos) { + var j = 0; + var nextElement; + while (j < pos) { + if (this.elements[j] && this.elements[j].getBaseElement) { + nextElement = this.elements[j].getBaseElement(); + } + j += 1; + } + if (nextElement) { + this.layerElement.insertBefore(elem, nextElement); + } else { + this.layerElement.appendChild(elem); + } + } + + function HShapeElement(data, globalData, comp) { + //List of drawable elements + this.shapes = []; + // Full shape data + this.shapesData = data.shapes; + //List of styles that will be applied to shapes + this.stylesList = []; + //List of modifiers that will be applied to shapes + this.shapeModifiers = []; + //List of items in shape tree + this.itemsData = []; + //List of items in previous shape tree + this.processedElements = []; + // List of animated components + this.animatedContents = []; + this.shapesContainer = createNS('g'); + this.initElement(data, globalData, comp); + //Moving any property that doesn't get too much access after initialization because of v8 way of handling more than 10 properties. + // List of elements that have been created + this.prevViewData = []; + this.currentBBox = { + x: 999999, + y: -999999, + h: 0, + w: 0 + }; + } + extendPrototype([BaseElement, TransformElement, HSolidElement, SVGShapeElement, HBaseElement, HierarchyElement, FrameElement, RenderableElement], HShapeElement); + HShapeElement.prototype._renderShapeFrame = HShapeElement.prototype.renderInnerContent; + + HShapeElement.prototype.createContent = function () { + var cont; + this.baseElement.style.fontSize = 0; + if (this.data.hasMask) { + this.layerElement.appendChild(this.shapesContainer); + cont = this.svgElement; + } else { + cont = createNS('svg'); + var size = this.comp.data ? this.comp.data : this.globalData.compSize; + cont.setAttribute('width', size.w); + cont.setAttribute('height', size.h); + cont.appendChild(this.shapesContainer); + this.layerElement.appendChild(cont); + } + + this.searchShapes(this.shapesData, this.itemsData, this.prevViewData, this.shapesContainer, 0, [], true); + this.filterUniqueShapes(); + this.shapeCont = cont; + }; + + HShapeElement.prototype.getTransformedPoint = function (transformers, point) { + var i, len = transformers.length; + for (i = 0; i < len; i += 1) { + point = transformers[i].mProps.v.applyToPointArray(point[0], point[1], 0); + } + return point; + } + + HShapeElement.prototype.calculateShapeBoundingBox = function (item, boundingBox) { + var shape = item.sh.v; + var transformers = item.transformers; + var i, len = shape._length, vPoint, oPoint, nextIPoint, nextVPoint, bounds; + if (len <= 1) { + return; + } + for (i = 0; i < len - 1; i += 1) { + vPoint = this.getTransformedPoint(transformers, shape.v[i]); + oPoint = this.getTransformedPoint(transformers, shape.o[i]); + nextIPoint = this.getTransformedPoint(transformers, shape.i[i + 1]); + nextVPoint = this.getTransformedPoint(transformers, shape.v[i + 1]); + this.checkBounds(vPoint, oPoint, nextIPoint, nextVPoint, boundingBox); + } + if (shape.c) { + vPoint = this.getTransformedPoint(transformers, shape.v[i]); + oPoint = this.getTransformedPoint(transformers, shape.o[i]); + nextIPoint = this.getTransformedPoint(transformers, shape.i[0]); + nextVPoint = this.getTransformedPoint(transformers, shape.v[0]); + this.checkBounds(vPoint, oPoint, nextIPoint, nextVPoint, boundingBox); + } + } + + HShapeElement.prototype.checkBounds = function (vPoint, oPoint, nextIPoint, nextVPoint, boundingBox) { + this.getBoundsOfCurve(vPoint, oPoint, nextIPoint, nextVPoint); + var bounds = this.shapeBoundingBox; + boundingBox.x = bm_min(bounds.left, boundingBox.x); + boundingBox.xMax = bm_max(bounds.right, boundingBox.xMax); + boundingBox.y = bm_min(bounds.top, boundingBox.y); + boundingBox.yMax = bm_max(bounds.bottom, boundingBox.yMax); + } + + HShapeElement.prototype.shapeBoundingBox = { + left: 0, + right: 0, + top: 0, + bottom: 0, + } + + HShapeElement.prototype.tempBoundingBox = { + x: 0, + xMax: 0, + y: 0, + yMax: 0, + width: 0, + height: 0 + } + + HShapeElement.prototype.getBoundsOfCurve = function (p0, p1, p2, p3) { + + var bounds = [[p0[0], p3[0]], [p0[1], p3[1]]]; + + for (var a, b, c, t, b2ac, t1, t2, i = 0; i < 2; ++i) { + + b = 6 * p0[i] - 12 * p1[i] + 6 * p2[i]; + a = -3 * p0[i] + 9 * p1[i] - 9 * p2[i] + 3 * p3[i]; + c = 3 * p1[i] - 3 * p0[i]; + + b = b | 0; + a = a | 0; + c = c | 0; + + if (a === 0) { + + if (b === 0) { + continue; + } + + t = -c / b; + + if (0 < t && t < 1) { + bounds[i].push(this.calculateF(t, p0, p1, p2, p3, i)); + } + continue; + } + + b2ac = b * b - 4 * c * a; + + if (b2ac < 0) { + continue; + } + + t1 = (-b + bm_sqrt(b2ac)) / (2 * a); + if (0 < t1 && t1 < 1) bounds[i].push(this.calculateF(t1, p0, p1, p2, p3, i)); + + t2 = (-b - bm_sqrt(b2ac)) / (2 * a); + if (0 < t2 && t2 < 1) bounds[i].push(this.calculateF(t2, p0, p1, p2, p3, i)); + + } + + this.shapeBoundingBox.left = bm_min.apply(null, bounds[0]); + this.shapeBoundingBox.top = bm_min.apply(null, bounds[1]); + this.shapeBoundingBox.right = bm_max.apply(null, bounds[0]); + this.shapeBoundingBox.bottom = bm_max.apply(null, bounds[1]); + }; + + HShapeElement.prototype.calculateF = function (t, p0, p1, p2, p3, i) { + return bm_pow(1 - t, 3) * p0[i] + + 3 * bm_pow(1 - t, 2) * t * p1[i] + + 3 * (1 - t) * bm_pow(t, 2) * p2[i] + + bm_pow(t, 3) * p3[i]; + } + + HShapeElement.prototype.calculateBoundingBox = function (itemsData, boundingBox) { + var i, len = itemsData.length, path; + for (i = 0; i < len; i += 1) { + if (itemsData[i] && itemsData[i].sh) { + this.calculateShapeBoundingBox(itemsData[i], boundingBox) + } else if (itemsData[i] && itemsData[i].it) { + this.calculateBoundingBox(itemsData[i].it, boundingBox) + } + } + } + + HShapeElement.prototype.currentBoxContains = function (box) { + return this.currentBBox.x <= box.x + && this.currentBBox.y <= box.y + && this.currentBBox.width + this.currentBBox.x >= box.x + box.width + && this.currentBBox.height + this.currentBBox.y >= box.y + box.height + } + + HShapeElement.prototype.renderInnerContent = function () { + this._renderShapeFrame(); + + if (!this.hidden && (this._isFirstFrame || this._mdf)) { + var tempBoundingBox = this.tempBoundingBox; + var max = 999999; + tempBoundingBox.x = max; + tempBoundingBox.xMax = -max; + tempBoundingBox.y = max; + tempBoundingBox.yMax = -max; + this.calculateBoundingBox(this.itemsData, tempBoundingBox); + tempBoundingBox.width = tempBoundingBox.xMax < tempBoundingBox.x ? 0 : tempBoundingBox.xMax - tempBoundingBox.x; + tempBoundingBox.height = tempBoundingBox.yMax < tempBoundingBox.y ? 0 : tempBoundingBox.yMax - tempBoundingBox.y; + //var tempBoundingBox = this.shapeCont.getBBox(); + if (this.currentBoxContains(tempBoundingBox)) { + return; + } + var changed = false; + if (this.currentBBox.w !== tempBoundingBox.width) { + this.currentBBox.w = tempBoundingBox.width; + this.shapeCont.setAttribute('width', tempBoundingBox.width); + changed = true; + } + if (this.currentBBox.h !== tempBoundingBox.height) { + this.currentBBox.h = tempBoundingBox.height; + this.shapeCont.setAttribute('height', tempBoundingBox.height); + changed = true; + } + if (changed || this.currentBBox.x !== tempBoundingBox.x || this.currentBBox.y !== tempBoundingBox.y) { + this.currentBBox.w = tempBoundingBox.width; + this.currentBBox.h = tempBoundingBox.height; + this.currentBBox.x = tempBoundingBox.x; + this.currentBBox.y = tempBoundingBox.y; + + this.shapeCont.setAttribute('viewBox', this.currentBBox.x + ' ' + this.currentBBox.y + ' ' + this.currentBBox.w + ' ' + this.currentBBox.h); + this.shapeCont.style.transform = this.shapeCont.style.webkitTransform = 'translate(' + this.currentBBox.x + 'px,' + this.currentBBox.y + 'px)'; + } + } + + }; + function HTextElement(data, globalData, comp) { + this.textSpans = []; + this.textPaths = []; + this.currentBBox = { + x: 999999, + y: -999999, + h: 0, + w: 0 + }; + this.renderType = 'svg'; + this.isMasked = false; + this.initElement(data, globalData, comp); + + } + extendPrototype([BaseElement, TransformElement, HBaseElement, HierarchyElement, FrameElement, RenderableDOMElement, ITextElement], HTextElement); + + HTextElement.prototype.createContent = function () { + this.isMasked = this.checkMasks(); + if (this.isMasked) { + this.renderType = 'svg'; + this.compW = this.comp.data.w; + this.compH = this.comp.data.h; + this.svgElement.setAttribute('width', this.compW); + this.svgElement.setAttribute('height', this.compH); + var g = createNS('g'); + this.maskedElement.appendChild(g); + this.innerElem = g; + } else { + this.renderType = 'html'; + this.innerElem = this.layerElement; + } + + this.checkParenting(); + + }; + + HTextElement.prototype.buildNewText = function () { + var documentData = this.textProperty.currentData; + this.renderedLetters = createSizedArray(documentData.l ? documentData.l.length : 0); + var innerElemStyle = this.innerElem.style; + innerElemStyle.color = innerElemStyle.fill = documentData.fc ? this.buildColor(documentData.fc) : 'rgba(0,0,0,0)'; + if (documentData.sc) { + innerElemStyle.stroke = this.buildColor(documentData.sc); + innerElemStyle.strokeWidth = documentData.sw + 'px'; + } + var fontData = this.globalData.fontManager.getFontByName(documentData.f); + if (!this.globalData.fontManager.chars) { + innerElemStyle.fontSize = documentData.finalSize + 'px'; + innerElemStyle.lineHeight = documentData.finalSize + 'px'; + if (fontData.fClass) { + this.innerElem.className = fontData.fClass; + } else { + innerElemStyle.fontFamily = fontData.fFamily; + var fWeight = documentData.fWeight, fStyle = documentData.fStyle; + innerElemStyle.fontStyle = fStyle; + innerElemStyle.fontWeight = fWeight; + } + } + var i, len; + + var letters = documentData.l; + len = letters.length; + var tSpan, tParent, tCont; + var matrixHelper = this.mHelper; + var shapes, shapeStr = ''; + var cnt = 0; + for (i = 0; i < len; i += 1) { + if (this.globalData.fontManager.chars) { + if (!this.textPaths[cnt]) { + tSpan = createNS('path'); + tSpan.setAttribute('stroke-linecap', 'butt'); + tSpan.setAttribute('stroke-linejoin', 'round'); + tSpan.setAttribute('stroke-miterlimit', '4'); + } else { + tSpan = this.textPaths[cnt]; + } + if (!this.isMasked) { + if (this.textSpans[cnt]) { + tParent = this.textSpans[cnt]; + tCont = tParent.children[0]; + } else { + + tParent = createTag('div'); + tParent.style.lineHeight = 0; + tCont = createNS('svg'); + tCont.appendChild(tSpan); + styleDiv(tParent); + } + } + } else { + if (!this.isMasked) { + if (this.textSpans[cnt]) { + tParent = this.textSpans[cnt]; + tSpan = this.textPaths[cnt]; + } else { + tParent = createTag('span'); + styleDiv(tParent); + tSpan = createTag('span'); + styleDiv(tSpan); + tParent.appendChild(tSpan); + } + } else { + tSpan = this.textPaths[cnt] ? this.textPaths[cnt] : createNS('text'); + } + } + //tSpan.setAttribute('visibility', 'hidden'); + if (this.globalData.fontManager.chars) { + var charData = this.globalData.fontManager.getCharData(documentData.finalText[i], fontData.fStyle, this.globalData.fontManager.getFontByName(documentData.f).fFamily); + var shapeData; + if (charData) { + shapeData = charData.data; + } else { + shapeData = null; + } + matrixHelper.reset(); + if (shapeData && shapeData.shapes) { + shapes = shapeData.shapes[0].it; + matrixHelper.scale(documentData.finalSize / 100, documentData.finalSize / 100); + shapeStr = this.createPathShape(matrixHelper, shapes); + tSpan.setAttribute('d', shapeStr); + } + if (!this.isMasked) { + this.innerElem.appendChild(tParent); + if (shapeData && shapeData.shapes) { + + //document.body.appendChild is needed to get exact measure of shape + document.body.appendChild(tCont); + var boundingBox = tCont.getBBox(); + tCont.setAttribute('width', boundingBox.width + 2); + tCont.setAttribute('height', boundingBox.height + 2); + tCont.setAttribute('viewBox', (boundingBox.x - 1) + ' ' + (boundingBox.y - 1) + ' ' + (boundingBox.width + 2) + ' ' + (boundingBox.height + 2)); + tCont.style.transform = tCont.style.webkitTransform = 'translate(' + (boundingBox.x - 1) + 'px,' + (boundingBox.y - 1) + 'px)'; + + letters[i].yOffset = boundingBox.y - 1; + + } else { + tCont.setAttribute('width', 1); + tCont.setAttribute('height', 1); + } + tParent.appendChild(tCont); + } else { + this.innerElem.appendChild(tSpan); + } + } else { + tSpan.textContent = letters[i].val; + tSpan.setAttributeNS("http://www.w3.org/XML/1998/namespace", "xml:space", "preserve"); + if (!this.isMasked) { + this.innerElem.appendChild(tParent); + // + tSpan.style.transform = tSpan.style.webkitTransform = 'translate3d(0,' + -documentData.finalSize / 1.2 + 'px,0)'; + } else { + this.innerElem.appendChild(tSpan); + } + } + // + if (!this.isMasked) { + this.textSpans[cnt] = tParent; + } else { + this.textSpans[cnt] = tSpan; + } + this.textSpans[cnt].style.display = 'block'; + this.textPaths[cnt] = tSpan; + cnt += 1; + } + while (cnt < this.textSpans.length) { + this.textSpans[cnt].style.display = 'none'; + cnt += 1; + } + }; + + HTextElement.prototype.renderInnerContent = function () { + + if (this.data.singleShape) { + if (!this._isFirstFrame && !this.lettersChangedFlag) { + return; + } else { + // Todo Benchmark if using this is better than getBBox + if (this.isMasked && this.finalTransform._matMdf) { + this.svgElement.setAttribute('viewBox', -this.finalTransform.mProp.p.v[0] + ' ' + -this.finalTransform.mProp.p.v[1] + ' ' + this.compW + ' ' + this.compH); + this.svgElement.style.transform = this.svgElement.style.webkitTransform = 'translate(' + -this.finalTransform.mProp.p.v[0] + 'px,' + -this.finalTransform.mProp.p.v[1] + 'px)'; + } + } + } + + this.textAnimator.getMeasures(this.textProperty.currentData, this.lettersChangedFlag); + if (!this.lettersChangedFlag && !this.textAnimator.lettersChangedFlag) { + return; + } + var i, len, count = 0; + var renderedLetters = this.textAnimator.renderedLetters; + + var letters = this.textProperty.currentData.l; + + len = letters.length; + var renderedLetter, textSpan, textPath; + for (i = 0; i < len; i += 1) { + if (letters[i].n) { + count += 1; + continue; + } + textSpan = this.textSpans[i]; + textPath = this.textPaths[i]; + renderedLetter = renderedLetters[count]; + count += 1; + if (renderedLetter._mdf.m) { + if (!this.isMasked) { + textSpan.style.transform = textSpan.style.webkitTransform = renderedLetter.m; + } else { + textSpan.setAttribute('transform', renderedLetter.m); + } + } + ////textSpan.setAttribute('opacity',renderedLetter.o); + textSpan.style.opacity = renderedLetter.o; + if (renderedLetter.sw && renderedLetter._mdf.sw) { + textPath.setAttribute('stroke-width', renderedLetter.sw); + } + if (renderedLetter.sc && renderedLetter._mdf.sc) { + textPath.setAttribute('stroke', renderedLetter.sc); + } + if (renderedLetter.fc && renderedLetter._mdf.fc) { + textPath.setAttribute('fill', renderedLetter.fc); + textPath.style.color = renderedLetter.fc; + } + } + + if (this.innerElem.getBBox && !this.hidden && (this._isFirstFrame || this._mdf)) { + var boundingBox = this.innerElem.getBBox(); + + if (this.currentBBox.w !== boundingBox.width) { + this.currentBBox.w = boundingBox.width; + this.svgElement.setAttribute('width', boundingBox.width); + } + if (this.currentBBox.h !== boundingBox.height) { + this.currentBBox.h = boundingBox.height; + this.svgElement.setAttribute('height', boundingBox.height); + } + + var margin = 1; + if (this.currentBBox.w !== (boundingBox.width + margin * 2) || this.currentBBox.h !== (boundingBox.height + margin * 2) || this.currentBBox.x !== (boundingBox.x - margin) || this.currentBBox.y !== (boundingBox.y - margin)) { + this.currentBBox.w = boundingBox.width + margin * 2; + this.currentBBox.h = boundingBox.height + margin * 2; + this.currentBBox.x = boundingBox.x - margin; + this.currentBBox.y = boundingBox.y - margin; + + this.svgElement.setAttribute('viewBox', this.currentBBox.x + ' ' + this.currentBBox.y + ' ' + this.currentBBox.w + ' ' + this.currentBBox.h); + this.svgElement.style.transform = this.svgElement.style.webkitTransform = 'translate(' + this.currentBBox.x + 'px,' + this.currentBBox.y + 'px)'; + } + } + }; + function HImageElement(data, globalData, comp) { + this.assetData = globalData.getAssetData(data.refId); + this.initElement(data, globalData, comp); + } + + extendPrototype([BaseElement, TransformElement, HBaseElement, HSolidElement, HierarchyElement, FrameElement, RenderableElement], HImageElement); + + + HImageElement.prototype.createContent = function () { + var assetPath = this.globalData.getAssetsPath(this.assetData); + var img = new Image(); + + if (this.data.hasMask) { + this.imageElem = createNS('image'); + this.imageElem.setAttribute('width', this.assetData.w + "px"); + this.imageElem.setAttribute('height', this.assetData.h + "px"); + this.imageElem.setAttributeNS('http://www.w3.org/1999/xlink', 'href', assetPath); + this.layerElement.appendChild(this.imageElem); + this.baseElement.setAttribute('width', this.assetData.w); + this.baseElement.setAttribute('height', this.assetData.h); + } else { + this.layerElement.appendChild(img); + } + img.src = assetPath; + if (this.data.ln) { + this.baseElement.setAttribute('id', this.data.ln); + } + }; + function HCameraElement(data, globalData, comp) { + this.initFrame(); + this.initBaseData(data, globalData, comp); + this.initHierarchy(); + var getProp = PropertyFactory.getProp; + this.pe = getProp(this, data.pe, 0, 0, this); + if (data.ks.p.s) { + this.px = getProp(this, data.ks.p.x, 1, 0, this); + this.py = getProp(this, data.ks.p.y, 1, 0, this); + this.pz = getProp(this, data.ks.p.z, 1, 0, this); + } else { + this.p = getProp(this, data.ks.p, 1, 0, this); + } + if (data.ks.a) { + this.a = getProp(this, data.ks.a, 1, 0, this); + } + if (data.ks.or.k.length && data.ks.or.k[0].to) { + var i, len = data.ks.or.k.length; + for (i = 0; i < len; i += 1) { + data.ks.or.k[i].to = null; + data.ks.or.k[i].ti = null; + } + } + this.or = getProp(this, data.ks.or, 1, degToRads, this); + this.or.sh = true; + this.rx = getProp(this, data.ks.rx, 0, degToRads, this); + this.ry = getProp(this, data.ks.ry, 0, degToRads, this); + this.rz = getProp(this, data.ks.rz, 0, degToRads, this); + this.mat = new Matrix(); + this._prevMat = new Matrix(); + this._isFirstFrame = true; + + // TODO: find a better way to make the HCamera element to be compatible with the LayerInterface and TransformInterface. + this.finalTransform = { + mProp: this + }; + } + extendPrototype([BaseElement, FrameElement, HierarchyElement], HCameraElement); + + HCameraElement.prototype.setup = function () { + var i, len = this.comp.threeDElements.length, comp; + for (i = 0; i < len; i += 1) { + //[perspectiveElem,container] + comp = this.comp.threeDElements[i]; + if (comp.type === '3d') { + comp.perspectiveElem.style.perspective = comp.perspectiveElem.style.webkitPerspective = this.pe.v + 'px'; + comp.container.style.transformOrigin = comp.container.style.mozTransformOrigin = comp.container.style.webkitTransformOrigin = "0px 0px 0px"; + comp.perspectiveElem.style.transform = comp.perspectiveElem.style.webkitTransform = 'matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1)'; + } + } + }; + + HCameraElement.prototype.createElements = function () { + }; + + HCameraElement.prototype.hide = function () { + }; + + HCameraElement.prototype.renderFrame = function () { + var _mdf = this._isFirstFrame; + var i, len; + if (this.hierarchy) { + len = this.hierarchy.length; + for (i = 0; i < len; i += 1) { + _mdf = this.hierarchy[i].finalTransform.mProp._mdf || _mdf; + } + } + if (_mdf || this.pe._mdf || (this.p && this.p._mdf) || (this.px && (this.px._mdf || this.py._mdf || this.pz._mdf)) || this.rx._mdf || this.ry._mdf || this.rz._mdf || this.or._mdf || (this.a && this.a._mdf)) { + this.mat.reset(); + + if (this.hierarchy) { + var mat; + len = this.hierarchy.length - 1; + for (i = len; i >= 0; i -= 1) { + var mTransf = this.hierarchy[i].finalTransform.mProp; + this.mat.translate(-mTransf.p.v[0], -mTransf.p.v[1], mTransf.p.v[2]); + this.mat.rotateX(-mTransf.or.v[0]).rotateY(-mTransf.or.v[1]).rotateZ(mTransf.or.v[2]); + this.mat.rotateX(-mTransf.rx.v).rotateY(-mTransf.ry.v).rotateZ(mTransf.rz.v); + this.mat.scale(1 / mTransf.s.v[0], 1 / mTransf.s.v[1], 1 / mTransf.s.v[2]); + this.mat.translate(mTransf.a.v[0], mTransf.a.v[1], mTransf.a.v[2]); + } + } + if (this.p) { + this.mat.translate(-this.p.v[0], -this.p.v[1], this.p.v[2]); + } else { + this.mat.translate(-this.px.v, -this.py.v, this.pz.v); + } + if (this.a) { + var diffVector + if (this.p) { + diffVector = [this.p.v[0] - this.a.v[0], this.p.v[1] - this.a.v[1], this.p.v[2] - this.a.v[2]]; + } else { + diffVector = [this.px.v - this.a.v[0], this.py.v - this.a.v[1], this.pz.v - this.a.v[2]]; + } + var mag = Math.sqrt(Math.pow(diffVector[0], 2) + Math.pow(diffVector[1], 2) + Math.pow(diffVector[2], 2)); + //var lookDir = getNormalizedPoint(getDiffVector(this.a.v,this.p.v)); + var lookDir = [diffVector[0] / mag, diffVector[1] / mag, diffVector[2] / mag]; + var lookLengthOnXZ = Math.sqrt(lookDir[2] * lookDir[2] + lookDir[0] * lookDir[0]); + var m_rotationX = (Math.atan2(lookDir[1], lookLengthOnXZ)); + var m_rotationY = (Math.atan2(lookDir[0], -lookDir[2])); + this.mat.rotateY(m_rotationY).rotateX(-m_rotationX); + + } + this.mat.rotateX(-this.rx.v).rotateY(-this.ry.v).rotateZ(this.rz.v); + this.mat.rotateX(-this.or.v[0]).rotateY(-this.or.v[1]).rotateZ(this.or.v[2]); + this.mat.translate(this.globalData.compSize.w / 2, this.globalData.compSize.h / 2, 0); + this.mat.translate(0, 0, this.pe.v); + + + + + var hasMatrixChanged = !this._prevMat.equals(this.mat); + if ((hasMatrixChanged || this.pe._mdf) && this.comp.threeDElements) { + len = this.comp.threeDElements.length; + var comp; + for (i = 0; i < len; i += 1) { + comp = this.comp.threeDElements[i]; + if (comp.type === '3d') { + if (hasMatrixChanged) { + comp.container.style.transform = comp.container.style.webkitTransform = this.mat.toCSS(); + } + if (this.pe._mdf) { + comp.perspectiveElem.style.perspective = comp.perspectiveElem.style.webkitPerspective = this.pe.v + 'px'; + } + } + } + this.mat.clone(this._prevMat); + } + } + this._isFirstFrame = false; + }; + + HCameraElement.prototype.prepareFrame = function (num) { + this.prepareProperties(num, true); + }; + + HCameraElement.prototype.destroy = function () { + }; + HCameraElement.prototype.getBaseElement = function () { return null; }; + function HEffects() { + } + HEffects.prototype.renderFrame = function () { }; + var animationManager = (function () { + var moduleOb = {}; + var registeredAnimations = []; + var initTime = 0; + var len = 0; + var playingAnimationsNum = 0; + var _stopped = true; + var _isFrozen = false; + + function removeElement(ev) { + var i = 0; + var animItem = ev.target; + while (i < len) { + if (registeredAnimations[i].animation === animItem) { + registeredAnimations.splice(i, 1); + i -= 1; + len -= 1; + if (!animItem.isPaused) { + subtractPlayingCount(); + } + } + i += 1; + } + } + + function registerAnimation(element, animationData) { + if (!element) { + return null; + } + var i = 0; + while (i < len) { + if (registeredAnimations[i].elem == element && registeredAnimations[i].elem !== null) { + return registeredAnimations[i].animation; + } + i += 1; + } + var animItem = new AnimationItem(); + setupAnimation(animItem, element); + animItem.setData(element, animationData); + return animItem; + } + + function getRegisteredAnimations() { + var i, len = registeredAnimations.length; + var animations = []; + for (i = 0; i < len; i += 1) { + animations.push(registeredAnimations[i].animation); + } + return animations; + } + + function addPlayingCount() { + playingAnimationsNum += 1; + activate(); + } + + function subtractPlayingCount() { + playingAnimationsNum -= 1; + } + + function setupAnimation(animItem, element) { + animItem.addEventListener('destroy', removeElement); + animItem.addEventListener('_active', addPlayingCount); + animItem.addEventListener('_idle', subtractPlayingCount); + registeredAnimations.push({ elem: element, animation: animItem }); + len += 1; + } + + function loadAnimation(params) { + var animItem = new AnimationItem(); + setupAnimation(animItem, null); + animItem.setParams(params); + return animItem; + } + + + function setSpeed(val, animation) { + var i; + for (i = 0; i < len; i += 1) { + registeredAnimations[i].animation.setSpeed(val, animation); + } + } + + function setDirection(val, animation) { + var i; + for (i = 0; i < len; i += 1) { + registeredAnimations[i].animation.setDirection(val, animation); + } + } + + function play(animation) { + var i; + for (i = 0; i < len; i += 1) { + registeredAnimations[i].animation.play(animation); + } + } + function resume(nowTime) { + var elapsedTime = nowTime - initTime; + var i; + for (i = 0; i < len; i += 1) { + registeredAnimations[i].animation.advanceTime(elapsedTime); + } + initTime = nowTime; + if (playingAnimationsNum && !_isFrozen) { + window.requestAnimationFrame(resume); + } else { + _stopped = true; + } + } + + function first(nowTime) { + initTime = nowTime; + window.requestAnimationFrame(resume); + } + + function pause(animation) { + var i; + for (i = 0; i < len; i += 1) { + registeredAnimations[i].animation.pause(animation); + } + } + + function goToAndStop(value, isFrame, animation) { + var i; + for (i = 0; i < len; i += 1) { + registeredAnimations[i].animation.goToAndStop(value, isFrame, animation); + } + } + + function stop(animation) { + var i; + for (i = 0; i < len; i += 1) { + registeredAnimations[i].animation.stop(animation); + } + } + + function togglePause(animation) { + var i; + for (i = 0; i < len; i += 1) { + registeredAnimations[i].animation.togglePause(animation); + } + } + + function destroy(animation) { + var i; + for (i = (len - 1); i >= 0; i -= 1) { + registeredAnimations[i].animation.destroy(animation); + } + } + + function searchAnimations(animationData, standalone, renderer) { + var animElements = [].concat([].slice.call(document.getElementsByClassName('lottie')), + [].slice.call(document.getElementsByClassName('bodymovin'))); + var i, len = animElements.length; + for (i = 0; i < len; i += 1) { + if (renderer) { + animElements[i].setAttribute('data-bm-type', renderer); + } + registerAnimation(animElements[i], animationData); + } + if (standalone && len === 0) { + if (!renderer) { + renderer = 'svg'; + } + var body = document.getElementsByTagName('body')[0]; + body.innerHTML = ''; + var div = createTag('div'); + div.style.width = '100%'; + div.style.height = '100%'; + div.setAttribute('data-bm-type', renderer); + body.appendChild(div); + registerAnimation(div, animationData); + } + } + + function resize() { + var i; + for (i = 0; i < len; i += 1) { + registeredAnimations[i].animation.resize(); + } + } + + function activate() { + if (!_isFrozen && playingAnimationsNum) { + if (_stopped) { + window.requestAnimationFrame(first); + _stopped = false; + } + } + } + + function freeze() { + _isFrozen = true; + } + + function unfreeze() { + _isFrozen = false; + activate(); + } + + moduleOb.registerAnimation = registerAnimation; + moduleOb.loadAnimation = loadAnimation; + moduleOb.setSpeed = setSpeed; + moduleOb.setDirection = setDirection; + moduleOb.play = play; + moduleOb.pause = pause; + moduleOb.stop = stop; + moduleOb.togglePause = togglePause; + moduleOb.searchAnimations = searchAnimations; + moduleOb.resize = resize; + //moduleOb.start = start; + moduleOb.goToAndStop = goToAndStop; + moduleOb.destroy = destroy; + moduleOb.freeze = freeze; + moduleOb.unfreeze = unfreeze; + moduleOb.getRegisteredAnimations = getRegisteredAnimations; + return moduleOb; + }()); + + var AnimationItem = function () { + this._cbs = []; + this.name = ''; + this.path = ''; + this.isLoaded = false; + this.currentFrame = 0; + this.currentRawFrame = 0; + this.firstFrame = 0; + this.totalFrames = 0; + this.frameRate = 0; + this.frameMult = 0; + this.playSpeed = 1; + this.playDirection = 1; + this.playCount = 0; + this.animationData = {}; + this.assets = []; + this.isPaused = true; + this.autoplay = false; + this.loop = true; + this.renderer = null; + this.animationID = createElementID(); + this.assetsPath = ''; + this.timeCompleted = 0; + this.segmentPos = 0; + this.subframeEnabled = subframeEnabled; + this.segments = []; + this._idle = true; + this._completedLoop = false; + this.projectInterface = ProjectInterface(); + this.imagePreloader = new ImagePreloader(); + }; + + extendPrototype([BaseEvent], AnimationItem); + + AnimationItem.prototype.setParams = function (params) { + if (params.context) { + this.context = params.context; + } + if (params.wrapper || params.container) { + this.wrapper = params.wrapper || params.container; + } + var animType = params.animType ? params.animType : params.renderer ? params.renderer : 'svg'; + switch (animType) { + case 'canvas': + this.renderer = new CanvasRenderer(this, params.rendererSettings); + break; + case 'svg': + this.renderer = new SVGRenderer(this, params.rendererSettings); + break; + default: + this.renderer = new HybridRenderer(this, params.rendererSettings); + break; + } + this.renderer.setProjectInterface(this.projectInterface); + this.animType = animType; + + if (params.loop === '' || params.loop === null) { + } else if (params.loop === false) { + this.loop = false; + } else if (params.loop === true) { + this.loop = true; + } else { + this.loop = parseInt(params.loop); + } + this.autoplay = 'autoplay' in params ? params.autoplay : true; + this.name = params.name ? params.name : ''; + this.autoloadSegments = params.hasOwnProperty('autoloadSegments') ? params.autoloadSegments : true; + this.assetsPath = params.assetsPath; + this.initialSegment = params.initialSegment; + if (params.animationData) { + this.configAnimation(params.animationData); + } else if (params.path) { + + if (params.path.lastIndexOf('\\') !== -1) { + this.path = params.path.substr(0, params.path.lastIndexOf('\\') + 1); + } else { + this.path = params.path.substr(0, params.path.lastIndexOf('/') + 1); + } + this.fileName = params.path.substr(params.path.lastIndexOf('/') + 1); + this.fileName = this.fileName.substr(0, this.fileName.lastIndexOf('.json')); + + assetLoader.load(params.path, this.configAnimation.bind(this), function () { + this.trigger('data_failed'); + }.bind(this)); + } + + }; + + AnimationItem.prototype.setData = function (wrapper, animationData) { + var params = { + wrapper: wrapper, + animationData: animationData ? (typeof animationData === "object") ? animationData : JSON.parse(animationData) : null + }; + var wrapperAttributes = wrapper.attributes; + + params.path = wrapperAttributes.getNamedItem('data-animation-path') ? wrapperAttributes.getNamedItem('data-animation-path').value : wrapperAttributes.getNamedItem('data-bm-path') ? wrapperAttributes.getNamedItem('data-bm-path').value : wrapperAttributes.getNamedItem('bm-path') ? wrapperAttributes.getNamedItem('bm-path').value : ''; + params.animType = wrapperAttributes.getNamedItem('data-anim-type') ? wrapperAttributes.getNamedItem('data-anim-type').value : wrapperAttributes.getNamedItem('data-bm-type') ? wrapperAttributes.getNamedItem('data-bm-type').value : wrapperAttributes.getNamedItem('bm-type') ? wrapperAttributes.getNamedItem('bm-type').value : wrapperAttributes.getNamedItem('data-bm-renderer') ? wrapperAttributes.getNamedItem('data-bm-renderer').value : wrapperAttributes.getNamedItem('bm-renderer') ? wrapperAttributes.getNamedItem('bm-renderer').value : 'canvas'; + + var loop = wrapperAttributes.getNamedItem('data-anim-loop') ? wrapperAttributes.getNamedItem('data-anim-loop').value : wrapperAttributes.getNamedItem('data-bm-loop') ? wrapperAttributes.getNamedItem('data-bm-loop').value : wrapperAttributes.getNamedItem('bm-loop') ? wrapperAttributes.getNamedItem('bm-loop').value : ''; + if (loop === '') { + } else if (loop === 'false') { + params.loop = false; + } else if (loop === 'true') { + params.loop = true; + } else { + params.loop = parseInt(loop); + } + var autoplay = wrapperAttributes.getNamedItem('data-anim-autoplay') ? wrapperAttributes.getNamedItem('data-anim-autoplay').value : wrapperAttributes.getNamedItem('data-bm-autoplay') ? wrapperAttributes.getNamedItem('data-bm-autoplay').value : wrapperAttributes.getNamedItem('bm-autoplay') ? wrapperAttributes.getNamedItem('bm-autoplay').value : true; + params.autoplay = autoplay !== "false"; + + params.name = wrapperAttributes.getNamedItem('data-name') ? wrapperAttributes.getNamedItem('data-name').value : wrapperAttributes.getNamedItem('data-bm-name') ? wrapperAttributes.getNamedItem('data-bm-name').value : wrapperAttributes.getNamedItem('bm-name') ? wrapperAttributes.getNamedItem('bm-name').value : ''; + var prerender = wrapperAttributes.getNamedItem('data-anim-prerender') ? wrapperAttributes.getNamedItem('data-anim-prerender').value : wrapperAttributes.getNamedItem('data-bm-prerender') ? wrapperAttributes.getNamedItem('data-bm-prerender').value : wrapperAttributes.getNamedItem('bm-prerender') ? wrapperAttributes.getNamedItem('bm-prerender').value : ''; + + if (prerender === 'false') { + params.prerender = false; + } + this.setParams(params); + }; + + AnimationItem.prototype.includeLayers = function (data) { + if (data.op > this.animationData.op) { + this.animationData.op = data.op; + this.totalFrames = Math.floor(data.op - this.animationData.ip); + } + var layers = this.animationData.layers; + var i, len = layers.length; + var newLayers = data.layers; + var j, jLen = newLayers.length; + for (j = 0; j < jLen; j += 1) { + i = 0; + while (i < len) { + if (layers[i].id == newLayers[j].id) { + layers[i] = newLayers[j]; + break; + } + i += 1; + } + } + if (data.chars || data.fonts) { + this.renderer.globalData.fontManager.addChars(data.chars); + this.renderer.globalData.fontManager.addFonts(data.fonts, this.renderer.globalData.defs); + } + if (data.assets) { + len = data.assets.length; + for (i = 0; i < len; i += 1) { + this.animationData.assets.push(data.assets[i]); + } + } + this.animationData.__complete = false; + dataManager.completeData(this.animationData, this.renderer.globalData.fontManager); + this.renderer.includeLayers(data.layers); + if (expressionsPlugin) { + expressionsPlugin.initExpressions(this); + } + this.loadNextSegment(); + }; + + AnimationItem.prototype.loadNextSegment = function () { + var segments = this.animationData.segments; + if (!segments || segments.length === 0 || !this.autoloadSegments) { + this.trigger('data_ready'); + this.timeCompleted = this.totalFrames; + return; + } + var segment = segments.shift(); + this.timeCompleted = segment.time * this.frameRate; + var segmentPath = this.path + this.fileName + '_' + this.segmentPos + '.json'; + this.segmentPos += 1; + assetLoader.load(segmentPath, this.includeLayers.bind(this), function () { + this.trigger('data_failed'); + }.bind(this)); + }; + + AnimationItem.prototype.loadSegments = function () { + var segments = this.animationData.segments; + if (!segments) { + this.timeCompleted = this.totalFrames; + } + this.loadNextSegment(); + }; + + AnimationItem.prototype.imagesLoaded = function () { + this.trigger('loaded_images'); + this.checkLoaded() + } + + AnimationItem.prototype.preloadImages = function () { + this.imagePreloader.setAssetsPath(this.assetsPath); + this.imagePreloader.setPath(this.path); + this.imagePreloader.loadAssets(this.animationData.assets, this.imagesLoaded.bind(this)); + } + + AnimationItem.prototype.configAnimation = function (animData) { + if (!this.renderer) { + return; + } + try { + this.animationData = animData; + + if (this.initialSegment) { + this.totalFrames = Math.floor(this.initialSegment[1] - this.initialSegment[0]); + this.firstFrame = Math.round(this.initialSegment[0]); + } else { + this.totalFrames = Math.floor(this.animationData.op - this.animationData.ip); + this.firstFrame = Math.round(this.animationData.ip); + } + this.renderer.configAnimation(animData); + if (!animData.assets) { + animData.assets = []; + } + + this.assets = this.animationData.assets; + this.frameRate = this.animationData.fr; + this.frameMult = this.animationData.fr / 1000; + this.renderer.searchExtraCompositions(animData.assets); + this.trigger('config_ready'); + this.preloadImages(); + this.loadSegments(); + this.updaFrameModifier(); + this.waitForFontsLoaded(); + } catch (error) { + this.triggerConfigError(error); + } + }; + + AnimationItem.prototype.waitForFontsLoaded = function () { + if (!this.renderer) { + return; + } + if (this.renderer.globalData.fontManager.loaded()) { + this.checkLoaded(); + } else { + setTimeout(this.waitForFontsLoaded.bind(this), 20); + } + } + + AnimationItem.prototype.checkLoaded = function () { + if (!this.isLoaded && this.renderer.globalData.fontManager.loaded() && (this.imagePreloader.loaded() || this.renderer.rendererType !== 'canvas')) { + this.isLoaded = true; + dataManager.completeData(this.animationData, this.renderer.globalData.fontManager); + if (expressionsPlugin) { + expressionsPlugin.initExpressions(this); + } + this.renderer.initItems(); + setTimeout(function () { + this.trigger('DOMLoaded'); + }.bind(this), 0); + this.gotoFrame(); + if (this.autoplay) { + this.play(); + } + } + }; + + AnimationItem.prototype.resize = function () { + this.renderer.updateContainerSize(); + }; + + AnimationItem.prototype.setSubframe = function (flag) { + this.subframeEnabled = flag ? true : false; + }; + + AnimationItem.prototype.gotoFrame = function () { + this.currentFrame = this.subframeEnabled ? this.currentRawFrame : ~~this.currentRawFrame; + + if (this.timeCompleted !== this.totalFrames && this.currentFrame > this.timeCompleted) { + this.currentFrame = this.timeCompleted; + } + this.trigger('enterFrame'); + this.renderFrame(); + }; + + AnimationItem.prototype.renderFrame = function () { + if (this.isLoaded === false) { + return; + } + try { + this.renderer.renderFrame(this.currentFrame + this.firstFrame); + } catch (error) { + this.triggerRenderFrameError(error); + } + }; + + AnimationItem.prototype.play = function (name) { + if (name && this.name != name) { + return; + } + if (this.isPaused === true) { + this.isPaused = false; + if (this._idle) { + this._idle = false; + this.trigger('_active'); + } + } + }; + + AnimationItem.prototype.pause = function (name) { + if (name && this.name != name) { + return; + } + if (this.isPaused === false) { + this.isPaused = true; + this._idle = true; + this.trigger('_idle'); + } + }; + + AnimationItem.prototype.togglePause = function (name) { + if (name && this.name != name) { + return; + } + if (this.isPaused === true) { + this.play(); + } else { + this.pause(); + } + }; + + AnimationItem.prototype.stop = function (name) { + if (name && this.name != name) { + return; + } + this.pause(); + this.playCount = 0; + this._completedLoop = false; + this.setCurrentRawFrameValue(0); + }; + + AnimationItem.prototype.goToAndStop = function (value, isFrame, name) { + if (name && this.name != name) { + return; + } + if (isFrame) { + this.setCurrentRawFrameValue(value); + } else { + this.setCurrentRawFrameValue(value * this.frameModifier); + } + this.pause(); + }; + + AnimationItem.prototype.goToAndPlay = function (value, isFrame, name) { + this.goToAndStop(value, isFrame, name); + this.play(); + }; + + AnimationItem.prototype.advanceTime = function (value) { + if (this.isPaused === true || this.isLoaded === false) { + return; + } + var nextValue = this.currentRawFrame + value * this.frameModifier; + var _isComplete = false; + // Checking if nextValue > totalFrames - 1 for addressing non looping and looping animations. + // If animation won't loop, it should stop at totalFrames - 1. If it will loop it should complete the last frame and then loop. + if (nextValue >= this.totalFrames - 1 && this.frameModifier > 0) { + if (!this.loop || this.playCount === this.loop) { + if (!this.checkSegments(nextValue > this.totalFrames ? nextValue % this.totalFrames : 0)) { + _isComplete = true; + nextValue = this.totalFrames - 1; + } + } else if (nextValue >= this.totalFrames) { + this.playCount += 1; + if (!this.checkSegments(nextValue % this.totalFrames)) { + this.setCurrentRawFrameValue(nextValue % this.totalFrames); + this._completedLoop = true; + this.trigger('loopComplete'); + } + } else { + this.setCurrentRawFrameValue(nextValue); + } + } else if (nextValue < 0) { + if (!this.checkSegments(nextValue % this.totalFrames)) { + if (this.loop && !(this.playCount-- <= 0 && this.loop !== true)) { + this.setCurrentRawFrameValue(this.totalFrames + (nextValue % this.totalFrames)); + if (!this._completedLoop) { + this._completedLoop = true; + } else { + this.trigger('loopComplete'); + } + } else { + _isComplete = true; + nextValue = 0; + } + } + } else { + this.setCurrentRawFrameValue(nextValue); + } + if (_isComplete) { + this.setCurrentRawFrameValue(nextValue); + this.pause(); + this.trigger('complete'); + } + }; + + AnimationItem.prototype.adjustSegment = function (arr, offset) { + this.playCount = 0; + if (arr[1] < arr[0]) { + if (this.frameModifier > 0) { + if (this.playSpeed < 0) { + this.setSpeed(-this.playSpeed); + } else { + this.setDirection(-1); + } + } + this.timeCompleted = this.totalFrames = arr[0] - arr[1]; + this.firstFrame = arr[1]; + this.setCurrentRawFrameValue(this.totalFrames - 0.001 - offset); + } else if (arr[1] > arr[0]) { + if (this.frameModifier < 0) { + if (this.playSpeed < 0) { + this.setSpeed(-this.playSpeed); + } else { + this.setDirection(1); + } + } + this.timeCompleted = this.totalFrames = arr[1] - arr[0]; + this.firstFrame = arr[0]; + this.setCurrentRawFrameValue(0.001 + offset); + } + this.trigger('segmentStart'); + }; + AnimationItem.prototype.setSegment = function (init, end) { + var pendingFrame = -1; + if (this.isPaused) { + if (this.currentRawFrame + this.firstFrame < init) { + pendingFrame = init; + } else if (this.currentRawFrame + this.firstFrame > end) { + pendingFrame = end - init; + } + } + + this.firstFrame = init; + this.timeCompleted = this.totalFrames = end - init; + if (pendingFrame !== -1) { + this.goToAndStop(pendingFrame, true); + } + }; + + AnimationItem.prototype.playSegments = function (arr, forceFlag) { + if (forceFlag) { + this.segments.length = 0; + } + if (typeof arr[0] === 'object') { + var i, len = arr.length; + for (i = 0; i < len; i += 1) { + this.segments.push(arr[i]); + } + } else { + this.segments.push(arr); + } + if (this.segments.length && forceFlag) { + this.adjustSegment(this.segments.shift(), 0); + } + if (this.isPaused) { + this.play(); + } + }; + + AnimationItem.prototype.resetSegments = function (forceFlag) { + this.segments.length = 0; + this.segments.push([this.animationData.ip, this.animationData.op]); + //this.segments.push([this.animationData.ip*this.frameRate,Math.floor(this.animationData.op - this.animationData.ip+this.animationData.ip*this.frameRate)]); + if (forceFlag) { + this.checkSegments(0); + } + }; + AnimationItem.prototype.checkSegments = function (offset) { + if (this.segments.length) { + this.adjustSegment(this.segments.shift(), offset); + return true; + } + return false; + }; + + AnimationItem.prototype.destroy = function (name) { + if ((name && this.name != name) || !this.renderer) { + return; + } + this.renderer.destroy(); + this.imagePreloader.destroy(); + this.trigger('destroy'); + this._cbs = null; + this.onEnterFrame = this.onLoopComplete = this.onComplete = this.onSegmentStart = this.onDestroy = null; + this.renderer = null; + }; + + AnimationItem.prototype.setCurrentRawFrameValue = function (value) { + this.currentRawFrame = value; + this.gotoFrame(); + }; + + AnimationItem.prototype.setSpeed = function (val) { + this.playSpeed = val; + this.updaFrameModifier(); + }; + + AnimationItem.prototype.setDirection = function (val) { + this.playDirection = val < 0 ? -1 : 1; + this.updaFrameModifier(); + }; + + AnimationItem.prototype.updaFrameModifier = function () { + this.frameModifier = this.frameMult * this.playSpeed * this.playDirection; + }; + + AnimationItem.prototype.getPath = function () { + return this.path; + }; + + AnimationItem.prototype.getAssetsPath = function (assetData) { + var path = ''; + if (assetData.e) { + path = assetData.p; + } else if (this.assetsPath) { + var imagePath = assetData.p; + if (imagePath.indexOf('images/') !== -1) { + imagePath = imagePath.split('/')[1]; + } + path = this.assetsPath + imagePath; + } else { + path = this.path; + path += assetData.u ? assetData.u : ''; + path += assetData.p; + } + return path; + }; + + AnimationItem.prototype.getAssetData = function (id) { + var i = 0, len = this.assets.length; + while (i < len) { + if (id == this.assets[i].id) { + return this.assets[i]; + } + i += 1; + } + }; + + AnimationItem.prototype.hide = function () { + this.renderer.hide(); + }; + + AnimationItem.prototype.show = function () { + this.renderer.show(); + }; + + AnimationItem.prototype.getDuration = function (isFrame) { + return isFrame ? this.totalFrames : this.totalFrames / this.frameRate; + }; + + AnimationItem.prototype.trigger = function (name) { + if (this._cbs && this._cbs[name]) { + switch (name) { + case 'enterFrame': + this.triggerEvent(name, new BMEnterFrameEvent(name, this.currentFrame, this.totalFrames, this.frameModifier)); + break; + case 'loopComplete': + this.triggerEvent(name, new BMCompleteLoopEvent(name, this.loop, this.playCount, this.frameMult)); + break; + case 'complete': + this.triggerEvent(name, new BMCompleteEvent(name, this.frameMult)); + break; + case 'segmentStart': + this.triggerEvent(name, new BMSegmentStartEvent(name, this.firstFrame, this.totalFrames)); + break; + case 'destroy': + this.triggerEvent(name, new BMDestroyEvent(name, this)); + break; + default: + this.triggerEvent(name); + } + } + if (name === 'enterFrame' && this.onEnterFrame) { + this.onEnterFrame.call(this, new BMEnterFrameEvent(name, this.currentFrame, this.totalFrames, this.frameMult)); + } + if (name === 'loopComplete' && this.onLoopComplete) { + this.onLoopComplete.call(this, new BMCompleteLoopEvent(name, this.loop, this.playCount, this.frameMult)); + } + if (name === 'complete' && this.onComplete) { + this.onComplete.call(this, new BMCompleteEvent(name, this.frameMult)); + } + if (name === 'segmentStart' && this.onSegmentStart) { + this.onSegmentStart.call(this, new BMSegmentStartEvent(name, this.firstFrame, this.totalFrames)); + } + if (name === 'destroy' && this.onDestroy) { + this.onDestroy.call(this, new BMDestroyEvent(name, this)); + } + }; + + AnimationItem.prototype.triggerRenderFrameError = function (nativeError) { + + var error = new BMRenderFrameErrorEvent(nativeError, this.currentFrame); + this.triggerEvent('error', error); + + if (this.onError) { + this.onError.call(this, error); + } + } + + AnimationItem.prototype.triggerConfigError = function (nativeError) { + + var error = new BMConfigErrorEvent(nativeError, this.currentFrame); + this.triggerEvent('error', error); + + if (this.onError) { + this.onError.call(this, error); + } + } + var Expressions = (function () { + var ob = {}; + ob.initExpressions = initExpressions; + + + function initExpressions(animation) { + + var stackCount = 0; + var registers = []; + + function pushExpression() { + stackCount += 1; + } + + function popExpression() { + stackCount -= 1; + if (stackCount === 0) { + releaseInstances(); + } + } + + function registerExpressionProperty(expression) { + if (registers.indexOf(expression) === -1) { + registers.push(expression) + } + } + + function releaseInstances() { + var i, len = registers.length; + for (i = 0; i < len; i += 1) { + registers[i].release(); + } + registers.length = 0; + } + + animation.renderer.compInterface = CompExpressionInterface(animation.renderer); + animation.renderer.globalData.projectInterface.registerComposition(animation.renderer); + animation.renderer.globalData.pushExpression = pushExpression; + animation.renderer.globalData.popExpression = popExpression; + animation.renderer.globalData.registerExpressionProperty = registerExpressionProperty; + } + return ob; + }()); + + expressionsPlugin = Expressions; + + var ExpressionManager = (function () { + 'use strict'; + var ob = {}; + var Math = BMMath; + var window = null; + var document = null; + + function $bm_isInstanceOfArray(arr) { + return arr.constructor === Array || arr.constructor === Float32Array; + } + + function isNumerable(tOfV, v) { + return tOfV === 'number' || tOfV === 'boolean' || tOfV === 'string' || v instanceof Number; + } + + function $bm_neg(a) { + var tOfA = typeof a; + if (tOfA === 'number' || tOfA === 'boolean' || a instanceof Number) { + return -a; + } + if ($bm_isInstanceOfArray(a)) { + var i, lenA = a.length; + var retArr = []; + for (i = 0; i < lenA; i += 1) { + retArr[i] = -a[i]; + } + return retArr; + } + if (a.propType) { + return a.v; + } + } + + var easeInBez = BezierFactory.getBezierEasing(0.333, 0, .833, .833, 'easeIn').get; + var easeOutBez = BezierFactory.getBezierEasing(0.167, 0.167, .667, 1, 'easeOut').get; + var easeInOutBez = BezierFactory.getBezierEasing(.33, 0, .667, 1, 'easeInOut').get; + + function sum(a, b) { + var tOfA = typeof a; + var tOfB = typeof b; + if (tOfA === 'string' || tOfB === 'string') { + return a + b; + } + if (isNumerable(tOfA, a) && isNumerable(tOfB, b)) { + return a + b; + } + if ($bm_isInstanceOfArray(a) && isNumerable(tOfB, b)) { + a = a.slice(0); + a[0] = a[0] + b; + return a; + } + if (isNumerable(tOfA, a) && $bm_isInstanceOfArray(b)) { + b = b.slice(0); + b[0] = a + b[0]; + return b; + } + if ($bm_isInstanceOfArray(a) && $bm_isInstanceOfArray(b)) { + + var i = 0, lenA = a.length, lenB = b.length; + var retArr = []; + while (i < lenA || i < lenB) { + if ((typeof a[i] === 'number' || a[i] instanceof Number) && (typeof b[i] === 'number' || b[i] instanceof Number)) { + retArr[i] = a[i] + b[i]; + } else { + retArr[i] = b[i] === undefined ? a[i] : a[i] || b[i]; + } + i += 1; + } + return retArr; + } + return 0; + } + var add = sum; + + function sub(a, b) { + var tOfA = typeof a; + var tOfB = typeof b; + if (isNumerable(tOfA, a) && isNumerable(tOfB, b)) { + if (tOfA === 'string') { + a = parseInt(a); + } + if (tOfB === 'string') { + b = parseInt(b); + } + return a - b; + } + if ($bm_isInstanceOfArray(a) && isNumerable(tOfB, b)) { + a = a.slice(0); + a[0] = a[0] - b; + return a; + } + if (isNumerable(tOfA, a) && $bm_isInstanceOfArray(b)) { + b = b.slice(0); + b[0] = a - b[0]; + return b; + } + if ($bm_isInstanceOfArray(a) && $bm_isInstanceOfArray(b)) { + var i = 0, lenA = a.length, lenB = b.length; + var retArr = []; + while (i < lenA || i < lenB) { + if ((typeof a[i] === 'number' || a[i] instanceof Number) && (typeof b[i] === 'number' || b[i] instanceof Number)) { + retArr[i] = a[i] - b[i]; + } else { + retArr[i] = b[i] === undefined ? a[i] : a[i] || b[i]; + } + i += 1; + } + return retArr; + } + return 0; + } + + function mul(a, b) { + var tOfA = typeof a; + var tOfB = typeof b; + var arr; + if (isNumerable(tOfA, a) && isNumerable(tOfB, b)) { + return a * b; + } + + var i, len; + if ($bm_isInstanceOfArray(a) && isNumerable(tOfB, b)) { + len = a.length; + arr = createTypedArray('float32', len); + for (i = 0; i < len; i += 1) { + arr[i] = a[i] * b; + } + return arr; + } + if (isNumerable(tOfA, a) && $bm_isInstanceOfArray(b)) { + len = b.length; + arr = createTypedArray('float32', len); + for (i = 0; i < len; i += 1) { + arr[i] = a * b[i]; + } + return arr; + } + return 0; + } + + function div(a, b) { + var tOfA = typeof a; + var tOfB = typeof b; + var arr; + if (isNumerable(tOfA, a) && isNumerable(tOfB, b)) { + return a / b; + } + var i, len; + if ($bm_isInstanceOfArray(a) && isNumerable(tOfB, b)) { + len = a.length; + arr = createTypedArray('float32', len); + for (i = 0; i < len; i += 1) { + arr[i] = a[i] / b; + } + return arr; + } + if (isNumerable(tOfA, a) && $bm_isInstanceOfArray(b)) { + len = b.length; + arr = createTypedArray('float32', len); + for (i = 0; i < len; i += 1) { + arr[i] = a / b[i]; + } + return arr; + } + return 0; + } + function mod(a, b) { + if (typeof a === 'string') { + a = parseInt(a); + } + if (typeof b === 'string') { + b = parseInt(b); + } + return a % b; + } + var $bm_sum = sum; + var $bm_sub = sub; + var $bm_mul = mul; + var $bm_div = div; + var $bm_mod = mod; + + function clamp(num, min, max) { + if (min > max) { + var mm = max; + max = min; + min = mm; + } + return Math.min(Math.max(num, min), max); + } + + function radiansToDegrees(val) { + return val / degToRads; + } + var radians_to_degrees = radiansToDegrees; + + function degreesToRadians(val) { + return val * degToRads; + } + var degrees_to_radians = radiansToDegrees; + + var helperLengthArray = [0, 0, 0, 0, 0, 0]; + + function length(arr1, arr2) { + if (typeof arr1 === 'number' || arr1 instanceof Number) { + arr2 = arr2 || 0; + return Math.abs(arr1 - arr2); + } + if (!arr2) { + arr2 = helperLengthArray; + } + var i, len = Math.min(arr1.length, arr2.length); + var addedLength = 0; + for (i = 0; i < len; i += 1) { + addedLength += Math.pow(arr2[i] - arr1[i], 2); + } + return Math.sqrt(addedLength); + } + + function normalize(vec) { + return div(vec, length(vec)); + } + + function rgbToHsl(val) { + var r = val[0]; var g = val[1]; var b = val[2]; + var max = Math.max(r, g, b), min = Math.min(r, g, b); + var h, s, l = (max + min) / 2; + + if (max == min) { + h = s = 0; // achromatic + } else { + var d = max - min; + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + switch (max) { + case r: h = (g - b) / d + (g < b ? 6 : 0); break; + case g: h = (b - r) / d + 2; break; + case b: h = (r - g) / d + 4; break; + } + h /= 6; + } + + return [h, s, l, val[3]]; + } + + function hue2rgb(p, q, t) { + if (t < 0) t += 1; + if (t > 1) t -= 1; + if (t < 1 / 6) return p + (q - p) * 6 * t; + if (t < 1 / 2) return q; + if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; + return p; + } + + function hslToRgb(val) { + var h = val[0]; + var s = val[1]; + var l = val[2]; + + var r, g, b; + + if (s === 0) { + r = g = b = l; // achromatic + } else { + + var q = l < 0.5 ? l * (1 + s) : l + s - l * s; + var p = 2 * l - q; + r = hue2rgb(p, q, h + 1 / 3); + g = hue2rgb(p, q, h); + b = hue2rgb(p, q, h - 1 / 3); + } + + return [r, g, b, val[3]]; + } + + function linear(t, tMin, tMax, value1, value2) { + if (value1 === undefined || value2 === undefined) { + value1 = tMin; + value2 = tMax; + tMin = 0; + tMax = 1; + } + if (tMax < tMin) { + var _tMin = tMax; + tMax = tMin; + tMin = _tMin; + } + if (t <= tMin) { + return value1; + } else if (t >= tMax) { + return value2; + } + var perc = tMax === tMin ? 0 : (t - tMin) / (tMax - tMin); + if (!value1.length) { + return value1 + (value2 - value1) * perc; + } + var i, len = value1.length; + var arr = createTypedArray('float32', len); + for (i = 0; i < len; i += 1) { + arr[i] = value1[i] + (value2[i] - value1[i]) * perc; + } + return arr; + } + function random(min, max) { + if (max === undefined) { + if (min === undefined) { + min = 0; + max = 1; + } else { + max = min; + min = undefined; + } + } + if (max.length) { + var i, len = max.length; + if (!min) { + min = createTypedArray('float32', len); + } + var arr = createTypedArray('float32', len); + var rnd = BMMath.random(); + for (i = 0; i < len; i += 1) { + arr[i] = min[i] + rnd * (max[i] - min[i]); + } + return arr; + } + if (min === undefined) { + min = 0; + } + var rndm = BMMath.random(); + return min + rndm * (max - min); + } + + function createPath(points, inTangents, outTangents, closed) { + var i, len = points.length; + var path = shape_pool.newElement(); + path.setPathData(!!closed, len); + var arrPlaceholder = [0, 0], inVertexPoint, outVertexPoint; + for (i = 0; i < len; i += 1) { + inVertexPoint = (inTangents && inTangents[i]) ? inTangents[i] : arrPlaceholder; + outVertexPoint = (outTangents && outTangents[i]) ? outTangents[i] : arrPlaceholder; + path.setTripleAt(points[i][0], points[i][1], outVertexPoint[0] + points[i][0], outVertexPoint[1] + points[i][1], inVertexPoint[0] + points[i][0], inVertexPoint[1] + points[i][1], i, true); + } + return path; + } + + function initiateExpression(elem, data, property) { + var val = data.x; + var needsVelocity = /velocity(?![\w\d])/.test(val); + var _needsRandom = val.indexOf('random') !== -1; + var elemType = elem.data.ty; + var transform, $bm_transform, content, effect; + var thisProperty = property; + thisProperty.valueAtTime = thisProperty.getValueAtTime; + Object.defineProperty(thisProperty, 'value', { + get: function () { + return thisProperty.v + } + }) + elem.comp.frameDuration = 1 / elem.comp.globalData.frameRate; + elem.comp.displayStartTime = 0; + var inPoint = elem.data.ip / elem.comp.globalData.frameRate; + var outPoint = elem.data.op / elem.comp.globalData.frameRate; + var width = elem.data.sw ? elem.data.sw : 0; + var height = elem.data.sh ? elem.data.sh : 0; + var name = elem.data.nm; + var loopIn, loop_in, loopOut, loop_out, smooth; + var toWorld, fromWorld, fromComp, toComp, fromCompToSurface, position, rotation, anchorPoint, scale, thisLayer, thisComp, mask, valueAtTime, velocityAtTime; + var __expression_functions = []; + if (data.xf) { + var i, len = data.xf.length; + for (i = 0; i < len; i += 1) { + __expression_functions[i] = eval('(function(){ return ' + data.xf[i] + '}())'); + } + } + + var scoped_bm_rt; + var expression_function = eval('[function _expression_function(){' + val + ';scoped_bm_rt=$bm_rt}' + ']')[0]; + var numKeys = property.kf ? data.k.length : 0; + + var active = !this.data || this.data.hd !== true; + + var wiggle = function wiggle(freq, amp) { + var i, j, len = this.pv.length ? this.pv.length : 1; + var addedAmps = createTypedArray('float32', len); + freq = 5; + var iterations = Math.floor(time * freq); + i = 0; + j = 0; + while (i < iterations) { + //var rnd = BMMath.random(); + for (j = 0; j < len; j += 1) { + addedAmps[j] += -amp + amp * 2 * BMMath.random(); + //addedAmps[j] += -amp + amp*2*rnd; + } + i += 1; + } + //var rnd2 = BMMath.random(); + var periods = time * freq; + var perc = periods - Math.floor(periods); + var arr = createTypedArray('float32', len); + if (len > 1) { + for (j = 0; j < len; j += 1) { + arr[j] = this.pv[j] + addedAmps[j] + (-amp + amp * 2 * BMMath.random()) * perc; + //arr[j] = this.pv[j] + addedAmps[j] + (-amp + amp*2*rnd)*perc; + //arr[i] = this.pv[i] + addedAmp + amp1*perc + amp2*(1-perc); + } + return arr; + } else { + return this.pv + addedAmps[0] + (-amp + amp * 2 * BMMath.random()) * perc; + } + }.bind(this); + + if (thisProperty.loopIn) { + loopIn = thisProperty.loopIn.bind(thisProperty); + loop_in = loopIn; + } + + if (thisProperty.loopOut) { + loopOut = thisProperty.loopOut.bind(thisProperty); + loop_out = loopOut; + } + + if (thisProperty.smooth) { + smooth = thisProperty.smooth.bind(thisProperty); + } + + function loopInDuration(type, duration) { + return loopIn(type, duration, true); + } + + function loopOutDuration(type, duration) { + return loopOut(type, duration, true); + } + + if (this.getValueAtTime) { + valueAtTime = this.getValueAtTime.bind(this); + } + + if (this.getVelocityAtTime) { + velocityAtTime = this.getVelocityAtTime.bind(this); + } + + var comp = elem.comp.globalData.projectInterface.bind(elem.comp.globalData.projectInterface); + + function lookAt(elem1, elem2) { + var fVec = [elem2[0] - elem1[0], elem2[1] - elem1[1], elem2[2] - elem1[2]]; + var pitch = Math.atan2(fVec[0], Math.sqrt(fVec[1] * fVec[1] + fVec[2] * fVec[2])) / degToRads; + var yaw = -Math.atan2(fVec[1], fVec[2]) / degToRads; + return [yaw, pitch, 0]; + } + + function easeOut(t, tMin, tMax, val1, val2) { + return applyEase(easeOutBez, t, tMin, tMax, val1, val2); + } + + function easeIn(t, tMin, tMax, val1, val2) { + return applyEase(easeInBez, t, tMin, tMax, val1, val2); + } + + function ease(t, tMin, tMax, val1, val2) { + return applyEase(easeInOutBez, t, tMin, tMax, val1, val2); + } + + function applyEase(fn, t, tMin, tMax, val1, val2) { + if (val1 === undefined) { + val1 = tMin; + val2 = tMax; + } else { + t = (t - tMin) / (tMax - tMin); + } + t = t > 1 ? 1 : t < 0 ? 0 : t; + var mult = fn(t); + if ($bm_isInstanceOfArray(val1)) { + var i, len = val1.length; + var arr = createTypedArray('float32', len); + for (i = 0; i < len; i += 1) { + arr[i] = (val2[i] - val1[i]) * mult + val1[i]; + } + return arr; + } else { + return (val2 - val1) * mult + val1; + } + } + + function nearestKey(time) { + var i, len = data.k.length, index, keyTime; + if (!data.k.length || typeof (data.k[0]) === 'number') { + index = 0; + keyTime = 0; + } else { + index = -1; + time *= elem.comp.globalData.frameRate; + if (time < data.k[0].t) { + index = 1; + keyTime = data.k[0].t; + } else { + for (i = 0; i < len - 1; i += 1) { + if (time === data.k[i].t) { + index = i + 1; + keyTime = data.k[i].t; + break; + } else if (time > data.k[i].t && time < data.k[i + 1].t) { + if (time - data.k[i].t > data.k[i + 1].t - time) { + index = i + 2; + keyTime = data.k[i + 1].t; + } else { + index = i + 1; + keyTime = data.k[i].t; + } + break; + } + } + if (index === -1) { + index = i + 1; + keyTime = data.k[i].t; + } + } + + } + var ob = {}; + ob.index = index; + ob.time = keyTime / elem.comp.globalData.frameRate; + return ob; + } + + function key(ind) { + var ob, i, len; + if (!data.k.length || typeof (data.k[0]) === 'number') { + throw new Error('The property has no keyframe at index ' + ind); + } + ind -= 1; + ob = { + time: data.k[ind].t / elem.comp.globalData.frameRate, + value: [] + }; + var arr = data.k[ind].hasOwnProperty('s') ? data.k[ind].s : data.k[ind - 1].e; + + len = arr.length; + for (i = 0; i < len; i += 1) { + ob[i] = arr[i]; + ob.value[i] = arr[i] + } + return ob; + } + + function framesToTime(frames, fps) { + if (!fps) { + fps = elem.comp.globalData.frameRate; + } + return frames / fps; + } + + function timeToFrames(t, fps) { + if (!t && t !== 0) { + t = time; + } + if (!fps) { + fps = elem.comp.globalData.frameRate; + } + return t * fps; + } + + function seedRandom(seed) { + BMMath.seedrandom(randSeed + seed); + } + + function sourceRectAtTime() { + return elem.sourceRectAtTime(); + } + + function substring(init, end) { + if (typeof value === 'string') { + if (end === undefined) { + return value.substring(init) + } + return value.substring(init, end) + } + return ''; + } + + function substr(init, end) { + if (typeof value === 'string') { + if (end === undefined) { + return value.substr(init) + } + return value.substr(init, end) + } + return ''; + } + + function posterizeTime(framesPerSecond) { + time = framesPerSecond === 0 ? 0 : Math.floor(time * framesPerSecond) / framesPerSecond + value = valueAtTime(time) + } + + var time, velocity, value, text, textIndex, textTotal, selectorValue; + var index = elem.data.ind; + var hasParent = !!(elem.hierarchy && elem.hierarchy.length); + var parent; + var randSeed = Math.floor(Math.random() * 1000000); + var globalData = elem.globalData; + function executeExpression(_value) { + // globalData.pushExpression(); + value = _value; + if (_needsRandom) { + seedRandom(randSeed); + } + if (this.frameExpressionId === elem.globalData.frameId && this.propType !== 'textSelector') { + return value; + } + if (this.propType === 'textSelector') { + textIndex = this.textIndex; + textTotal = this.textTotal; + selectorValue = this.selectorValue; + } + if (!thisLayer) { + text = elem.layerInterface.text; + thisLayer = elem.layerInterface; + thisComp = elem.comp.compInterface; + toWorld = thisLayer.toWorld.bind(thisLayer); + fromWorld = thisLayer.fromWorld.bind(thisLayer); + fromComp = thisLayer.fromComp.bind(thisLayer); + toComp = thisLayer.toComp.bind(thisLayer); + mask = thisLayer.mask ? thisLayer.mask.bind(thisLayer) : null; + fromCompToSurface = fromComp; + } + if (!transform) { + transform = elem.layerInterface("ADBE Transform Group"); + $bm_transform = transform; + if (transform) { + anchorPoint = transform.anchorPoint; + /*position = transform.position; + rotation = transform.rotation; + scale = transform.scale;*/ + } + } + + if (elemType === 4 && !content) { + content = thisLayer("ADBE Root Vectors Group"); + } + if (!effect) { + effect = thisLayer(4); + } + hasParent = !!(elem.hierarchy && elem.hierarchy.length); + if (hasParent && !parent) { + parent = elem.hierarchy[0].layerInterface; + } + time = this.comp.renderedFrame / this.comp.globalData.frameRate; + if (needsVelocity) { + velocity = velocityAtTime(time); + } + expression_function(); + this.frameExpressionId = elem.globalData.frameId; + + + //TODO: Check if it's possible to return on ShapeInterface the .v value + if (scoped_bm_rt.propType === "shape") { + scoped_bm_rt = scoped_bm_rt.v; + } + // globalData.popExpression(); + return scoped_bm_rt; + } + return executeExpression; + } + + ob.initiateExpression = initiateExpression; + return ob; + }()); + var expressionHelpers = (function () { + + function searchExpressions(elem, data, prop) { + if (data.x) { + prop.k = true; + prop.x = true; + prop.initiateExpression = ExpressionManager.initiateExpression; + prop.effectsSequence.push(prop.initiateExpression(elem, data, prop).bind(prop)); + } + } + + function getValueAtTime(frameNum) { + frameNum *= this.elem.globalData.frameRate; + frameNum -= this.offsetTime; + if (frameNum !== this._cachingAtTime.lastFrame) { + this._cachingAtTime.lastIndex = this._cachingAtTime.lastFrame < frameNum ? this._cachingAtTime.lastIndex : 0; + this._cachingAtTime.value = this.interpolateValue(frameNum, this._cachingAtTime); + this._cachingAtTime.lastFrame = frameNum; + } + return this._cachingAtTime.value; + + } + + function getSpeedAtTime(frameNum) { + var delta = -0.01; + var v1 = this.getValueAtTime(frameNum); + var v2 = this.getValueAtTime(frameNum + delta); + var speed = 0; + if (v1.length) { + var i; + for (i = 0; i < v1.length; i += 1) { + speed += Math.pow(v2[i] - v1[i], 2); + } + speed = Math.sqrt(speed) * 100; + } else { + speed = 0; + } + return speed; + } + + function getVelocityAtTime(frameNum) { + if (this.vel !== undefined) { + return this.vel; + } + var delta = -0.001; + //frameNum += this.elem.data.st; + var v1 = this.getValueAtTime(frameNum); + var v2 = this.getValueAtTime(frameNum + delta); + var velocity; + if (v1.length) { + velocity = createTypedArray('float32', v1.length); + var i; + for (i = 0; i < v1.length; i += 1) { + //removing frameRate + //if needed, don't add it here + //velocity[i] = this.elem.globalData.frameRate*((v2[i] - v1[i])/delta); + velocity[i] = (v2[i] - v1[i]) / delta; + } + } else { + velocity = (v2 - v1) / delta; + } + return velocity; + } + + function getStaticValueAtTime() { + return this.pv; + } + + function setGroupProperty(propertyGroup) { + this.propertyGroup = propertyGroup; + } + + return { + searchExpressions: searchExpressions, + getSpeedAtTime: getSpeedAtTime, + getVelocityAtTime: getVelocityAtTime, + getValueAtTime: getValueAtTime, + getStaticValueAtTime: getStaticValueAtTime, + setGroupProperty: setGroupProperty, + } + }()); + (function addPropertyDecorator() { + + function loopOut(type, duration, durationFlag) { + if (!this.k || !this.keyframes) { + return this.pv; + } + type = type ? type.toLowerCase() : ''; + var currentFrame = this.comp.renderedFrame; + var keyframes = this.keyframes; + var lastKeyFrame = keyframes[keyframes.length - 1].t; + if (currentFrame <= lastKeyFrame) { + return this.pv; + } else { + var cycleDuration, firstKeyFrame; + if (!durationFlag) { + if (!duration || duration > keyframes.length - 1) { + duration = keyframes.length - 1; + } + firstKeyFrame = keyframes[keyframes.length - 1 - duration].t; + cycleDuration = lastKeyFrame - firstKeyFrame; + } else { + if (!duration) { + cycleDuration = Math.max(0, lastKeyFrame - this.elem.data.ip); + } else { + cycleDuration = Math.abs(lastKeyFrame - elem.comp.globalData.frameRate * duration); + } + firstKeyFrame = lastKeyFrame - cycleDuration; + } + var i, len, ret; + if (type === 'pingpong') { + var iterations = Math.floor((currentFrame - firstKeyFrame) / cycleDuration); + if (iterations % 2 !== 0) { + return this.getValueAtTime(((cycleDuration - (currentFrame - firstKeyFrame) % cycleDuration + firstKeyFrame)) / this.comp.globalData.frameRate, 0); + } + } else if (type === 'offset') { + var initV = this.getValueAtTime(firstKeyFrame / this.comp.globalData.frameRate, 0); + var endV = this.getValueAtTime(lastKeyFrame / this.comp.globalData.frameRate, 0); + var current = this.getValueAtTime(((currentFrame - firstKeyFrame) % cycleDuration + firstKeyFrame) / this.comp.globalData.frameRate, 0); + var repeats = Math.floor((currentFrame - firstKeyFrame) / cycleDuration); + if (this.pv.length) { + ret = new Array(initV.length); + len = ret.length; + for (i = 0; i < len; i += 1) { + ret[i] = (endV[i] - initV[i]) * repeats + current[i]; + } + return ret; + } + return (endV - initV) * repeats + current; + } else if (type === 'continue') { + var lastValue = this.getValueAtTime(lastKeyFrame / this.comp.globalData.frameRate, 0); + var nextLastValue = this.getValueAtTime((lastKeyFrame - 0.001) / this.comp.globalData.frameRate, 0); + if (this.pv.length) { + ret = new Array(lastValue.length); + len = ret.length; + for (i = 0; i < len; i += 1) { + ret[i] = lastValue[i] + (lastValue[i] - nextLastValue[i]) * ((currentFrame - lastKeyFrame) / this.comp.globalData.frameRate) / 0.0005; + } + return ret; + } + return lastValue + (lastValue - nextLastValue) * (((currentFrame - lastKeyFrame)) / 0.001); + } + return this.getValueAtTime((((currentFrame - firstKeyFrame) % cycleDuration + firstKeyFrame)) / this.comp.globalData.frameRate, 0); + } + } + + function loopIn(type, duration, durationFlag) { + if (!this.k) { + return this.pv; + } + type = type ? type.toLowerCase() : ''; + var currentFrame = this.comp.renderedFrame; + var keyframes = this.keyframes; + var firstKeyFrame = keyframes[0].t; + if (currentFrame >= firstKeyFrame) { + return this.pv; + } else { + var cycleDuration, lastKeyFrame; + if (!durationFlag) { + if (!duration || duration > keyframes.length - 1) { + duration = keyframes.length - 1; + } + lastKeyFrame = keyframes[duration].t; + cycleDuration = lastKeyFrame - firstKeyFrame; + } else { + if (!duration) { + cycleDuration = Math.max(0, this.elem.data.op - firstKeyFrame); + } else { + cycleDuration = Math.abs(elem.comp.globalData.frameRate * duration); + } + lastKeyFrame = firstKeyFrame + cycleDuration; + } + var i, len, ret; + if (type === 'pingpong') { + var iterations = Math.floor((firstKeyFrame - currentFrame) / cycleDuration); + if (iterations % 2 === 0) { + return this.getValueAtTime((((firstKeyFrame - currentFrame) % cycleDuration + firstKeyFrame)) / this.comp.globalData.frameRate, 0); + } + } else if (type === 'offset') { + var initV = this.getValueAtTime(firstKeyFrame / this.comp.globalData.frameRate, 0); + var endV = this.getValueAtTime(lastKeyFrame / this.comp.globalData.frameRate, 0); + var current = this.getValueAtTime((cycleDuration - (firstKeyFrame - currentFrame) % cycleDuration + firstKeyFrame) / this.comp.globalData.frameRate, 0); + var repeats = Math.floor((firstKeyFrame - currentFrame) / cycleDuration) + 1; + if (this.pv.length) { + ret = new Array(initV.length); + len = ret.length; + for (i = 0; i < len; i += 1) { + ret[i] = current[i] - (endV[i] - initV[i]) * repeats; + } + return ret; + } + return current - (endV - initV) * repeats; + } else if (type === 'continue') { + var firstValue = this.getValueAtTime(firstKeyFrame / this.comp.globalData.frameRate, 0); + var nextFirstValue = this.getValueAtTime((firstKeyFrame + 0.001) / this.comp.globalData.frameRate, 0); + if (this.pv.length) { + ret = new Array(firstValue.length); + len = ret.length; + for (i = 0; i < len; i += 1) { + ret[i] = firstValue[i] + (firstValue[i] - nextFirstValue[i]) * (firstKeyFrame - currentFrame) / 0.001; + } + return ret; + } + return firstValue + (firstValue - nextFirstValue) * (firstKeyFrame - currentFrame) / 0.001; + } + return this.getValueAtTime(((cycleDuration - (firstKeyFrame - currentFrame) % cycleDuration + firstKeyFrame)) / this.comp.globalData.frameRate, 0); + } + } + + function smooth(width, samples) { + if (!this.k) { + return this.pv; + } + width = (width || 0.4) * 0.5; + samples = Math.floor(samples || 5); + if (samples <= 1) { + return this.pv; + } + var currentTime = this.comp.renderedFrame / this.comp.globalData.frameRate; + var initFrame = currentTime - width; + var endFrame = currentTime + width; + var sampleFrequency = samples > 1 ? (endFrame - initFrame) / (samples - 1) : 1; + var i = 0, j = 0; + var value; + if (this.pv.length) { + value = createTypedArray('float32', this.pv.length); + } else { + value = 0; + } + var sampleValue; + while (i < samples) { + sampleValue = this.getValueAtTime(initFrame + i * sampleFrequency); + if (this.pv.length) { + for (j = 0; j < this.pv.length; j += 1) { + value[j] += sampleValue[j]; + } + } else { + value += sampleValue; + } + i += 1; + } + if (this.pv.length) { + for (j = 0; j < this.pv.length; j += 1) { + value[j] /= samples; + } + } else { + value /= samples; + } + return value; + } + + function getValueAtTime(frameNum) { + frameNum *= this.elem.globalData.frameRate; + frameNum -= this.offsetTime; + if (frameNum !== this._cachingAtTime.lastFrame) { + this._cachingAtTime.lastIndex = this._cachingAtTime.lastFrame < frameNum ? this._cachingAtTime.lastIndex : 0; + this._cachingAtTime.value = this.interpolateValue(frameNum, this._cachingAtTime); + this._cachingAtTime.lastFrame = frameNum; + } + return this._cachingAtTime.value; + + } + + function getTransformValueAtTime(time) { + console.warn('Transform at time not supported'); + } + + function getTransformStaticValueAtTime(time) { + + } + + var getTransformProperty = TransformPropertyFactory.getTransformProperty; + TransformPropertyFactory.getTransformProperty = function (elem, data, container) { + var prop = getTransformProperty(elem, data, container); + if (prop.dynamicProperties.length) { + prop.getValueAtTime = getTransformValueAtTime.bind(prop); + } else { + prop.getValueAtTime = getTransformStaticValueAtTime.bind(prop); + } + prop.setGroupProperty = expressionHelpers.setGroupProperty; + return prop; + }; + + var propertyGetProp = PropertyFactory.getProp; + PropertyFactory.getProp = function (elem, data, type, mult, container) { + var prop = propertyGetProp(elem, data, type, mult, container); + //prop.getVelocityAtTime = getVelocityAtTime; + //prop.loopOut = loopOut; + //prop.loopIn = loopIn; + if (prop.kf) { + prop.getValueAtTime = expressionHelpers.getValueAtTime.bind(prop); + } else { + prop.getValueAtTime = expressionHelpers.getStaticValueAtTime.bind(prop); + } + prop.setGroupProperty = expressionHelpers.setGroupProperty; + prop.loopOut = loopOut; + prop.loopIn = loopIn; + prop.smooth = smooth; + prop.getVelocityAtTime = expressionHelpers.getVelocityAtTime.bind(prop); + prop.getSpeedAtTime = expressionHelpers.getSpeedAtTime.bind(prop); + prop.numKeys = data.a === 1 ? data.k.length : 0; + prop.propertyIndex = data.ix; + var value = 0; + if (type !== 0) { + value = createTypedArray('float32', data.a === 1 ? data.k[0].s.length : data.k.length); + } + prop._cachingAtTime = { + lastFrame: initialDefaultFrame, + lastIndex: 0, + value: value + }; + expressionHelpers.searchExpressions(elem, data, prop); + if (prop.k) { + container.addDynamicProperty(prop); + } + + return prop; + }; + + function getShapeValueAtTime(frameNum) { + //For now this caching object is created only when needed instead of creating it when the shape is initialized. + if (!this._cachingAtTime) { + this._cachingAtTime = { + shapeValue: shape_pool.clone(this.pv), + lastIndex: 0, + lastTime: initialDefaultFrame + }; + } + + frameNum *= this.elem.globalData.frameRate; + frameNum -= this.offsetTime; + if (frameNum !== this._cachingAtTime.lastTime) { + this._cachingAtTime.lastIndex = this._cachingAtTime.lastTime < frameNum ? this._caching.lastIndex : 0; + this._cachingAtTime.lastTime = frameNum; + this.interpolateShape(frameNum, this._cachingAtTime.shapeValue, this._cachingAtTime); + } + return this._cachingAtTime.shapeValue; + } + + var ShapePropertyConstructorFunction = ShapePropertyFactory.getConstructorFunction(); + var KeyframedShapePropertyConstructorFunction = ShapePropertyFactory.getKeyframedConstructorFunction(); + + function ShapeExpressions() { } + ShapeExpressions.prototype = { + vertices: function (prop, time) { + if (this.k) { + this.getValue(); + } + var shapePath = this.v; + if (time !== undefined) { + shapePath = this.getValueAtTime(time, 0); + } + var i, len = shapePath._length; + var vertices = shapePath[prop]; + var points = shapePath.v; + var arr = createSizedArray(len); + for (i = 0; i < len; i += 1) { + if (prop === 'i' || prop === 'o') { + arr[i] = [vertices[i][0] - points[i][0], vertices[i][1] - points[i][1]]; + } else { + arr[i] = [vertices[i][0], vertices[i][1]]; + } + + } + return arr; + }, + points: function (time) { + return this.vertices('v', time); + }, + inTangents: function (time) { + return this.vertices('i', time); + }, + outTangents: function (time) { + return this.vertices('o', time); + }, + isClosed: function () { + return this.v.c; + }, + pointOnPath: function (perc, time) { + var shapePath = this.v; + if (time !== undefined) { + shapePath = this.getValueAtTime(time, 0); + } + if (!this._segmentsLength) { + this._segmentsLength = bez.getSegmentsLength(shapePath); + } + + var segmentsLength = this._segmentsLength; + var lengths = segmentsLength.lengths; + var lengthPos = segmentsLength.totalLength * perc; + var i = 0, len = lengths.length; + var j = 0, jLen; + var accumulatedLength = 0, pt; + while (i < len) { + if (accumulatedLength + lengths[i].addedLength > lengthPos) { + var initIndex = i; + var endIndex = (shapePath.c && i === len - 1) ? 0 : i + 1; + var segmentPerc = (lengthPos - accumulatedLength) / lengths[i].addedLength; + pt = bez.getPointInSegment(shapePath.v[initIndex], shapePath.v[endIndex], shapePath.o[initIndex], shapePath.i[endIndex], segmentPerc, lengths[i]); + break; + } else { + accumulatedLength += lengths[i].addedLength; + } + i += 1; + } + if (!pt) { + pt = shapePath.c ? [shapePath.v[0][0], shapePath.v[0][1]] : [shapePath.v[shapePath._length - 1][0], shapePath.v[shapePath._length - 1][1]]; + } + return pt; + }, + vectorOnPath: function (perc, time, vectorType) { + //perc doesn't use triple equality because it can be a Number object as well as a primitive. + perc = perc == 1 ? this.v.c ? 0 : 0.999 : perc; + var pt1 = this.pointOnPath(perc, time); + var pt2 = this.pointOnPath(perc + 0.001, time); + var xLength = pt2[0] - pt1[0]; + var yLength = pt2[1] - pt1[1]; + var magnitude = Math.sqrt(Math.pow(xLength, 2) + Math.pow(yLength, 2)); + if (magnitude === 0) { + return [0, 0]; + } + var unitVector = vectorType === 'tangent' ? [xLength / magnitude, yLength / magnitude] : [-yLength / magnitude, xLength / magnitude]; + return unitVector; + }, + tangentOnPath: function (perc, time) { + return this.vectorOnPath(perc, time, 'tangent'); + }, + normalOnPath: function (perc, time) { + return this.vectorOnPath(perc, time, 'normal'); + }, + setGroupProperty: expressionHelpers.setGroupProperty, + getValueAtTime: expressionHelpers.getStaticValueAtTime + }; + extendPrototype([ShapeExpressions], ShapePropertyConstructorFunction); + extendPrototype([ShapeExpressions], KeyframedShapePropertyConstructorFunction); + KeyframedShapePropertyConstructorFunction.prototype.getValueAtTime = getShapeValueAtTime; + KeyframedShapePropertyConstructorFunction.prototype.initiateExpression = ExpressionManager.initiateExpression; + + var propertyGetShapeProp = ShapePropertyFactory.getShapeProp; + ShapePropertyFactory.getShapeProp = function (elem, data, type, arr, trims) { + var prop = propertyGetShapeProp(elem, data, type, arr, trims); + prop.propertyIndex = data.ix; + prop.lock = false; + if (type === 3) { + expressionHelpers.searchExpressions(elem, data.pt, prop); + } else if (type === 4) { + expressionHelpers.searchExpressions(elem, data.ks, prop); + } + if (prop.k) { + elem.addDynamicProperty(prop); + } + return prop; + }; + }()); + (function addDecorator() { + + function searchExpressions() { + if (this.data.d.x) { + this.calculateExpression = ExpressionManager.initiateExpression.bind(this)(this.elem, this.data.d, this); + this.addEffect(this.getExpressionValue.bind(this)); + return true; + } + } + + TextProperty.prototype.getExpressionValue = function (currentValue, text) { + var newValue = this.calculateExpression(text); + if (currentValue.t !== newValue) { + var newData = {}; + this.copyData(newData, currentValue); + newData.t = newValue.toString(); + newData.__complete = false; + return newData; + } + return currentValue; + } + + TextProperty.prototype.searchProperty = function () { + + var isKeyframed = this.searchKeyframes(); + var hasExpressions = this.searchExpressions(); + this.kf = isKeyframed || hasExpressions; + return this.kf; + }; + + TextProperty.prototype.searchExpressions = searchExpressions; + + }()); + var ShapeExpressionInterface = (function () { + + function iterateElements(shapes, view, propertyGroup) { + var arr = []; + var i, len = shapes ? shapes.length : 0; + for (i = 0; i < len; i += 1) { + if (shapes[i].ty == 'gr') { + arr.push(groupInterfaceFactory(shapes[i], view[i], propertyGroup)); + } else if (shapes[i].ty == 'fl') { + arr.push(fillInterfaceFactory(shapes[i], view[i], propertyGroup)); + } else if (shapes[i].ty == 'st') { + arr.push(strokeInterfaceFactory(shapes[i], view[i], propertyGroup)); + } else if (shapes[i].ty == 'tm') { + arr.push(trimInterfaceFactory(shapes[i], view[i], propertyGroup)); + } else if (shapes[i].ty == 'tr') { + //arr.push(transformInterfaceFactory(shapes[i],view[i],propertyGroup)); + } else if (shapes[i].ty == 'el') { + arr.push(ellipseInterfaceFactory(shapes[i], view[i], propertyGroup)); + } else if (shapes[i].ty == 'sr') { + arr.push(starInterfaceFactory(shapes[i], view[i], propertyGroup)); + } else if (shapes[i].ty == 'sh') { + arr.push(pathInterfaceFactory(shapes[i], view[i], propertyGroup)); + } else if (shapes[i].ty == 'rc') { + arr.push(rectInterfaceFactory(shapes[i], view[i], propertyGroup)); + } else if (shapes[i].ty == 'rd') { + arr.push(roundedInterfaceFactory(shapes[i], view[i], propertyGroup)); + } else if (shapes[i].ty == 'rp') { + arr.push(repeaterInterfaceFactory(shapes[i], view[i], propertyGroup)); + } + } + return arr; + } + + function contentsInterfaceFactory(shape, view, propertyGroup) { + var interfaces; + var interfaceFunction = function _interfaceFunction(value) { + var i = 0, len = interfaces.length; + while (i < len) { + if (interfaces[i]._name === value || interfaces[i].mn === value || interfaces[i].propertyIndex === value || interfaces[i].ix === value || interfaces[i].ind === value) { + return interfaces[i]; + } + i += 1; + } + if (typeof value === 'number') { + return interfaces[value - 1]; + } + }; + interfaceFunction.propertyGroup = function (val) { + if (val === 1) { + return interfaceFunction; + } else { + return propertyGroup(val - 1); + } + }; + interfaces = iterateElements(shape.it, view.it, interfaceFunction.propertyGroup); + interfaceFunction.numProperties = interfaces.length; + interfaceFunction.propertyIndex = shape.cix; + interfaceFunction._name = shape.nm; + + return interfaceFunction; + } + + function groupInterfaceFactory(shape, view, propertyGroup) { + var interfaceFunction = function _interfaceFunction(value) { + switch (value) { + case 'ADBE Vectors Group': + case 'Contents': + case 2: + return interfaceFunction.content; + //Not necessary for now. Keeping them here in case a new case appears + //case 'ADBE Vector Transform Group': + //case 3: + default: + return interfaceFunction.transform; + } + }; + interfaceFunction.propertyGroup = function (val) { + if (val === 1) { + return interfaceFunction; + } else { + return propertyGroup(val - 1); + } + }; + var content = contentsInterfaceFactory(shape, view, interfaceFunction.propertyGroup); + var transformInterface = transformInterfaceFactory(shape.it[shape.it.length - 1], view.it[view.it.length - 1], interfaceFunction.propertyGroup); + interfaceFunction.content = content; + interfaceFunction.transform = transformInterface; + Object.defineProperty(interfaceFunction, '_name', { + get: function () { + return shape.nm; + } + }); + //interfaceFunction.content = interfaceFunction; + interfaceFunction.numProperties = shape.np; + interfaceFunction.propertyIndex = shape.ix; + interfaceFunction.nm = shape.nm; + interfaceFunction.mn = shape.mn; + return interfaceFunction; + } + + function fillInterfaceFactory(shape, view, propertyGroup) { + function interfaceFunction(val) { + if (val === 'Color' || val === 'color') { + return interfaceFunction.color; + } else if (val === 'Opacity' || val === 'opacity') { + return interfaceFunction.opacity; + } + } + Object.defineProperties(interfaceFunction, { + 'color': { + get: ExpressionPropertyInterface(view.c) + }, + 'opacity': { + get: ExpressionPropertyInterface(view.o) + }, + '_name': { value: shape.nm }, + 'mn': { value: shape.mn } + }); + + view.c.setGroupProperty(propertyGroup); + view.o.setGroupProperty(propertyGroup); + return interfaceFunction; + } + + function strokeInterfaceFactory(shape, view, propertyGroup) { + function _propertyGroup(val) { + if (val === 1) { + return ob; + } else { + return propertyGroup(val - 1); + } + } + function _dashPropertyGroup(val) { + if (val === 1) { + return dashOb; + } else { + return _propertyGroup(val - 1); + } + } + function addPropertyToDashOb(i) { + Object.defineProperty(dashOb, shape.d[i].nm, { + get: ExpressionPropertyInterface(view.d.dataProps[i].p) + }); + } + var i, len = shape.d ? shape.d.length : 0; + var dashOb = {}; + for (i = 0; i < len; i += 1) { + addPropertyToDashOb(i); + view.d.dataProps[i].p.setGroupProperty(_dashPropertyGroup); + } + + function interfaceFunction(val) { + if (val === 'Color' || val === 'color') { + return interfaceFunction.color; + } else if (val === 'Opacity' || val === 'opacity') { + return interfaceFunction.opacity; + } else if (val === 'Stroke Width' || val === 'stroke width') { + return interfaceFunction.strokeWidth; + } + } + Object.defineProperties(interfaceFunction, { + 'color': { + get: ExpressionPropertyInterface(view.c) + }, + 'opacity': { + get: ExpressionPropertyInterface(view.o) + }, + 'strokeWidth': { + get: ExpressionPropertyInterface(view.w) + }, + 'dash': { + get: function () { + return dashOb; + } + }, + '_name': { value: shape.nm }, + 'mn': { value: shape.mn } + }); + + view.c.setGroupProperty(_propertyGroup); + view.o.setGroupProperty(_propertyGroup); + view.w.setGroupProperty(_propertyGroup); + return interfaceFunction; + } + + function trimInterfaceFactory(shape, view, propertyGroup) { + function _propertyGroup(val) { + if (val == 1) { + return interfaceFunction; + } else { + return propertyGroup(--val); + } + } + interfaceFunction.propertyIndex = shape.ix; + + view.s.setGroupProperty(_propertyGroup); + view.e.setGroupProperty(_propertyGroup); + view.o.setGroupProperty(_propertyGroup); + + function interfaceFunction(val) { + if (val === shape.e.ix || val === 'End' || val === 'end') { + return interfaceFunction.end; + } + if (val === shape.s.ix) { + return interfaceFunction.start; + } + if (val === shape.o.ix) { + return interfaceFunction.offset; + } + } + interfaceFunction.propertyIndex = shape.ix; + interfaceFunction.propertyGroup = propertyGroup; + + Object.defineProperties(interfaceFunction, { + 'start': { + get: ExpressionPropertyInterface(view.s) + }, + 'end': { + get: ExpressionPropertyInterface(view.e) + }, + 'offset': { + get: ExpressionPropertyInterface(view.o) + }, + '_name': { value: shape.nm } + }); + interfaceFunction.mn = shape.mn; + return interfaceFunction; + } + + function transformInterfaceFactory(shape, view, propertyGroup) { + function _propertyGroup(val) { + if (val == 1) { + return interfaceFunction; + } else { + return propertyGroup(--val); + } + } + view.transform.mProps.o.setGroupProperty(_propertyGroup); + view.transform.mProps.p.setGroupProperty(_propertyGroup); + view.transform.mProps.a.setGroupProperty(_propertyGroup); + view.transform.mProps.s.setGroupProperty(_propertyGroup); + view.transform.mProps.r.setGroupProperty(_propertyGroup); + if (view.transform.mProps.sk) { + view.transform.mProps.sk.setGroupProperty(_propertyGroup); + view.transform.mProps.sa.setGroupProperty(_propertyGroup); + } + view.transform.op.setGroupProperty(_propertyGroup); + + function interfaceFunction(value) { + if (shape.a.ix === value || value === 'Anchor Point') { + return interfaceFunction.anchorPoint; + } + if (shape.o.ix === value || value === 'Opacity') { + return interfaceFunction.opacity; + } + if (shape.p.ix === value || value === 'Position') { + return interfaceFunction.position; + } + if (shape.r.ix === value || value === 'Rotation' || value === 'ADBE Vector Rotation') { + return interfaceFunction.rotation; + } + if (shape.s.ix === value || value === 'Scale') { + return interfaceFunction.scale; + } + if (shape.sk && shape.sk.ix === value || value === 'Skew') { + return interfaceFunction.skew; + } + if (shape.sa && shape.sa.ix === value || value === 'Skew Axis') { + return interfaceFunction.skewAxis; + } + + } + Object.defineProperties(interfaceFunction, { + 'opacity': { + get: ExpressionPropertyInterface(view.transform.mProps.o) + }, + 'position': { + get: ExpressionPropertyInterface(view.transform.mProps.p) + }, + 'anchorPoint': { + get: ExpressionPropertyInterface(view.transform.mProps.a) + }, + 'scale': { + get: ExpressionPropertyInterface(view.transform.mProps.s) + }, + 'rotation': { + get: ExpressionPropertyInterface(view.transform.mProps.r) + }, + 'skew': { + get: ExpressionPropertyInterface(view.transform.mProps.sk) + }, + 'skewAxis': { + get: ExpressionPropertyInterface(view.transform.mProps.sa) + }, + '_name': { value: shape.nm } + }); + interfaceFunction.ty = 'tr'; + interfaceFunction.mn = shape.mn; + interfaceFunction.propertyGroup = propertyGroup; + return interfaceFunction; + } + + function ellipseInterfaceFactory(shape, view, propertyGroup) { + function _propertyGroup(val) { + if (val == 1) { + return interfaceFunction; + } else { + return propertyGroup(--val); + } + } + interfaceFunction.propertyIndex = shape.ix; + var prop = view.sh.ty === 'tm' ? view.sh.prop : view.sh; + prop.s.setGroupProperty(_propertyGroup); + prop.p.setGroupProperty(_propertyGroup); + function interfaceFunction(value) { + if (shape.p.ix === value) { + return interfaceFunction.position; + } + if (shape.s.ix === value) { + return interfaceFunction.size; + } + } + + Object.defineProperties(interfaceFunction, { + 'size': { + get: ExpressionPropertyInterface(prop.s) + }, + 'position': { + get: ExpressionPropertyInterface(prop.p) + }, + '_name': { value: shape.nm } + }); + interfaceFunction.mn = shape.mn; + return interfaceFunction; + } + + function starInterfaceFactory(shape, view, propertyGroup) { + function _propertyGroup(val) { + if (val == 1) { + return interfaceFunction; + } else { + return propertyGroup(--val); + } + } + var prop = view.sh.ty === 'tm' ? view.sh.prop : view.sh; + interfaceFunction.propertyIndex = shape.ix; + prop.or.setGroupProperty(_propertyGroup); + prop.os.setGroupProperty(_propertyGroup); + prop.pt.setGroupProperty(_propertyGroup); + prop.p.setGroupProperty(_propertyGroup); + prop.r.setGroupProperty(_propertyGroup); + if (shape.ir) { + prop.ir.setGroupProperty(_propertyGroup); + prop.is.setGroupProperty(_propertyGroup); + } + + function interfaceFunction(value) { + if (shape.p.ix === value) { + return interfaceFunction.position; + } + if (shape.r.ix === value) { + return interfaceFunction.rotation; + } + if (shape.pt.ix === value) { + return interfaceFunction.points; + } + if (shape.or.ix === value || 'ADBE Vector Star Outer Radius' === value) { + return interfaceFunction.outerRadius; + } + if (shape.os.ix === value) { + return interfaceFunction.outerRoundness; + } + if (shape.ir && (shape.ir.ix === value || 'ADBE Vector Star Inner Radius' === value)) { + return interfaceFunction.innerRadius; + } + if (shape.is && shape.is.ix === value) { + return interfaceFunction.innerRoundness; + } + + } + + Object.defineProperties(interfaceFunction, { + 'position': { + get: ExpressionPropertyInterface(prop.p) + }, + 'rotation': { + get: ExpressionPropertyInterface(prop.r) + }, + 'points': { + get: ExpressionPropertyInterface(prop.pt) + }, + 'outerRadius': { + get: ExpressionPropertyInterface(prop.or) + }, + 'outerRoundness': { + get: ExpressionPropertyInterface(prop.os) + }, + 'innerRadius': { + get: ExpressionPropertyInterface(prop.ir) + }, + 'innerRoundness': { + get: ExpressionPropertyInterface(prop.is) + }, + '_name': { value: shape.nm } + }); + interfaceFunction.mn = shape.mn; + return interfaceFunction; + } + + function rectInterfaceFactory(shape, view, propertyGroup) { + function _propertyGroup(val) { + if (val == 1) { + return interfaceFunction; + } else { + return propertyGroup(--val); + } + } + var prop = view.sh.ty === 'tm' ? view.sh.prop : view.sh; + interfaceFunction.propertyIndex = shape.ix; + prop.p.setGroupProperty(_propertyGroup); + prop.s.setGroupProperty(_propertyGroup); + prop.r.setGroupProperty(_propertyGroup); + + function interfaceFunction(value) { + if (shape.p.ix === value) { + return interfaceFunction.position; + } + if (shape.r.ix === value) { + return interfaceFunction.roundness; + } + if (shape.s.ix === value || value === 'Size' || value === 'ADBE Vector Rect Size') { + return interfaceFunction.size; + } + + } + Object.defineProperties(interfaceFunction, { + 'position': { + get: ExpressionPropertyInterface(prop.p) + }, + 'roundness': { + get: ExpressionPropertyInterface(prop.r) + }, + 'size': { + get: ExpressionPropertyInterface(prop.s) + }, + '_name': { value: shape.nm } + }); + interfaceFunction.mn = shape.mn; + return interfaceFunction; + } + + function roundedInterfaceFactory(shape, view, propertyGroup) { + function _propertyGroup(val) { + if (val == 1) { + return interfaceFunction; + } else { + return propertyGroup(--val); + } + } + var prop = view; + interfaceFunction.propertyIndex = shape.ix; + prop.rd.setGroupProperty(_propertyGroup); + + function interfaceFunction(value) { + if (shape.r.ix === value || 'Round Corners 1' === value) { + return interfaceFunction.radius; + } + + } + Object.defineProperties(interfaceFunction, { + 'radius': { + get: ExpressionPropertyInterface(prop.rd) + }, + '_name': { value: shape.nm } + }); + interfaceFunction.mn = shape.mn; + return interfaceFunction; + } + + function repeaterInterfaceFactory(shape, view, propertyGroup) { + function _propertyGroup(val) { + if (val == 1) { + return interfaceFunction; + } else { + return propertyGroup(--val); + } + } + var prop = view; + interfaceFunction.propertyIndex = shape.ix; + prop.c.setGroupProperty(_propertyGroup); + prop.o.setGroupProperty(_propertyGroup); + + function interfaceFunction(value) { + if (shape.c.ix === value || 'Copies' === value) { + return interfaceFunction.copies; + } else if (shape.o.ix === value || 'Offset' === value) { + return interfaceFunction.offset; + } + + } + Object.defineProperties(interfaceFunction, { + 'copies': { + get: ExpressionPropertyInterface(prop.c) + }, + 'offset': { + get: ExpressionPropertyInterface(prop.o) + }, + '_name': { value: shape.nm } + }); + interfaceFunction.mn = shape.mn; + return interfaceFunction; + } + + function pathInterfaceFactory(shape, view, propertyGroup) { + var prop = view.sh; + function _propertyGroup(val) { + if (val == 1) { + return interfaceFunction; + } else { + return propertyGroup(--val); + } + } + prop.setGroupProperty(_propertyGroup); + + function interfaceFunction(val) { + if (val === 'Shape' || val === 'shape' || val === 'Path' || val === 'path' || val === 'ADBE Vector Shape' || val === 2) { + return interfaceFunction.path; + } + } + Object.defineProperties(interfaceFunction, { + 'path': { + get: function () { + if (prop.k) { + prop.getValue(); + } + return prop; + } + }, + 'shape': { + get: function () { + if (prop.k) { + prop.getValue(); + } + return prop; + } + }, + '_name': { value: shape.nm }, + 'ix': { value: shape.ix }, + 'propertyIndex': { value: shape.ix }, + 'mn': { value: shape.mn } + }); + return interfaceFunction; + } + + return function (shapes, view, propertyGroup) { + var interfaces; + function _interfaceFunction(value) { + if (typeof value === 'number') { + return interfaces[value - 1]; + } else { + var i = 0, len = interfaces.length; + while (i < len) { + if (interfaces[i]._name === value) { + return interfaces[i]; + } + i += 1; + } + } + } + _interfaceFunction.propertyGroup = propertyGroup; + interfaces = iterateElements(shapes, view, _interfaceFunction); + _interfaceFunction.numProperties = interfaces.length; + return _interfaceFunction; + }; + }()); + + var TextExpressionInterface = (function () { + return function (elem) { + var _prevValue, _sourceText; + function _thisLayerFunction() { + } + Object.defineProperty(_thisLayerFunction, "sourceText", { + get: function () { + elem.textProperty.getValue() + var stringValue = elem.textProperty.currentData.t; + if (stringValue !== _prevValue) { + elem.textProperty.currentData.t = _prevValue; + _sourceText = new String(stringValue); + //If stringValue is an empty string, eval returns undefined, so it has to be returned as a String primitive + _sourceText.value = stringValue ? stringValue : new String(stringValue); + } + return _sourceText; + } + }); + return _thisLayerFunction; + }; + }()); + var LayerExpressionInterface = (function () { + function toWorld(arr, time) { + var toWorldMat = new Matrix(); + toWorldMat.reset(); + var transformMat; + if (time) { + //Todo implement value at time on transform properties + //transformMat = this._elem.finalTransform.mProp.getValueAtTime(time); + transformMat = this._elem.finalTransform.mProp; + } else { + transformMat = this._elem.finalTransform.mProp; + } + transformMat.applyToMatrix(toWorldMat); + if (this._elem.hierarchy && this._elem.hierarchy.length) { + var i, len = this._elem.hierarchy.length; + for (i = 0; i < len; i += 1) { + this._elem.hierarchy[i].finalTransform.mProp.applyToMatrix(toWorldMat); + } + return toWorldMat.applyToPointArray(arr[0], arr[1], arr[2] || 0); + } + return toWorldMat.applyToPointArray(arr[0], arr[1], arr[2] || 0); + } + function fromWorld(arr, time) { + var toWorldMat = new Matrix(); + toWorldMat.reset(); + var transformMat; + if (time) { + //Todo implement value at time on transform properties + //transformMat = this._elem.finalTransform.mProp.getValueAtTime(time); + transformMat = this._elem.finalTransform.mProp; + } else { + transformMat = this._elem.finalTransform.mProp; + } + transformMat.applyToMatrix(toWorldMat); + if (this._elem.hierarchy && this._elem.hierarchy.length) { + var i, len = this._elem.hierarchy.length; + for (i = 0; i < len; i += 1) { + this._elem.hierarchy[i].finalTransform.mProp.applyToMatrix(toWorldMat); + } + return toWorldMat.inversePoint(arr); + } + return toWorldMat.inversePoint(arr); + } + function fromComp(arr) { + var toWorldMat = new Matrix(); + toWorldMat.reset(); + this._elem.finalTransform.mProp.applyToMatrix(toWorldMat); + if (this._elem.hierarchy && this._elem.hierarchy.length) { + var i, len = this._elem.hierarchy.length; + for (i = 0; i < len; i += 1) { + this._elem.hierarchy[i].finalTransform.mProp.applyToMatrix(toWorldMat); + } + return toWorldMat.inversePoint(arr); + } + return toWorldMat.inversePoint(arr); + } + + function sampleImage() { + return [1, 1, 1, 1]; + } + + + return function (elem) { + + var transformInterface; + + function _registerMaskInterface(maskManager) { + _thisLayerFunction.mask = new MaskManagerInterface(maskManager, elem); + } + function _registerEffectsInterface(effects) { + _thisLayerFunction.effect = effects; + } + + function _thisLayerFunction(name) { + switch (name) { + case "ADBE Root Vectors Group": + case "Contents": + case 2: + return _thisLayerFunction.shapeInterface; + case 1: + case 6: + case "Transform": + case "transform": + case "ADBE Transform Group": + return transformInterface; + case 4: + case "ADBE Effect Parade": + case "effects": + case "Effects": + return _thisLayerFunction.effect; + } + } + _thisLayerFunction.toWorld = toWorld; + _thisLayerFunction.fromWorld = fromWorld; + _thisLayerFunction.toComp = toWorld; + _thisLayerFunction.fromComp = fromComp; + _thisLayerFunction.sampleImage = sampleImage; + _thisLayerFunction.sourceRectAtTime = elem.sourceRectAtTime.bind(elem); + _thisLayerFunction._elem = elem; + transformInterface = TransformExpressionInterface(elem.finalTransform.mProp); + var anchorPointDescriptor = getDescriptor(transformInterface, 'anchorPoint'); + Object.defineProperties(_thisLayerFunction, { + hasParent: { + get: function () { + return elem.hierarchy.length; + } + }, + parent: { + get: function () { + return elem.hierarchy[0].layerInterface; + } + }, + rotation: getDescriptor(transformInterface, 'rotation'), + scale: getDescriptor(transformInterface, 'scale'), + position: getDescriptor(transformInterface, 'position'), + opacity: getDescriptor(transformInterface, 'opacity'), + anchorPoint: anchorPointDescriptor, + anchor_point: anchorPointDescriptor, + transform: { + get: function () { + return transformInterface; + } + }, + active: { + get: function () { + return elem.isInRange; + } + } + }); + + _thisLayerFunction.startTime = elem.data.st; + _thisLayerFunction.index = elem.data.ind; + _thisLayerFunction.source = elem.data.refId; + _thisLayerFunction.height = elem.data.ty === 0 ? elem.data.h : 100; + _thisLayerFunction.width = elem.data.ty === 0 ? elem.data.w : 100; + _thisLayerFunction.inPoint = elem.data.ip / elem.comp.globalData.frameRate; + _thisLayerFunction.outPoint = elem.data.op / elem.comp.globalData.frameRate; + _thisLayerFunction._name = elem.data.nm; + + _thisLayerFunction.registerMaskInterface = _registerMaskInterface; + _thisLayerFunction.registerEffectsInterface = _registerEffectsInterface; + return _thisLayerFunction; + }; + }()); + + var CompExpressionInterface = (function () { + return function (comp) { + function _thisLayerFunction(name) { + var i = 0, len = comp.layers.length; + while (i < len) { + if (comp.layers[i].nm === name || comp.layers[i].ind === name) { + return comp.elements[i].layerInterface; + } + i += 1; + } + return null; + //return {active:false}; + } + Object.defineProperty(_thisLayerFunction, "_name", { value: comp.data.nm }); + _thisLayerFunction.layer = _thisLayerFunction; + _thisLayerFunction.pixelAspect = 1; + _thisLayerFunction.height = comp.data.h || comp.globalData.compSize.h; + _thisLayerFunction.width = comp.data.w || comp.globalData.compSize.w; + _thisLayerFunction.pixelAspect = 1; + _thisLayerFunction.frameDuration = 1 / comp.globalData.frameRate; + _thisLayerFunction.displayStartTime = 0; + _thisLayerFunction.numLayers = comp.layers.length; + return _thisLayerFunction; + }; + }()); + var TransformExpressionInterface = (function () { + return function (transform) { + function _thisFunction(name) { + switch (name) { + case "scale": + case "Scale": + case "ADBE Scale": + case 6: + return _thisFunction.scale; + case "rotation": + case "Rotation": + case "ADBE Rotation": + case "ADBE Rotate Z": + case 10: + return _thisFunction.rotation; + case "ADBE Rotate X": + return _thisFunction.xRotation; + case "ADBE Rotate Y": + return _thisFunction.yRotation; + case "position": + case "Position": + case "ADBE Position": + case 2: + return _thisFunction.position; + case 'ADBE Position_0': + return _thisFunction.xPosition; + case 'ADBE Position_1': + return _thisFunction.yPosition; + case 'ADBE Position_2': + return _thisFunction.zPosition; + case "anchorPoint": + case "AnchorPoint": + case "Anchor Point": + case "ADBE AnchorPoint": + case 1: + return _thisFunction.anchorPoint; + case "opacity": + case "Opacity": + case 11: + return _thisFunction.opacity; + } + } + + Object.defineProperty(_thisFunction, "rotation", { + get: ExpressionPropertyInterface(transform.r || transform.rz) + }); + + Object.defineProperty(_thisFunction, "zRotation", { + get: ExpressionPropertyInterface(transform.rz || transform.r) + }); + + Object.defineProperty(_thisFunction, "xRotation", { + get: ExpressionPropertyInterface(transform.rx) + }); + + Object.defineProperty(_thisFunction, "yRotation", { + get: ExpressionPropertyInterface(transform.ry) + }); + Object.defineProperty(_thisFunction, "scale", { + get: ExpressionPropertyInterface(transform.s) + }); + + if (transform.p) { + var _transformFactory = ExpressionPropertyInterface(transform.p); + } + Object.defineProperty(_thisFunction, "position", { + get: function () { + if (transform.p) { + return _transformFactory(); + } else { + return [transform.px.v, transform.py.v, transform.pz ? transform.pz.v : 0]; + } + } + }); + + Object.defineProperty(_thisFunction, "xPosition", { + get: ExpressionPropertyInterface(transform.px) + }); + + Object.defineProperty(_thisFunction, "yPosition", { + get: ExpressionPropertyInterface(transform.py) + }); + + Object.defineProperty(_thisFunction, "zPosition", { + get: ExpressionPropertyInterface(transform.pz) + }); + + Object.defineProperty(_thisFunction, "anchorPoint", { + get: ExpressionPropertyInterface(transform.a) + }); + + Object.defineProperty(_thisFunction, "opacity", { + get: ExpressionPropertyInterface(transform.o) + }); + + Object.defineProperty(_thisFunction, "skew", { + get: ExpressionPropertyInterface(transform.sk) + }); + + Object.defineProperty(_thisFunction, "skewAxis", { + get: ExpressionPropertyInterface(transform.sa) + }); + + Object.defineProperty(_thisFunction, "orientation", { + get: ExpressionPropertyInterface(transform.or) + }); + + return _thisFunction; + }; + }()); + var ProjectInterface = (function () { + + function registerComposition(comp) { + this.compositions.push(comp); + } + + return function () { + function _thisProjectFunction(name) { + var i = 0, len = this.compositions.length; + while (i < len) { + if (this.compositions[i].data && this.compositions[i].data.nm === name) { + if (this.compositions[i].prepareFrame && this.compositions[i].data.xt) { + this.compositions[i].prepareFrame(this.currentFrame); + } + return this.compositions[i].compInterface; + } + i += 1; + } + } + + _thisProjectFunction.compositions = []; + _thisProjectFunction.currentFrame = 0; + + _thisProjectFunction.registerComposition = registerComposition; + + + + return _thisProjectFunction; + }; + }()); + var EffectsExpressionInterface = (function () { + var ob = { + createEffectsInterface: createEffectsInterface + }; + + function createEffectsInterface(elem, propertyGroup) { + if (elem.effectsManager) { + + var effectElements = []; + var effectsData = elem.data.ef; + var i, len = elem.effectsManager.effectElements.length; + for (i = 0; i < len; i += 1) { + effectElements.push(createGroupInterface(effectsData[i], elem.effectsManager.effectElements[i], propertyGroup, elem)); + } + + return function (name) { + var effects = elem.data.ef || [], i = 0, len = effects.length; + while (i < len) { + if (name === effects[i].nm || name === effects[i].mn || name === effects[i].ix) { + return effectElements[i]; + } + i += 1; + } + }; + } + } + + function createGroupInterface(data, elements, propertyGroup, elem) { + var effectElements = []; + var i, len = data.ef.length; + for (i = 0; i < len; i += 1) { + if (data.ef[i].ty === 5) { + effectElements.push(createGroupInterface(data.ef[i], elements.effectElements[i], elements.effectElements[i].propertyGroup, elem)); + } else { + effectElements.push(createValueInterface(elements.effectElements[i], data.ef[i].ty, elem, _propertyGroup)); + } + } + + function _propertyGroup(val) { + if (val === 1) { + return groupInterface; + } else { + return propertyGroup(val - 1); + } + } + + var groupInterface = function (name) { + var effects = data.ef, i = 0, len = effects.length; + while (i < len) { + if (name === effects[i].nm || name === effects[i].mn || name === effects[i].ix) { + if (effects[i].ty === 5) { + return effectElements[i]; + } else { + return effectElements[i](); + } + } + i += 1; + } + return effectElements[0](); + }; + + groupInterface.propertyGroup = _propertyGroup; + + if (data.mn === 'ADBE Color Control') { + Object.defineProperty(groupInterface, 'color', { + get: function () { + return effectElements[0](); + } + }); + } + Object.defineProperty(groupInterface, 'numProperties', { + get: function () { + return data.np; + } + }); + groupInterface.active = groupInterface.enabled = data.en !== 0; + return groupInterface; + } + + function createValueInterface(element, type, elem, propertyGroup) { + var expressionProperty = ExpressionPropertyInterface(element.p); + function interfaceFunction() { + if (type === 10) { + return elem.comp.compInterface(element.p.v); + } + return expressionProperty(); + } + + if (element.p.setGroupProperty) { + element.p.setGroupProperty(propertyGroup); + } + + return interfaceFunction; + } + + return ob; + + }()); + var MaskManagerInterface = (function () { + + function MaskInterface(mask, data) { + this._mask = mask; + this._data = data; + } + Object.defineProperty(MaskInterface.prototype, 'maskPath', { + get: function () { + if (this._mask.prop.k) { + this._mask.prop.getValue(); + } + return this._mask.prop; + } + }); + Object.defineProperty(MaskInterface.prototype, 'maskOpacity', { + get: function () { + if (this._mask.op.k) { + this._mask.op.getValue(); + } + return this._mask.op.v * 100; + } + }); + + var MaskManager = function (maskManager, elem) { + var _maskManager = maskManager; + var _elem = elem; + var _masksInterfaces = createSizedArray(maskManager.viewData.length); + var i, len = maskManager.viewData.length; + for (i = 0; i < len; i += 1) { + _masksInterfaces[i] = new MaskInterface(maskManager.viewData[i], maskManager.masksProperties[i]); + } + + var maskFunction = function (name) { + i = 0; + while (i < len) { + if (maskManager.masksProperties[i].nm === name) { + return _masksInterfaces[i]; + } + i += 1; + } + }; + return maskFunction; + }; + return MaskManager; + }()); + + var ExpressionPropertyInterface = (function () { + + var defaultUnidimensionalValue = { pv: 0, v: 0, mult: 1 } + var defaultMultidimensionalValue = { pv: [0, 0, 0], v: [0, 0, 0], mult: 1 } + + function completeProperty(expressionValue, property, type) { + Object.defineProperty(expressionValue, 'velocity', { + get: function () { + return property.getVelocityAtTime(property.comp.currentFrame); + } + }); + expressionValue.numKeys = property.keyframes ? property.keyframes.length : 0; + expressionValue.key = function (pos) { + if (!expressionValue.numKeys) { + return 0; + } else { + var value = ''; + if ('s' in property.keyframes[pos - 1]) { + value = property.keyframes[pos - 1].s; + } else if ('e' in property.keyframes[pos - 2]) { + value = property.keyframes[pos - 2].e; + } else { + value = property.keyframes[pos - 2].s; + } + var valueProp = type === 'unidimensional' ? new Number(value) : Object.assign({}, value); + valueProp.time = property.keyframes[pos - 1].t / property.elem.comp.globalData.frameRate; + return valueProp; + } + }; + expressionValue.valueAtTime = property.getValueAtTime; + expressionValue.speedAtTime = property.getSpeedAtTime; + expressionValue.velocityAtTime = property.getVelocityAtTime; + expressionValue.propertyGroup = property.propertyGroup; + } + + function UnidimensionalPropertyInterface(property) { + if (!property || !('pv' in property)) { + property = defaultUnidimensionalValue; + } + var mult = 1 / property.mult; + var val = property.pv * mult; + var expressionValue = new Number(val); + expressionValue.value = val; + completeProperty(expressionValue, property, 'unidimensional'); + + return function () { + if (property.k) { + property.getValue(); + } + val = property.v * mult; + if (expressionValue.value !== val) { + expressionValue = new Number(val); + expressionValue.value = val; + completeProperty(expressionValue, property, 'unidimensional'); + } + return expressionValue; + } + } + + function MultidimensionalPropertyInterface(property) { + if (!property || !('pv' in property)) { + property = defaultMultidimensionalValue; + } + var mult = 1 / property.mult; + var len = property.pv.length; + var expressionValue = createTypedArray('float32', len); + var arrValue = createTypedArray('float32', len); + expressionValue.value = arrValue; + completeProperty(expressionValue, property, 'multidimensional'); + + return function () { + if (property.k) { + property.getValue(); + } + for (var i = 0; i < len; i += 1) { + expressionValue[i] = arrValue[i] = property.v[i] * mult; + } + return expressionValue; + } + } + + //TODO: try to avoid using this getter + function defaultGetter() { + return defaultUnidimensionalValue; + } + + return function (property) { + if (!property) { + return defaultGetter; + } else if (property.propType === 'unidimensional') { + return UnidimensionalPropertyInterface(property); + } else { + return MultidimensionalPropertyInterface(property); + } + } + }()); + + (function () { + + var TextExpressionSelectorProp = (function () { + + function getValueProxy(index, total) { + this.textIndex = index + 1; + this.textTotal = total; + this.v = this.getValue() * this.mult; + return this.v; + } + + return function TextExpressionSelectorProp(elem, data) { + this.pv = 1; + this.comp = elem.comp; + this.elem = elem; + this.mult = 0.01; + this.propType = 'textSelector'; + this.textTotal = data.totalChars; + this.selectorValue = 100; + this.lastValue = [1, 1, 1]; + this.k = true; + this.x = true; + this.getValue = ExpressionManager.initiateExpression.bind(this)(elem, data, this); + this.getMult = getValueProxy; + this.getVelocityAtTime = expressionHelpers.getVelocityAtTime; + if (this.kf) { + this.getValueAtTime = expressionHelpers.getValueAtTime.bind(this); + } else { + this.getValueAtTime = expressionHelpers.getStaticValueAtTime.bind(this); + } + this.setGroupProperty = expressionHelpers.setGroupProperty; + }; + }()); + + var propertyGetTextProp = TextSelectorProp.getTextSelectorProp; + TextSelectorProp.getTextSelectorProp = function (elem, data, arr) { + if (data.t === 1) { + return new TextExpressionSelectorProp(elem, data, arr); + } else { + return propertyGetTextProp(elem, data, arr); + } + }; + }()); + function SliderEffect(data, elem, container) { + this.p = PropertyFactory.getProp(elem, data.v, 0, 0, container); + } + function AngleEffect(data, elem, container) { + this.p = PropertyFactory.getProp(elem, data.v, 0, 0, container); + } + function ColorEffect(data, elem, container) { + this.p = PropertyFactory.getProp(elem, data.v, 1, 0, container); + } + function PointEffect(data, elem, container) { + this.p = PropertyFactory.getProp(elem, data.v, 1, 0, container); + } + function LayerIndexEffect(data, elem, container) { + this.p = PropertyFactory.getProp(elem, data.v, 0, 0, container); + } + function MaskIndexEffect(data, elem, container) { + this.p = PropertyFactory.getProp(elem, data.v, 0, 0, container); + } + function CheckboxEffect(data, elem, container) { + this.p = PropertyFactory.getProp(elem, data.v, 0, 0, container); + } + function NoValueEffect() { + this.p = {}; + } + function EffectsManager() { } + function EffectsManager(data, element) { + var effects = data.ef || []; + this.effectElements = []; + var i, len = effects.length; + var effectItem; + for (i = 0; i < len; i++) { + effectItem = new GroupEffect(effects[i], element); + this.effectElements.push(effectItem); + } + } + + function GroupEffect(data, element) { + this.init(data, element); + } + + extendPrototype([DynamicPropertyContainer], GroupEffect); + + GroupEffect.prototype.getValue = GroupEffect.prototype.iterateDynamicProperties; + + GroupEffect.prototype.init = function (data, element) { + this.data = data; + this.effectElements = []; + this.initDynamicPropertyContainer(element); + var i, len = this.data.ef.length; + var eff, effects = this.data.ef; + for (i = 0; i < len; i += 1) { + eff = null; + switch (effects[i].ty) { + case 0: + eff = new SliderEffect(effects[i], element, this); + break; + case 1: + eff = new AngleEffect(effects[i], element, this); + break; + case 2: + eff = new ColorEffect(effects[i], element, this); + break; + case 3: + eff = new PointEffect(effects[i], element, this); + break; + case 4: + case 7: + eff = new CheckboxEffect(effects[i], element, this); + break; + case 10: + eff = new LayerIndexEffect(effects[i], element, this); + break; + case 11: + eff = new MaskIndexEffect(effects[i], element, this); + break; + case 5: + eff = new EffectsManager(effects[i], element, this); + break; + //case 6: + default: + eff = new NoValueEffect(effects[i], element, this); + break; + } + if (eff) { + this.effectElements.push(eff); + } + } + }; + + var lottie = {}; + + var _isFrozen = false; + + function setLocationHref(href) { + locationHref = href; + } + + function searchAnimations() { + if (standalone === true) { + animationManager.searchAnimations(animationData, standalone, renderer); + } else { + animationManager.searchAnimations(); + } + } + + function setSubframeRendering(flag) { + subframeEnabled = flag; + } + + function loadAnimation(params) { + if (standalone === true) { + params.animationData = JSON.parse(animationData); + } + return animationManager.loadAnimation(params); + } + + function setQuality(value) { + if (typeof value === 'string') { + switch (value) { + case 'high': + defaultCurveSegments = 200; + break; + case 'medium': + defaultCurveSegments = 50; + break; + case 'low': + defaultCurveSegments = 10; + break; + } + } else if (!isNaN(value) && value > 1) { + defaultCurveSegments = value; + } + if (defaultCurveSegments >= 50) { + roundValues(false); + } else { + roundValues(true); + } + } + + function inBrowser() { + return typeof navigator !== 'undefined'; + } + + function installPlugin(type, plugin) { + if (type === 'expressions') { + expressionsPlugin = plugin; + } + } + + function getFactory(name) { + switch (name) { + case "propertyFactory": + return PropertyFactory; + case "shapePropertyFactory": + return ShapePropertyFactory; + case "matrix": + return Matrix; + } + } + + lottie.play = animationManager.play; + lottie.pause = animationManager.pause; + lottie.setLocationHref = setLocationHref; + lottie.togglePause = animationManager.togglePause; + lottie.setSpeed = animationManager.setSpeed; + lottie.setDirection = animationManager.setDirection; + lottie.stop = animationManager.stop; + lottie.searchAnimations = searchAnimations; + lottie.registerAnimation = animationManager.registerAnimation; + lottie.loadAnimation = loadAnimation; + lottie.setSubframeRendering = setSubframeRendering; + lottie.resize = animationManager.resize; + //lottie.start = start; + lottie.goToAndStop = animationManager.goToAndStop; + lottie.destroy = animationManager.destroy; + lottie.setQuality = setQuality; + lottie.inBrowser = inBrowser; + lottie.installPlugin = installPlugin; + lottie.freeze = animationManager.freeze; + lottie.unfreeze = animationManager.unfreeze; + lottie.getRegisteredAnimations = animationManager.getRegisteredAnimations; + lottie.__getFactory = getFactory; + lottie.version = '5.6.8'; + + function checkReady() { + if (document.readyState === "complete") { + clearInterval(readyStateCheckInterval); + searchAnimations(); + } + } + + function getQueryVariable(variable) { + var vars = queryString.split('&'); + for (var i = 0; i < vars.length; i++) { + var pair = vars[i].split('='); + if (decodeURIComponent(pair[0]) == variable) { + return decodeURIComponent(pair[1]); + } + } + } + var standalone = '__[STANDALONE]__'; + var animationData = '__[ANIMATIONDATA]__'; + var renderer = ''; + if (standalone) { + var scripts = document.getElementsByTagName('script'); + var index = scripts.length - 1; + var myScript = scripts[index] || { + src: '' + }; + var queryString = myScript.src.replace(/^[^\?]+\??/, ''); + renderer = getQueryVariable('renderer'); + } + var readyStateCheckInterval = setInterval(checkReady, 100); + + return lottie; +})); diff --git a/src/AddIns/Uno.UI.Lottie.Wasm/WasmScripts/uno-lottie.d.ts b/src/AddIns/Uno.UI.Lottie.Wasm/WasmScripts/uno-lottie.d.ts new file mode 100644 index 000000000000..e52cdd5382be --- /dev/null +++ b/src/AddIns/Uno.UI.Lottie.Wasm/WasmScripts/uno-lottie.d.ts @@ -0,0 +1,36 @@ +declare const require: any; +declare const config: any; +declare namespace Uno.UI { + import AnimationData = Lottie.AnimationData; + interface LottieAnimationProperties { + elementId: number; + jsonPath?: string; + autoplay: boolean; + stretch: string; + rate: number; + } + interface RunningLottieAnimation { + animation: Lottie.AnimationItem; + properties: LottieAnimationProperties; + } + class Lottie { + private static _player; + private static _runningAnimations; + private static _numberOfFrames; + static setAnimationProperties(newProperties: LottieAnimationProperties, animationData?: AnimationData): string; + static stop(elementId: number): string; + static play(elementId: number, fromProgress: number, toProgress: number, looped: boolean): string; + static kill(elementId: number): string; + static pause(elementId: number): string; + static resume(elementId: number): string; + static setProgress(elementId: number, progress: number): string; + static getAnimationState(elementId: number): string; + private static needNewPlayerAnimation; + private static updateProperties; + private static createAnimation; + private static getStateString; + private static raiseState; + private static getPlayerConfig; + private static withPlayer; + } +} diff --git a/src/AddIns/Uno.UI.Lottie.Wasm/WasmScripts/uno-lottie.js b/src/AddIns/Uno.UI.Lottie.Wasm/WasmScripts/uno-lottie.js new file mode 100644 index 000000000000..c4be858846fa --- /dev/null +++ b/src/AddIns/Uno.UI.Lottie.Wasm/WasmScripts/uno-lottie.js @@ -0,0 +1,189 @@ +var Uno; +(function (Uno) { + var UI; + (function (UI) { + class Lottie { + static setAnimationProperties(newProperties, animationData) { + const elementId = newProperties.elementId; + Lottie.withPlayer(p => { + let currentAnimation = Lottie._runningAnimations[elementId]; + if (!currentAnimation || Lottie.needNewPlayerAnimation(currentAnimation.properties, newProperties)) { + // Here we need a new player animation + // (some property changes required a new animation) + currentAnimation = Lottie.createAnimation(newProperties, animationData); + } + Lottie.updateProperties(currentAnimation, newProperties); + }); + return "ok"; + } + static stop(elementId) { + Lottie.withPlayer(p => { + const a = Lottie._runningAnimations[elementId].animation; + a.stop(); + Lottie.raiseState(a); + }); + return "ok"; + } + static play(elementId, fromProgress, toProgress, looped) { + Lottie.withPlayer(p => { + const a = Lottie._runningAnimations[elementId].animation; + a.loop = looped; + const fromFrame = fromProgress * Lottie._numberOfFrames; + const toFrame = toProgress * Lottie._numberOfFrames; + a.playSegments([fromFrame, toFrame], false); + Lottie.raiseState(a); + }); + return "ok"; + } + static kill(elementId) { + Lottie.withPlayer(p => { + Lottie._runningAnimations[elementId].animation.destroy(); + delete Lottie._runningAnimations[elementId]; + }); + return "ok"; + } + static pause(elementId) { + Lottie.withPlayer(p => { + const a = Lottie._runningAnimations[elementId].animation; + a.pause(); + Lottie.raiseState(a); + }); + return "ok"; + } + static resume(elementId) { + Lottie.withPlayer(p => { + const a = Lottie._runningAnimations[elementId].animation; + a.play(); + Lottie.raiseState(a); + }); + return "ok"; + } + static setProgress(elementId, progress) { + Lottie.withPlayer(p => { + const animation = Lottie._runningAnimations[elementId].animation; + const frames = animation.getDuration(true); + const frame = frames * progress; + animation.goToAndStop(frame, true); + Lottie.raiseState(animation); + }); + return "ok"; + } + static getAnimationState(elementId) { + const animation = Lottie._runningAnimations[elementId].animation; + const state = Lottie.getStateString(animation); + return state; + } + static needNewPlayerAnimation(current, newProperties) { + if (current.jsonPath !== newProperties.jsonPath) { + return true; + } + if (newProperties.stretch !== current.stretch) { + return true; + } + if (newProperties.autoplay !== current.autoplay) { + return true; + } + return false; + } + static updateProperties(runningAnimation, newProperties) { + const animation = runningAnimation.animation; + const runningProperties = runningAnimation.properties; + if (runningProperties == null || newProperties.rate != runningProperties.rate) { + animation.setSpeed(newProperties.rate); + } + runningAnimation.properties = newProperties; + } + static createAnimation(properties, animationData) { + const existingAnimation = Lottie._runningAnimations[properties.elementId]; + if (existingAnimation) { + // destroy any previous animation + existingAnimation.animation.destroy(); + existingAnimation.animation = null; + } + const config = Lottie.getPlayerConfig(properties, animationData); + const animation = Lottie._player.loadAnimation(config); + const runningAnimation = { + animation: animation, + properties: properties + }; + Lottie._runningAnimations[properties.elementId] = runningAnimation; + animation.addEventListener("complete", (e) => { + Lottie.raiseState(animation); + }); + animation.addEventListener("loopComplete", (e) => { + Lottie.raiseState(animation); + }); + animation.addEventListener("segmentStart", (e) => { + Lottie.raiseState(animation); + }); + animation.addEventListener("data_ready", (e) => { + Lottie._numberOfFrames = animation.totalFrames; + Lottie.raiseState(animation); + }); + Lottie.raiseState(animation); + return runningAnimation; + } + static getStateString(animation) { + const duration = animation.getDuration(false); + const state = `${animation.animationData.w}|${animation.animationData.h}|` + + `${animation.isLoaded}|${animation.isPaused}|${duration}`; + return state; + } + static raiseState(animation) { + const element = animation.wrapper; + const state = Lottie.getStateString(animation); + element.dispatchEvent(new CustomEvent("lottie_state", { detail: state })); + } + static getPlayerConfig(properties, animationData) { + let scaleMode = "none"; + switch (properties.stretch) { + case "Uniform": + scaleMode = "xMidYMid meet"; + break; + case "UniformToFill": + scaleMode = "xMidYMid slice"; + break; + case "Fill": + scaleMode = "none"; + break; + } + const containerElement = Uno.UI.WindowManager.current.getView(properties.elementId); + // https://github.com/airbnb/lottie-web/wiki/loadAnimation-options + const playerConfig = { + loop: true, + autoplay: properties.autoplay, + name: `Lottie-${properties.elementId}`, + renderer: "svg", + container: containerElement, + rendererSettings: { + // https://github.com/airbnb/lottie-web/wiki/Renderer-Settings + preserveAspectRatio: scaleMode + } + }; + // Set source, with priority to animationData, if specified. + if (animationData != null) { + playerConfig.animationData = animationData; + } + else if (properties.jsonPath != null && properties.jsonPath !== "") { + playerConfig.path = properties.jsonPath; + } + return playerConfig; + } + static withPlayer(action) { + if (Lottie._player) { + action(Lottie._player); + } + else { + require([`${config.uno_app_base}/lottie`], (p) => { + if (!Lottie._player) { + Lottie._player = p; + } + action(p); + }); + } + } + } + Lottie._runningAnimations = {}; + UI.Lottie = Lottie; + })(UI = Uno.UI || (Uno.UI = {})); +})(Uno || (Uno = {})); diff --git a/src/AddIns/Uno.UI.Lottie.Wasm/ts/Uno.UI.Lottie.ts b/src/AddIns/Uno.UI.Lottie.Wasm/ts/Uno.UI.Lottie.ts new file mode 100644 index 000000000000..3c0f13bccf34 --- /dev/null +++ b/src/AddIns/Uno.UI.Lottie.Wasm/ts/Uno.UI.Lottie.ts @@ -0,0 +1,255 @@ +declare const require: any; +declare const config: any; + +namespace Uno.UI { + import AnimationData = Lottie.AnimationData; + + export interface LottieAnimationProperties { + elementId: number; + jsonPath?: string; + autoplay: boolean; + stretch: string; + rate: number; + } + + export interface RunningLottieAnimation { + animation: Lottie.AnimationItem; + properties: LottieAnimationProperties; + } + + export class Lottie { + private static _player: LottiePlayer; + private static _runningAnimations: { [id: number]: RunningLottieAnimation } = {}; + private static _numberOfFrames: number; + + public static setAnimationProperties(newProperties: LottieAnimationProperties, animationData?: AnimationData): string { + const elementId = newProperties.elementId; + + Lottie.withPlayer(p => { + let currentAnimation = Lottie._runningAnimations[elementId]; + + if (!currentAnimation || Lottie.needNewPlayerAnimation(currentAnimation.properties, newProperties)) { + // Here we need a new player animation + // (some property changes required a new animation) + currentAnimation = Lottie.createAnimation(newProperties, animationData); + } + + Lottie.updateProperties(currentAnimation, newProperties); + }); + + return "ok"; + } + + public static stop(elementId: number): string { + Lottie.withPlayer(p => { + const a = Lottie._runningAnimations[elementId].animation; + a.stop(); + Lottie.raiseState(a); + }); + + return "ok"; + } + + public static play(elementId: number, fromProgress: number, toProgress: number, looped: boolean): string { + Lottie.withPlayer(p => { + const a = Lottie._runningAnimations[elementId].animation; + a.loop = looped; + + const fromFrame = fromProgress * Lottie._numberOfFrames; + const toFrame = toProgress * Lottie._numberOfFrames; + + a.playSegments([fromFrame, toFrame], false); + Lottie.raiseState(a); + }); + + return "ok"; + } + + public static kill(elementId: number): string { + Lottie.withPlayer(p => { + Lottie._runningAnimations[elementId].animation.destroy(); + delete Lottie._runningAnimations[elementId]; + }); + + return "ok"; + } + + public static pause(elementId: number): string { + Lottie.withPlayer(p => { + const a = Lottie._runningAnimations[elementId].animation; + a.pause(); + Lottie.raiseState(a); + }); + + return "ok"; + } + + public static resume(elementId: number): string { + Lottie.withPlayer(p => { + const a = Lottie._runningAnimations[elementId].animation; + a.play(); + Lottie.raiseState(a); + }); + + return "ok"; + } + + public static setProgress(elementId: number, progress: number): string { + Lottie.withPlayer(p => { + const animation = Lottie._runningAnimations[elementId].animation; + const frames = animation.getDuration(true); + const frame = frames * progress; + animation.goToAndStop(frame, true); + Lottie.raiseState(animation); + + }); + + return "ok"; + } + + public static getAnimationState(elementId: number): string { + const animation = Lottie._runningAnimations[elementId].animation; + + const state = Lottie.getStateString(animation); + + return state; + } + + private static needNewPlayerAnimation(current: LottieAnimationProperties, newProperties: LottieAnimationProperties): boolean { + + if (current.jsonPath !== newProperties.jsonPath) { + return true; + } + if (newProperties.stretch !== current.stretch) { + return true; + } + if (newProperties.autoplay !== current.autoplay) { + return true; + } + + return false; + } + + private static updateProperties( + runningAnimation: RunningLottieAnimation, + newProperties: LottieAnimationProperties) { + + const animation = runningAnimation.animation; + const runningProperties = runningAnimation.properties; + + if (runningProperties == null || newProperties.rate != runningProperties.rate) { + animation.setSpeed(newProperties.rate); + } + + runningAnimation.properties = newProperties; + } + + private static createAnimation(properties: LottieAnimationProperties, animationData?: AnimationData): RunningLottieAnimation { + const existingAnimation = Lottie._runningAnimations[properties.elementId]; + if (existingAnimation) { + // destroy any previous animation + existingAnimation.animation.destroy(); + existingAnimation.animation = null; + } + + const config = Lottie.getPlayerConfig(properties, animationData); + const animation = Lottie._player.loadAnimation(config); + + const runningAnimation = { + animation: animation, + properties: properties + }; + + Lottie._runningAnimations[properties.elementId] = runningAnimation; + + (animation as any).addEventListener("complete", (e: any) => { + Lottie.raiseState(animation); + }); + + (animation as any).addEventListener("loopComplete", (e: any) => { + Lottie.raiseState(animation); + }); + + (animation as any).addEventListener("segmentStart", (e: any) => { + Lottie.raiseState(animation); + }); + + (animation as any).addEventListener("data_ready", (e: any) => { + Lottie._numberOfFrames = animation.totalFrames; + Lottie.raiseState(animation); + }); + + Lottie.raiseState(animation); + + return runningAnimation; + } + + private static getStateString(animation: Lottie.AnimationItem): string { + const duration = animation.getDuration(false); + + const state = `${animation.animationData.w}|${animation.animationData.h}|` + + `${animation.isLoaded}|${animation.isPaused}|${duration}`; + return state; + } + + private static raiseState(animation: Lottie.AnimationItem) { + const element = animation.wrapper; + const state = Lottie.getStateString(animation); + + element.dispatchEvent(new CustomEvent("lottie_state", { detail: state })); + } + + private static getPlayerConfig(properties: LottieAnimationProperties, animationData?: AnimationData): Lottie.AnimationConfig { + let scaleMode = "none"; + switch (properties.stretch) { + case "Uniform": + scaleMode = "xMidYMid meet"; + break; + case "UniformToFill": + scaleMode = "xMidYMid slice"; + break; + case "Fill": + scaleMode = "none"; + break; + } + + const containerElement = (Uno.UI as any).WindowManager.current.getView(properties.elementId); + + // https://github.com/airbnb/lottie-web/wiki/loadAnimation-options + const playerConfig: Lottie.AnimationConfig = { + loop: true, + autoplay: properties.autoplay, + name: `Lottie-${properties.elementId}`, + renderer: "svg", // https://github.com/airbnb/lottie-web/wiki/Features + container: containerElement, + rendererSettings: { + // https://github.com/airbnb/lottie-web/wiki/Renderer-Settings + preserveAspectRatio: scaleMode + } + }; + + // Set source, with priority to animationData, if specified. + if (animationData != null) { + playerConfig.animationData = animationData; + } + else if (properties.jsonPath != null && properties.jsonPath !== "") { + playerConfig.path = properties.jsonPath; + } + + return playerConfig; + } + + private static withPlayer(action: (player: LottiePlayer) => void): void { + if (Lottie._player) { + action(Lottie._player); + } else { + require([`${config.uno_app_base}/lottie`], (p: LottiePlayer) => { + if (!Lottie._player) { + Lottie._player = p; + } + action(p); + }); + } + } + } +} diff --git a/src/AddIns/Uno.UI.Lottie.Wasm/ts/lottie-web.d.ts b/src/AddIns/Uno.UI.Lottie.Wasm/ts/lottie-web.d.ts new file mode 100644 index 000000000000..fdb38cb04359 --- /dev/null +++ b/src/AddIns/Uno.UI.Lottie.Wasm/ts/lottie-web.d.ts @@ -0,0 +1,131 @@ +declare namespace Lottie { + export interface AnimationItem { + play(): void; + + stop(): void; + + pause(): void; + + // one param speed (1 is normal speed) + setSpeed(speed: number): void; + + // one param direction (1 is normal direction) + setDirection(direction: number): void; + + // If false, it will respect the original AE fps. If true, it will update as much as possible. (true by default) + setSubframe(flag: boolean): void; + + // first param is a numeric value. second param is a boolean that defines time or frames for first param + goToAndPlay(value: number, isFrame: boolean): void; + + // first param is a numeric value. second param is a boolean that defines time or frames for first param + goToAndStop(value: number, isFrame: boolean): void; + + // first param is a single array or multiple arrays of two values each(fromFrame,toFrame), second param is a boolean for forcing the new segment right away + playSegments(segments: number[] | number[][], forceFlag: boolean): void; + + // inFrames: If true, returns duration in frames, if false, in seconds. + getDuration(inFrames: boolean): number; + + // To destroy and release resources. + destroy(): void; + + autoplay: boolean; + currentFrame: number; + isLoaded: boolean; + isPaused: boolean; + loop: boolean; + name: string; + playCount: number; + playDirection: number; + playSpeed: number; + totalFrames: number; + animationData: AnimationData; + wrapper: HTMLElement; + } + + export interface AnimationData { + // In Point of the Time Ruler. Sets the initial Frame of the animation. + ip: number; + + // Out Point of the Time Ruler. Sets the final Frame of the animation + op: number; + + // Frame Rate + fr: number; + + // Composition Width + w: number; + + // Composition Height + h: number; + + // Composition has 3-D layers + ddd: boolean; + + // Name + nm: string; + + // Version + v: string; + } + + export interface AnimationConfig { + // an Object with the exported animation data. + animationData?: any; + + // the relative path to the animation object. (animationData and path are mutually exclusive) + path?: string; + + // true / false / number + loop?: boolean | number; + + // true / false it will start playing as soon as it is ready + autoplay?: boolean; + + // animation name for future reference + name?: string; + + // 'svg' / 'canvas' / 'html' to set the renderer + renderer?: string; + + // the dom element on which to render the animation + container?: any; + + scaleMode?: string; + + rendererSettings?: any; + } +} + +declare class LottiePlayer { + // optional parameter name to target a specific animation + play(name?: string): void; + + // optional parameter name to target a specific animation + stop(name?: string): void; + + // first param speed (1 is normal speed) with 1 optional parameter name to target a specific animation + setSpeed(speed: number, name?: string): void; + + // first param direction (1 is normal direction.) with 1 optional parameter name to target a specific animation + setDirection(direction: number, name?: string): void; + + // default 'high', set 'high','medium','low', or a number > 1 to improve player performance. In some animations as low as 2 won't show any difference. + setQuality(quality: string | number): void; + + // param usually pass as location.href. Its useful when you experience mask issue in safari where your url does not have # symbol. + setLocationHref(href: string): void; + + // returns an animation instance to control individually. + loadAnimation(params: Lottie.AnimationConfig): Lottie.AnimationItem; + + // you can register an element directly with registerAnimation. It must have the "data-animation-path" attribute pointing at the data.json url + registerAnimation(element: any, animationData?: any): void; + + // looks for elements with class "lottie" + searchAnimations(animationData?: any, standalone?: boolean, renderer?: string): void; + + // To destroy and release resources. The DOM element will be emptied. + destroy(name?: string): void; +} diff --git a/src/AddIns/Uno.UI.Lottie.Wasm/tsconfig.json b/src/AddIns/Uno.UI.Lottie.Wasm/tsconfig.json new file mode 100644 index 000000000000..8830b1625cbb --- /dev/null +++ b/src/AddIns/Uno.UI.Lottie.Wasm/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "module": "none", + "declaration": true, + "diagnostics": true, + "noImplicitAny": true, + "outFile": "WasmScripts/uno-lottie.js", + "locale": "en-US", + "target": "es2015" + }, + "include": [ + "ts/**/*" + ] +} + diff --git a/src/AddIns/Uno.UI.Lottie/Uno.UI.Lottie.csproj b/src/AddIns/Uno.UI.Lottie/Uno.UI.Lottie.csproj index c7c9f4a196d3..2896ce435080 100644 --- a/src/AddIns/Uno.UI.Lottie/Uno.UI.Lottie.csproj +++ b/src/AddIns/Uno.UI.Lottie/Uno.UI.Lottie.csproj @@ -21,6 +21,17 @@ + + + + + + + + build + true + + @@ -65,8 +76,8 @@ - - + + diff --git a/src/AddIns/Uno.UI.Lottie/buildTransitive/Uno.UI.Lottie.targets b/src/AddIns/Uno.UI.Lottie/buildTransitive/Uno.UI.Lottie.targets new file mode 100644 index 000000000000..af5164019126 --- /dev/null +++ b/src/AddIns/Uno.UI.Lottie/buildTransitive/Uno.UI.Lottie.targets @@ -0,0 +1,16 @@ + + + + + + + <_ItemsFromUnoToRemove Include="@(RuntimeCopyLocalItems)" Condition="'%(RuntimeCopyLocalItems.NuGetPackageId)'=='Uno.UI.Lottie' or '%(RuntimeCopyLocalItems.NuGetPackageId)'=='Uno.WinUI.Lottie'" /> + + + + + + + diff --git a/src/AddIns/Uno.UI.MSAL.Skia/LinkerDefinition.xml b/src/AddIns/Uno.UI.MSAL.Skia/LinkerDefinition.xml new file mode 100644 index 000000000000..93aa7ef103a4 --- /dev/null +++ b/src/AddIns/Uno.UI.MSAL.Skia/LinkerDefinition.xml @@ -0,0 +1,3 @@ + + + diff --git a/src/AddIns/Uno.UI.MSAL.Skia/Uno.UI.MSAL.Skia.csproj b/src/AddIns/Uno.UI.MSAL.Skia/Uno.UI.MSAL.Skia.csproj new file mode 100644 index 000000000000..c1072905c3d1 --- /dev/null +++ b/src/AddIns/Uno.UI.MSAL.Skia/Uno.UI.MSAL.Skia.csproj @@ -0,0 +1,58 @@ + + + + netstandard2.0 + $(NoWarn);NU1701 + true + true + Uno.UI.MSAL + Uno.UI.MSAL + false + + + + Skia + ..\Uno.UI.MSAL\ + + + + + + + + + + + + + + + + false + all + + + + $(AssemblyName).xml + + + + + + + <_OverrideTargetFramework>$(TargetFramework) + <_TargetNugetFolder>$(USERPROFILE)\.nuget\packages\Uno.UI.MSAL\$(UnoNugetOverrideVersion)\uno-runtime\$(UnoRuntimeIdentifier.ToLowerInvariant()) + + + <_OutputFiles Include="$(TargetDir)**" /> + + + + + + + + + + + diff --git a/src/AddIns/Uno.UI.MSAL.Skia/WasmScripts/uno-ui-msal.d.ts b/src/AddIns/Uno.UI.MSAL.Skia/WasmScripts/uno-ui-msal.d.ts new file mode 100644 index 000000000000..35fd4816f6a8 --- /dev/null +++ b/src/AddIns/Uno.UI.MSAL.Skia/WasmScripts/uno-ui-msal.d.ts @@ -0,0 +1,6 @@ +declare namespace MSAL { + class WebUI { + static authenticate(urlNavigate: string, urlRedirect: string, title: string, popUpWidth: number, popUpHeight: number): Promise; + private static startMonitoringRedirect; + } +} diff --git a/src/AddIns/Uno.UI.MSAL.Skia/WasmScripts/uno-ui-msal.js b/src/AddIns/Uno.UI.MSAL.Skia/WasmScripts/uno-ui-msal.js new file mode 100644 index 000000000000..543fb60cbc0a --- /dev/null +++ b/src/AddIns/Uno.UI.MSAL.Skia/WasmScripts/uno-ui-msal.js @@ -0,0 +1,100 @@ +var MSAL; +(function (MSAL) { + class WebUI { + static authenticate(urlNavigate, urlRedirect, title, popUpWidth, popUpHeight) { + let win = null; + let timerSubscription = null; + return new Promise((ok, err) => { + let finished = false; + const close = () => { + if (win) { + win.close(); + win = null; + } + if (timerSubscription) { + window.clearInterval(timerSubscription); + timerSubscription = null; + } + if (!finished) { + err("Incompleted"); + } + }; + const completeSuccessfully = (url) => { + if (!finished) { + ok(url); + finished = true; + close(); + } + }; + const completeWithError = (error) => { + if (!finished) { + err(error); + finished = true; + close(); + } + }; + try { + /** + * adding winLeft and winTop to account for dual monitor + * using screenLeft and screenTop for IE8 and earlier + */ + const winLeft = window.screenLeft ? window.screenLeft : window.screenX; + const winTop = window.screenTop ? window.screenTop : window.screenY; + /** + * window.innerWidth displays browser window"s height and width excluding toolbars + * using document.documentElement.clientWidth for IE8 and earlier + */ + const width = window.innerWidth || + document.documentElement.clientWidth || + document.body.clientWidth; + const height = window.innerHeight || + document.documentElement.clientHeight || + document.body.clientHeight; + const left = ((width / 2) - (popUpWidth / 2)) + winLeft; + const top = ((height / 2) - (popUpHeight / 2)) + winTop; + // open the window + win = window.open(urlNavigate, title, "width=" + popUpWidth + ", height=" + popUpHeight + ", top=" + top + ", left=" + left); + if (!win) { + completeWithError("Cant open window"); + return; + } + if (win.focus) { + win.focus(); + } + win.addEventListener("beforeunload", close); + const onFinalUrlReached = (success, finalUrlOrMessage) => { + if (success) { + completeSuccessfully(finalUrlOrMessage); + } + else { + completeWithError(finalUrlOrMessage); + } + }; + timerSubscription = WebUI.startMonitoringRedirect(win, urlRedirect, onFinalUrlReached); + } + catch (e) { + completeWithError(`${e}`); + } + }); + } + static startMonitoringRedirect(win, urlRedirect, callback) { + const subscription = window.setInterval(() => { + try { + if (win.closed) { + callback(false, "Popup closed"); + return; + } + const url = win.document.URL; + if (url.indexOf(urlRedirect) !== -1) { + callback(true, url); + } + } + catch (e) { + // normal! DOMException / crossed origin until reached correct redirect page + } + }, 100); + return subscription; + } + } + MSAL.WebUI = WebUI; +})(MSAL || (MSAL = {})); diff --git a/src/AddIns/Uno.UI.MSAL.Skia/ts/MSAL.WebUI.ts b/src/AddIns/Uno.UI.MSAL.Skia/ts/MSAL.WebUI.ts new file mode 100644 index 000000000000..8881917a2aed --- /dev/null +++ b/src/AddIns/Uno.UI.MSAL.Skia/ts/MSAL.WebUI.ts @@ -0,0 +1,120 @@ +namespace MSAL { + export class WebUI { + + public static authenticate( + urlNavigate: string, + urlRedirect: string, + title: string, + popUpWidth: number, + popUpHeight: number): Promise { + + let win: Window = null; + let timerSubscription: number = null; + + return new Promise((ok, err) => { + + let finished = false; + const close = () => { + if (win) { + win.close(); + win = null; + } + + if (timerSubscription) { + window.clearInterval(timerSubscription); + timerSubscription = null; + } + if (!finished) { + err("Incompleted"); + } + }; + + const completeSuccessfully = (url: string) => { + if (!finished) { + ok(url); + finished = true; + close(); + } + }; + const completeWithError = (error: string) => { + if (!finished) { + err(error); + finished = true; + close(); + } + }; + + try { + /** + * adding winLeft and winTop to account for dual monitor + * using screenLeft and screenTop for IE8 and earlier + */ + const winLeft = window.screenLeft ? window.screenLeft : window.screenX; + const winTop = window.screenTop ? window.screenTop : window.screenY; + /** + * window.innerWidth displays browser window"s height and width excluding toolbars + * using document.documentElement.clientWidth for IE8 and earlier + */ + const width = window.innerWidth || + document.documentElement.clientWidth || + document.body.clientWidth; + const height = window.innerHeight || + document.documentElement.clientHeight || + document.body.clientHeight; + const left = ((width / 2) - (popUpWidth / 2)) + winLeft; + const top = ((height / 2) - (popUpHeight / 2)) + winTop; + + // open the window + win = window.open(urlNavigate, + title, + "width=" + popUpWidth + ", height=" + popUpHeight + ", top=" + top + ", left=" + left); + if (!win) { + completeWithError("Cant open window"); + return; + } + if (win.focus) { + win.focus(); + } + win.addEventListener("beforeunload", close); + + const onFinalUrlReached = (success: boolean, finalUrlOrMessage: string) => { + if (success) { + completeSuccessfully(finalUrlOrMessage); + } else { + completeWithError(finalUrlOrMessage); + } + } + timerSubscription = WebUI.startMonitoringRedirect(win, urlRedirect, onFinalUrlReached); + } catch (e) { + completeWithError(`${e}`); + } + }); + } + + private static startMonitoringRedirect( + win: Window, + urlRedirect: string, + callback: (success: boolean, finalUrlOrMessage: string) => void): number { + + const subscription = window.setInterval(() => { + try { + if (win.closed) { + callback(false, "Popup closed"); + return; + } + const url = win.document.URL; + if (url.indexOf(urlRedirect) !== -1) { + callback(true, url); + } + } catch (e) { + // normal! DOMException / crossed origin until reached correct redirect page + } + }, + 100); + + return subscription; + } + + } + +} diff --git a/src/AddIns/Uno.UI.MSAL.Skia/tsconfig.json b/src/AddIns/Uno.UI.MSAL.Skia/tsconfig.json new file mode 100644 index 000000000000..83e61994cc28 --- /dev/null +++ b/src/AddIns/Uno.UI.MSAL.Skia/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "module": "none", + "declaration": true, + "diagnostics": true, + "noImplicitAny": true, + "outFile": "WasmScripts/uno-ui-msal.js", + "locale": "en-US", + "target": "es6" + }, + "include": [ + "ts/**/*" + ] +} + diff --git a/src/AddIns/Uno.UI.MSAL.Wasm/LinkerDefinition.xml b/src/AddIns/Uno.UI.MSAL.Wasm/LinkerDefinition.xml new file mode 100644 index 000000000000..93aa7ef103a4 --- /dev/null +++ b/src/AddIns/Uno.UI.MSAL.Wasm/LinkerDefinition.xml @@ -0,0 +1,3 @@ + + + diff --git a/src/AddIns/Uno.UI.MSAL.Wasm/Uno.UI.MSAL.Wasm.csproj b/src/AddIns/Uno.UI.MSAL.Wasm/Uno.UI.MSAL.Wasm.csproj new file mode 100644 index 000000000000..9a71401630dc --- /dev/null +++ b/src/AddIns/Uno.UI.MSAL.Wasm/Uno.UI.MSAL.Wasm.csproj @@ -0,0 +1,71 @@ + + + + netstandard2.0 + $(NoWarn);NU1701 + true + true + Uno.UI.MSAL + Uno.UI.MSAL + false + + + + WebAssembly + ..\Uno.UI.MSAL\ + + + + $(UnoTargetFrameworkOverride) + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + false + all + + + + $(AssemblyName).xml + + + + + + + <_OverrideTargetFramework>$(TargetFramework) + <_TargetNugetFolder>$(USERPROFILE)\.nuget\packages\Uno.UI.MSAL\$(UnoNugetOverrideVersion)\uno-runtime\$(UnoRuntimeIdentifier.ToLowerInvariant()) + + + <_OutputFiles Include="$(TargetDir)**" /> + + + + + + + + + + diff --git a/src/AddIns/Uno.UI.MSAL.Wasm/WasmScripts/uno-ui-msal.d.ts b/src/AddIns/Uno.UI.MSAL.Wasm/WasmScripts/uno-ui-msal.d.ts new file mode 100644 index 000000000000..35fd4816f6a8 --- /dev/null +++ b/src/AddIns/Uno.UI.MSAL.Wasm/WasmScripts/uno-ui-msal.d.ts @@ -0,0 +1,6 @@ +declare namespace MSAL { + class WebUI { + static authenticate(urlNavigate: string, urlRedirect: string, title: string, popUpWidth: number, popUpHeight: number): Promise; + private static startMonitoringRedirect; + } +} diff --git a/src/AddIns/Uno.UI.MSAL.Wasm/WasmScripts/uno-ui-msal.js b/src/AddIns/Uno.UI.MSAL.Wasm/WasmScripts/uno-ui-msal.js new file mode 100644 index 000000000000..543fb60cbc0a --- /dev/null +++ b/src/AddIns/Uno.UI.MSAL.Wasm/WasmScripts/uno-ui-msal.js @@ -0,0 +1,100 @@ +var MSAL; +(function (MSAL) { + class WebUI { + static authenticate(urlNavigate, urlRedirect, title, popUpWidth, popUpHeight) { + let win = null; + let timerSubscription = null; + return new Promise((ok, err) => { + let finished = false; + const close = () => { + if (win) { + win.close(); + win = null; + } + if (timerSubscription) { + window.clearInterval(timerSubscription); + timerSubscription = null; + } + if (!finished) { + err("Incompleted"); + } + }; + const completeSuccessfully = (url) => { + if (!finished) { + ok(url); + finished = true; + close(); + } + }; + const completeWithError = (error) => { + if (!finished) { + err(error); + finished = true; + close(); + } + }; + try { + /** + * adding winLeft and winTop to account for dual monitor + * using screenLeft and screenTop for IE8 and earlier + */ + const winLeft = window.screenLeft ? window.screenLeft : window.screenX; + const winTop = window.screenTop ? window.screenTop : window.screenY; + /** + * window.innerWidth displays browser window"s height and width excluding toolbars + * using document.documentElement.clientWidth for IE8 and earlier + */ + const width = window.innerWidth || + document.documentElement.clientWidth || + document.body.clientWidth; + const height = window.innerHeight || + document.documentElement.clientHeight || + document.body.clientHeight; + const left = ((width / 2) - (popUpWidth / 2)) + winLeft; + const top = ((height / 2) - (popUpHeight / 2)) + winTop; + // open the window + win = window.open(urlNavigate, title, "width=" + popUpWidth + ", height=" + popUpHeight + ", top=" + top + ", left=" + left); + if (!win) { + completeWithError("Cant open window"); + return; + } + if (win.focus) { + win.focus(); + } + win.addEventListener("beforeunload", close); + const onFinalUrlReached = (success, finalUrlOrMessage) => { + if (success) { + completeSuccessfully(finalUrlOrMessage); + } + else { + completeWithError(finalUrlOrMessage); + } + }; + timerSubscription = WebUI.startMonitoringRedirect(win, urlRedirect, onFinalUrlReached); + } + catch (e) { + completeWithError(`${e}`); + } + }); + } + static startMonitoringRedirect(win, urlRedirect, callback) { + const subscription = window.setInterval(() => { + try { + if (win.closed) { + callback(false, "Popup closed"); + return; + } + const url = win.document.URL; + if (url.indexOf(urlRedirect) !== -1) { + callback(true, url); + } + } + catch (e) { + // normal! DOMException / crossed origin until reached correct redirect page + } + }, 100); + return subscription; + } + } + MSAL.WebUI = WebUI; +})(MSAL || (MSAL = {})); diff --git a/src/AddIns/Uno.UI.MSAL.Wasm/ts/MSAL.WebUI.ts b/src/AddIns/Uno.UI.MSAL.Wasm/ts/MSAL.WebUI.ts new file mode 100644 index 000000000000..8881917a2aed --- /dev/null +++ b/src/AddIns/Uno.UI.MSAL.Wasm/ts/MSAL.WebUI.ts @@ -0,0 +1,120 @@ +namespace MSAL { + export class WebUI { + + public static authenticate( + urlNavigate: string, + urlRedirect: string, + title: string, + popUpWidth: number, + popUpHeight: number): Promise { + + let win: Window = null; + let timerSubscription: number = null; + + return new Promise((ok, err) => { + + let finished = false; + const close = () => { + if (win) { + win.close(); + win = null; + } + + if (timerSubscription) { + window.clearInterval(timerSubscription); + timerSubscription = null; + } + if (!finished) { + err("Incompleted"); + } + }; + + const completeSuccessfully = (url: string) => { + if (!finished) { + ok(url); + finished = true; + close(); + } + }; + const completeWithError = (error: string) => { + if (!finished) { + err(error); + finished = true; + close(); + } + }; + + try { + /** + * adding winLeft and winTop to account for dual monitor + * using screenLeft and screenTop for IE8 and earlier + */ + const winLeft = window.screenLeft ? window.screenLeft : window.screenX; + const winTop = window.screenTop ? window.screenTop : window.screenY; + /** + * window.innerWidth displays browser window"s height and width excluding toolbars + * using document.documentElement.clientWidth for IE8 and earlier + */ + const width = window.innerWidth || + document.documentElement.clientWidth || + document.body.clientWidth; + const height = window.innerHeight || + document.documentElement.clientHeight || + document.body.clientHeight; + const left = ((width / 2) - (popUpWidth / 2)) + winLeft; + const top = ((height / 2) - (popUpHeight / 2)) + winTop; + + // open the window + win = window.open(urlNavigate, + title, + "width=" + popUpWidth + ", height=" + popUpHeight + ", top=" + top + ", left=" + left); + if (!win) { + completeWithError("Cant open window"); + return; + } + if (win.focus) { + win.focus(); + } + win.addEventListener("beforeunload", close); + + const onFinalUrlReached = (success: boolean, finalUrlOrMessage: string) => { + if (success) { + completeSuccessfully(finalUrlOrMessage); + } else { + completeWithError(finalUrlOrMessage); + } + } + timerSubscription = WebUI.startMonitoringRedirect(win, urlRedirect, onFinalUrlReached); + } catch (e) { + completeWithError(`${e}`); + } + }); + } + + private static startMonitoringRedirect( + win: Window, + urlRedirect: string, + callback: (success: boolean, finalUrlOrMessage: string) => void): number { + + const subscription = window.setInterval(() => { + try { + if (win.closed) { + callback(false, "Popup closed"); + return; + } + const url = win.document.URL; + if (url.indexOf(urlRedirect) !== -1) { + callback(true, url); + } + } catch (e) { + // normal! DOMException / crossed origin until reached correct redirect page + } + }, + 100); + + return subscription; + } + + } + +} diff --git a/src/AddIns/Uno.UI.MSAL.Wasm/tsconfig.json b/src/AddIns/Uno.UI.MSAL.Wasm/tsconfig.json new file mode 100644 index 000000000000..83e61994cc28 --- /dev/null +++ b/src/AddIns/Uno.UI.MSAL.Wasm/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "module": "none", + "declaration": true, + "diagnostics": true, + "noImplicitAny": true, + "outFile": "WasmScripts/uno-ui-msal.js", + "locale": "en-US", + "target": "es6" + }, + "include": [ + "ts/**/*" + ] +} + diff --git a/src/AddIns/Uno.UI.MSAL/Uno.UI.MSAL.csproj b/src/AddIns/Uno.UI.MSAL/Uno.UI.MSAL.csproj index 7ef4ce8b26a6..0b317887db3a 100644 --- a/src/AddIns/Uno.UI.MSAL/Uno.UI.MSAL.csproj +++ b/src/AddIns/Uno.UI.MSAL/Uno.UI.MSAL.csproj @@ -3,11 +3,15 @@ xamarinmac20;MonoAndroid10.0;xamarinios10;net461;netstandard2.0;uap10.0.17763 xamarinmac20;MonoAndroid90;MonoAndroid10.0;xamarinios10;net461;netstandard2.0;uap10.0.17763 - $(NoWarn);NU1701 + $(NoWarn);NU1701;NU5100 true true + + $(UnoTargetFrameworkOverride) + + true nventive @@ -19,14 +23,17 @@ Copyright (C) 2015-2020 nventive inc. - all rights reserved Uno.WinUI.MSAL + + Reference + - + - - $(UnoTargetFrameworkOverride) - + + + @@ -34,35 +41,31 @@ + + + true + buildTransitive + + + - all - runtime; build; native; contentfiles; analyzers; buildtransitive + all + runtime; build; native; contentfiles; analyzers; buildtransitive - + - + - - - false - all - - - - $(AssemblyName).xml - - - @@ -76,8 +79,60 @@ - - + + + + + + + + + + true + uno-runtime/webassembly + + + true + uno-runtime/webassembly + + + true + uno-runtime/skia + + + true + uno-runtime/skia + + + + + + + + + + + + + + + + false + true + TargetFramework + + + false + true + TargetFramework + + + diff --git a/src/AddIns/Uno.UI.MSAL/buildTransitive/Uno.UI.MSAL.targets b/src/AddIns/Uno.UI.MSAL/buildTransitive/Uno.UI.MSAL.targets new file mode 100644 index 000000000000..83f9cf1bc258 --- /dev/null +++ b/src/AddIns/Uno.UI.MSAL/buildTransitive/Uno.UI.MSAL.targets @@ -0,0 +1,16 @@ + + + + + + + <_ItemsFromUnoToRemove Include="@(RuntimeCopyLocalItems)" Condition="'%(RuntimeCopyLocalItems.NuGetPackageId)'=='Uno.UI.MSAL' or '%(RuntimeCopyLocalItems.NuGetPackageId)'=='Uno.WinUI.MSAL'" /> + + + + + + + diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 528132689215..5ba4ed7c6c2a 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -26,12 +26,14 @@ 255.255.255.255 - $(AssemblyName) ($(TargetFramework)) en-US - true + true - + + false + + false true true diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets index c9fe5cfc8f2d..cb9b4f2d5b41 100644 --- a/src/Directory.Build.targets +++ b/src/Directory.Build.targets @@ -1,40 +1,51 @@ - + + + + + $(AssemblyName) ($(TargetFramework) $(UnoRuntimeIdentifier)) + - - + + - + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/PlatformItemGroups.props b/src/PlatformItemGroups.props index 84f7ef158681..b475575cb436 100644 --- a/src/PlatformItemGroups.props +++ b/src/PlatformItemGroups.props @@ -37,19 +37,37 @@ - - - + + + - - - + + - + + + + + + + + + + + + + - diff --git a/src/SamplesApp/SamplesApp.Shared/App.xaml.cs b/src/SamplesApp/SamplesApp.Shared/App.xaml.cs index f6ce040c6e35..b360efab5474 100644 --- a/src/SamplesApp/SamplesApp.Shared/App.xaml.cs +++ b/src/SamplesApp/SamplesApp.Shared/App.xaml.cs @@ -62,6 +62,7 @@ public App() /// public void AssertIssue1790() { +#if !__SKIA__ // SKIA TODO void AssertIsUsable(Windows.Storage.ApplicationDataContainer container) { const string issue1790 = nameof(issue1790); @@ -74,6 +75,7 @@ void AssertIsUsable(Windows.Storage.ApplicationDataContainer container) AssertIsUsable(Windows.Storage.ApplicationData.Current.LocalSettings); AssertIsUsable(Windows.Storage.ApplicationData.Current.RoamingSettings); +#endif } /// diff --git a/src/SamplesApp/SamplesApp.Skia.Gtk/Program.cs b/src/SamplesApp/SamplesApp.Skia.Gtk/Program.cs new file mode 100644 index 000000000000..b79021d8295e --- /dev/null +++ b/src/SamplesApp/SamplesApp.Skia.Gtk/Program.cs @@ -0,0 +1,27 @@ +using System; +using GLib; +using SkiaSharp; +using Gtk; +using Uno.Foundation.Extensibility; +using System.Threading; +using Uno.UI.Runtime.Skia; + +namespace SkiaSharpExample +{ + class MainClass + { + [STAThread] + public static void Main(string[] args) + { + ExceptionManager.UnhandledException += delegate (UnhandledExceptionArgs expArgs) + { + Console.WriteLine("GLIB UNHANDLED EXCEPTION" + expArgs.ExceptionObject.ToString()); + expArgs.ExitApplication = true; + }; + + var host = new GtkHost(() => new SamplesApp.App(), args); + + host.Run(); + } + } +} diff --git a/src/SamplesApp/SamplesApp.Skia.Gtk/Properties/launchSettings.json b/src/SamplesApp/SamplesApp.Skia.Gtk/Properties/launchSettings.json new file mode 100644 index 000000000000..17ff079c3fcb --- /dev/null +++ b/src/SamplesApp/SamplesApp.Skia.Gtk/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "SamplesApp.Skia.Gtk": { + "commandName": "Project", + "nativeDebugging": false + } + } +} \ No newline at end of file diff --git a/src/SamplesApp/SamplesApp.Skia.Gtk/SamplesApp.Skia.Gtk.csproj b/src/SamplesApp/SamplesApp.Skia.Gtk/SamplesApp.Skia.Gtk.csproj new file mode 100644 index 000000000000..383aab20f01c --- /dev/null +++ b/src/SamplesApp/SamplesApp.Skia.Gtk/SamplesApp.Skia.Gtk.csproj @@ -0,0 +1,31 @@ + + + + WinExe + netcoreapp3.1 + + + + true + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/SamplesApp/SamplesApp.Skia.WPF/App.config b/src/SamplesApp/SamplesApp.Skia.WPF/App.config new file mode 100644 index 000000000000..016d28fcc6ff --- /dev/null +++ b/src/SamplesApp/SamplesApp.Skia.WPF/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/SamplesApp/SamplesApp.Skia.WPF/App.xaml b/src/SamplesApp/SamplesApp.Skia.WPF/App.xaml new file mode 100644 index 000000000000..e737c9249f17 --- /dev/null +++ b/src/SamplesApp/SamplesApp.Skia.WPF/App.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/src/SamplesApp/SamplesApp.Skia.WPF/App.xaml.cs b/src/SamplesApp/SamplesApp.Skia.WPF/App.xaml.cs new file mode 100644 index 000000000000..c2df56f9fee4 --- /dev/null +++ b/src/SamplesApp/SamplesApp.Skia.WPF/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace SamplesApp.WPF +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} diff --git a/src/SamplesApp/SamplesApp.Skia.WPF/MainWindow.xaml b/src/SamplesApp/SamplesApp.Skia.WPF/MainWindow.xaml new file mode 100644 index 000000000000..02a9eaa0220b --- /dev/null +++ b/src/SamplesApp/SamplesApp.Skia.WPF/MainWindow.xaml @@ -0,0 +1,10 @@ + + + diff --git a/src/SamplesApp/SamplesApp.Skia.WPF/MainWindow.xaml.cs b/src/SamplesApp/SamplesApp.Skia.WPF/MainWindow.xaml.cs new file mode 100644 index 000000000000..da54d864d965 --- /dev/null +++ b/src/SamplesApp/SamplesApp.Skia.WPF/MainWindow.xaml.cs @@ -0,0 +1,35 @@ +using SkiaSharp.Views.WPF; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using Uno.UI.Skia.Platform; + +namespace SamplesApp.WPF +{ + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : Window + { + public MainWindow() + { + InitializeComponent(); + + Windows.UI.Core.CoreDispatcher.DispatchOverride + = d => Dispatcher.BeginInvoke(d); + + root.Content = new WpfHost(() => new SamplesApp.App()); + } + } +} diff --git a/src/SamplesApp/SamplesApp.Skia.WPF/Properties/AssemblyInfo.cs b/src/SamplesApp/SamplesApp.Skia.WPF/Properties/AssemblyInfo.cs new file mode 100644 index 000000000000..fcd66d147594 --- /dev/null +++ b/src/SamplesApp/SamplesApp.Skia.WPF/Properties/AssemblyInfo.cs @@ -0,0 +1,55 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SamplesApp.WPF")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SamplesApp.WPF")] +[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +//In order to begin building localizable applications, set +//CultureYouAreCodingWith in your .csproj file +//inside a . For example, if you are using US english +//in your source files, set the to en-US. Then uncomment +//the NeutralResourceLanguage attribute below. Update the "en-US" in +//the line below to match the UICulture setting in the project file. + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] + + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/SamplesApp/SamplesApp.Skia.WPF/Properties/Resources.Designer.cs b/src/SamplesApp/SamplesApp.Skia.WPF/Properties/Resources.Designer.cs new file mode 100644 index 000000000000..6b8931d2b6d4 --- /dev/null +++ b/src/SamplesApp/SamplesApp.Skia.WPF/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SamplesApp.WPF.Properties +{ + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SamplesApp.WPF.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/src/SamplesApp/SamplesApp.Skia.WPF/Properties/Resources.resx b/src/SamplesApp/SamplesApp.Skia.WPF/Properties/Resources.resx new file mode 100644 index 000000000000..af7dbebbacef --- /dev/null +++ b/src/SamplesApp/SamplesApp.Skia.WPF/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/SamplesApp/SamplesApp.Skia.WPF/Properties/Settings.Designer.cs b/src/SamplesApp/SamplesApp.Skia.WPF/Properties/Settings.Designer.cs new file mode 100644 index 000000000000..d7fa2d356865 --- /dev/null +++ b/src/SamplesApp/SamplesApp.Skia.WPF/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SamplesApp.WPF.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/src/SamplesApp/SamplesApp.Skia.WPF/Properties/Settings.settings b/src/SamplesApp/SamplesApp.Skia.WPF/Properties/Settings.settings new file mode 100644 index 000000000000..033d7a5e9e22 --- /dev/null +++ b/src/SamplesApp/SamplesApp.Skia.WPF/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/SamplesApp/SamplesApp.Skia.WPF/SamplesApp.Skia.WPF.csproj b/src/SamplesApp/SamplesApp.Skia.WPF/SamplesApp.Skia.WPF.csproj new file mode 100644 index 000000000000..0eb01a96573e --- /dev/null +++ b/src/SamplesApp/SamplesApp.Skia.WPF/SamplesApp.Skia.WPF.csproj @@ -0,0 +1,157 @@ + + + + + Debug + AnyCPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507} + WinExe + SamplesApp.WPF + SamplesApp.WPF + v4.7 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + true + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + bin\x86\Debug\ + DEBUG;TRACE + ;1998 + full + x86 + prompt + MinimumRecommendedRules.ruleset + true + + + true + bin\x86\Release\ + TRACE + true + ;1998 + pdbonly + x86 + prompt + MinimumRecommendedRules.ruleset + true + + + + + + + + + + + + 4.0 + + + + + + + + + 1.68.0 + + + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + App.xaml + Code + + + MainWindow.xaml + Code + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + + + {6ffac28c-aced-4ba1-954d-7e720b035928} + Uno.Xaml + unoxaml + + + {9f2268e0-49cc-43e6-a59f-5f5219349545} + Uno.Foundation.Skia + + + {dd7daec9-8f20-440a-81cd-8ed00dbc96d5} + Uno.UI.Runtime.Skia.Wpf + + + {2d066b5f-f67e-469c-abc6-5c3fcb8dda7a} + Uno.UI.Skia + + + {e2985032-e07e-4d8b-b716-8c96bb519ae3} + Uno.Skia + + + {1023dc8a-7fd7-41d1-9fd3-4142b2c76d00} + SamplesApp.Skia + + + + + + + diff --git a/src/SamplesApp/SamplesApp.Skia/SamplesApp.Skia.csproj b/src/SamplesApp/SamplesApp.Skia/SamplesApp.Skia.csproj new file mode 100644 index 000000000000..0236e2238e81 --- /dev/null +++ b/src/SamplesApp/SamplesApp.Skia/SamplesApp.Skia.csproj @@ -0,0 +1,42 @@ + + + + netstandard2.0 + latest + $(DefineConstants);__SKIA__;HAS_UNO;UNO_REFERENCE_API + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/SamplesApp/SamplesApp.UnitTests.Shared/Controls/UITests/Presentation/SampleChooserViewModel.netstd.cs b/src/SamplesApp/SamplesApp.UnitTests.Shared/Controls/UITests/Presentation/SampleChooserViewModel.netstd.cs index 64979ea5c934..fa674eacc9fa 100644 --- a/src/SamplesApp/SamplesApp.UnitTests.Shared/Controls/UITests/Presentation/SampleChooserViewModel.netstd.cs +++ b/src/SamplesApp/SamplesApp.UnitTests.Shared/Controls/UITests/Presentation/SampleChooserViewModel.netstd.cs @@ -1,4 +1,4 @@ -#if __WASM__ +#if __SKIA__ using SampleControl.Entities; using System; using System.Collections; diff --git a/src/SamplesApp/SamplesApp.UnitTests.Shared/Controls/UITests/Presentation/SampleChooserViewModel.skia.cs b/src/SamplesApp/SamplesApp.UnitTests.Shared/Controls/UITests/Presentation/SampleChooserViewModel.skia.cs new file mode 100644 index 000000000000..64979ea5c934 --- /dev/null +++ b/src/SamplesApp/SamplesApp.UnitTests.Shared/Controls/UITests/Presentation/SampleChooserViewModel.skia.cs @@ -0,0 +1,43 @@ +#if __WASM__ +using SampleControl.Entities; +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Uno.Disposables; +using System.Reflection; +using System.Runtime.InteropServices.WindowsRuntime; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Uno.UI; +using Uno.UI.Samples.Controls; +using Windows.UI; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; + +namespace SampleControl.Presentation +{ + + public partial class SampleChooserViewModel + { + public void PrintViewHierarchy(UIElement vg, StringBuilder sb, int level = 0) + { + + } + + private async Task DumpOutputFolderName(CancellationToken ct, string folderName) + { + var fullPath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), folderName); + + Console.WriteLine($"Output folder for tests: {fullPath}"); + } + + private async Task GenerateBitmap(CancellationToken ct, string folderName, string fileName, IFrameworkElement content) + { + + } + } +} +#endif diff --git a/src/SamplesApp/SamplesApp.UnitTests.Shared/Controls/UITests/Views/Controls/StarStackPanel.cs b/src/SamplesApp/SamplesApp.UnitTests.Shared/Controls/UITests/Views/Controls/StarStackPanel.cs index 48d37de8a8a6..8c7ed4afde0d 100644 --- a/src/SamplesApp/SamplesApp.UnitTests.Shared/Controls/UITests/Views/Controls/StarStackPanel.cs +++ b/src/SamplesApp/SamplesApp.UnitTests.Shared/Controls/UITests/Views/Controls/StarStackPanel.cs @@ -6,7 +6,7 @@ using System.Text.RegularExpressions; using Uno.UI.Samples.Helper; -#if !NETFX_CORE && !__ANDROID__ && !__IOS__ && !__WASM__ && !__MACOS__ +#if !NETFX_CORE && !__ANDROID__ && !__IOS__ && !NETSTANDARD && !__MACOS__ using System.Windows; using System.Windows.Controls; #else @@ -634,7 +634,7 @@ private static void HandleSizePropertyChanged(DependencyObject d, DependencyProp } #endregion -#if !__ANDROID__ && !__IOS__ && !__WASM__ //In Uno, Padding is (incorrectly) defined on Panel +#if !__ANDROID__ && !__IOS__ && !NETSTANDARD //In Uno, Padding is (incorrectly) defined on Panel #region Padding DependencyProperty public Thickness Padding diff --git a/src/SamplesApp/SamplesApp.UnitTests.Shared/SamplesApp.UnitTests.Shared.projitems b/src/SamplesApp/SamplesApp.UnitTests.Shared/SamplesApp.UnitTests.Shared.projitems index f4d674542c82..481bbe378609 100644 --- a/src/SamplesApp/SamplesApp.UnitTests.Shared/SamplesApp.UnitTests.Shared.projitems +++ b/src/SamplesApp/SamplesApp.UnitTests.Shared/SamplesApp.UnitTests.Shared.projitems @@ -16,6 +16,7 @@ + diff --git a/src/SamplesApp/SamplesApp.Wasm/LinkerConfig.xml b/src/SamplesApp/SamplesApp.Wasm/LinkerConfig.xml index ab5286a15e40..81e7400bbda7 100644 --- a/src/SamplesApp/SamplesApp.Wasm/LinkerConfig.xml +++ b/src/SamplesApp/SamplesApp.Wasm/LinkerConfig.xml @@ -1,6 +1,5 @@  - diff --git a/src/SamplesApp/SamplesApp.Wasm/SamplesApp.Wasm.csproj b/src/SamplesApp/SamplesApp.Wasm/SamplesApp.Wasm.csproj index 6f30f08da1b9..d5512637ba85 100644 --- a/src/SamplesApp/SamplesApp.Wasm/SamplesApp.Wasm.csproj +++ b/src/SamplesApp/SamplesApp.Wasm/SamplesApp.Wasm.csproj @@ -3,8 +3,7 @@ Exe netstandard2.0 - true - $(DefineConstants);__WASM__;HAS_UNO + $(DefineConstants);__WASM__;HAS_UNO;UNO_REFERENCE_API NU1701,CS1998 7.3 true @@ -76,16 +75,17 @@ - - - - - - + + + + + + + - - + + @@ -107,4 +107,7 @@ + + + diff --git a/src/SamplesApp/UITests.Shared/Helpers/UWPViewHelper.cs b/src/SamplesApp/UITests.Shared/Helpers/UWPViewHelper.cs index 958bede4624d..d93b21ee12b1 100644 --- a/src/SamplesApp/UITests.Shared/Helpers/UWPViewHelper.cs +++ b/src/SamplesApp/UITests.Shared/Helpers/UWPViewHelper.cs @@ -8,7 +8,7 @@ namespace Uno.UI { public static class UWPViewHelper { -#if !XAMARIN && !__WASM__ +#if !XAMARIN && !NETSTANDARD [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Size PhysicalToLogicalPixels(this Size size) => size; diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/AutoBorderStretchwithbottommargin.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/AutoBorderStretchwithbottommargin.xaml.cs index 72a8033189e2..b3b00caaf86b 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/AutoBorderStretchwithbottommargin.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/AutoBorderStretchwithbottommargin.xaml.cs @@ -4,7 +4,6 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; -#if NETFX_CORE using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; @@ -14,10 +13,6 @@ using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; -#elif HAS_UNO -using Windows.UI.Xaml.Controls; -using System.Globalization; -#endif // The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236 diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/AutoBorderStretchwithleftmargin.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/AutoBorderStretchwithleftmargin.xaml.cs index 8e2ea6c2cf9d..2c3049904e85 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/AutoBorderStretchwithleftmargin.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/AutoBorderStretchwithleftmargin.xaml.cs @@ -4,7 +4,6 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; -#if NETFX_CORE using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; @@ -14,10 +13,6 @@ using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; -#elif HAS_UNO -using Windows.UI.Xaml.Controls; -using System.Globalization; -#endif // The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236 diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/AutoBorderStretchwithrightmargin.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/AutoBorderStretchwithrightmargin.xaml.cs index f57ad56c799f..044ac51c6126 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/AutoBorderStretchwithrightmargin.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/AutoBorderStretchwithrightmargin.xaml.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; using Uno.UI.Samples.Controls; -#if NETFX_CORE using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; @@ -14,10 +13,6 @@ using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; -#elif HAS_UNO -using Windows.UI.Xaml.Controls; -using System.Globalization; -#endif // The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236 diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/AutoBorderStretchwithtopmargin.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/AutoBorderStretchwithtopmargin.xaml.cs index 4916915e73b4..4d6ccf7f41c6 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/AutoBorderStretchwithtopmargin.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/AutoBorderStretchwithtopmargin.xaml.cs @@ -4,7 +4,6 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; -#if NETFX_CORE using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; @@ -14,10 +13,6 @@ using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; -#elif HAS_UNO -using Windows.UI.Xaml.Controls; -using System.Globalization; -#endif // The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236 diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/BorderBottomwithmargins.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/BorderBottomwithmargins.xaml.cs index e7def84f2354..4337b1bc543d 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/BorderBottomwithmargins.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/BorderBottomwithmargins.xaml.cs @@ -4,7 +4,6 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; -#if NETFX_CORE using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; @@ -14,10 +13,6 @@ using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; -#elif HAS_UNO -using Windows.UI.Xaml.Controls; -using System.Globalization; -#endif // The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236 diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/BorderCenteredwithmargins.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/BorderCenteredwithmargins.xaml.cs index 43368c44de5f..5cededc78a9c 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/BorderCenteredwithmargins.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/BorderCenteredwithmargins.xaml.cs @@ -4,7 +4,6 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; -#if NETFX_CORE using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; @@ -14,11 +13,6 @@ using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; -#elif HAS_UNO -using Windows.UI.Xaml.Controls; -using System.Globalization; -#endif - // The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236 diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/BorderLeftwithmargins.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/BorderLeftwithmargins.xaml.cs index 979a798730ec..317386a75c14 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/BorderLeftwithmargins.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/BorderLeftwithmargins.xaml.cs @@ -4,7 +4,6 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; -#if NETFX_CORE using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; @@ -14,10 +13,6 @@ using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; -#elif HAS_UNO -using Windows.UI.Xaml.Controls; -using System.Globalization; -#endif // The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236 diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/BorderRightwithmargins.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/BorderRightwithmargins.xaml.cs index 8f539e90ac99..cd38d247c83e 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/BorderRightwithmargins.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/BorderRightwithmargins.xaml.cs @@ -4,7 +4,6 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; -#if NETFX_CORE using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; @@ -14,11 +13,6 @@ using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; -#elif HAS_UNO -using Windows.UI.Xaml.Controls; -using System.Globalization; -#endif - // The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236 diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/BorderTopwithmargins.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/BorderTopwithmargins.xaml.cs index dc032969861c..54fed9c3edb5 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/BorderTopwithmargins.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/BorderTopwithmargins.xaml.cs @@ -4,7 +4,6 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; -#if NETFX_CORE using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; @@ -14,11 +13,6 @@ using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; -#elif HAS_UNO -using Windows.UI.Xaml.Controls; -using System.Globalization; -#endif - // The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236 diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_CornerRadius.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_CornerRadius.xaml.cs index 7068d79bd3c0..a79ad09ab16e 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_CornerRadius.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_CornerRadius.xaml.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; using Uno.UI.Samples.Controls; -#if NETFX_CORE using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; @@ -14,11 +13,6 @@ using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; -#elif HAS_UNO -using Windows.UI.Xaml.Controls; -using System.Globalization; -#endif - namespace Uno.UI.Samples.UITests.BorderTestsControl { diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_CornerRadius_Alignments.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_CornerRadius_Alignments.xaml.cs index 287c1cd48fe1..cd9d0bf04209 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_CornerRadius_Alignments.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_CornerRadius_Alignments.xaml.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; using Uno.UI.Samples.Controls; -#if NETFX_CORE using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; @@ -14,10 +13,6 @@ using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; -#elif HAS_UNO -using Windows.UI.Xaml.Controls; -using System.Globalization; -#endif namespace Uno.UI.Samples.UITests.BorderTestsControl diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_CornerRadius_Binding.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_CornerRadius_Binding.xaml.cs index 3bb99965df16..5c9a9c7617bf 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_CornerRadius_Binding.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_CornerRadius_Binding.xaml.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; using Uno.UI.Samples.Controls; -#if NETFX_CORE using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; @@ -14,11 +13,6 @@ using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; -#elif HAS_UNO -using Windows.UI.Xaml.Controls; -using System.Globalization; -#endif - namespace Uno.UI.Samples.UITests.BorderTestsControl { diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_CornerRadius_with_Opacity.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_CornerRadius_with_Opacity.xaml.cs index cd915a4801b6..4281d4047795 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_CornerRadius_with_Opacity.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_CornerRadius_with_Opacity.xaml.cs @@ -4,8 +4,6 @@ using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; using Uno.UI.Samples.Controls; - -#if NETFX_CORE using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; @@ -15,10 +13,6 @@ using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; -#elif HAS_UNO -using Windows.UI.Xaml.Controls; -using System.Globalization; -#endif namespace Uno.UI.Samples.UITests.BorderTestsControl { diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_Simple.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_Simple.xaml.cs index db96f7be7b3d..bf68c8c568df 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_Simple.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_Simple.xaml.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; using Uno.UI.Samples.Controls; -#if NETFX_CORE using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; @@ -14,10 +13,6 @@ using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; -#elif HAS_UNO -using Windows.UI.Xaml.Controls; -using System.Globalization; -#endif namespace Uno.UI.Samples.UITests.BorderTestsControl { diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_Simple_No_Background.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_Simple_No_Background.xaml.cs index b4ce64030ea9..349e6047f085 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_Simple_No_Background.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_Simple_No_Background.xaml.cs @@ -4,7 +4,6 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; -#if NETFX_CORE using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; @@ -14,10 +13,6 @@ using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; -#elif HAS_UNO -using Windows.UI.Xaml.Controls; -using System.Globalization; -#endif // The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236 diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_Simple_No_Background_With_Content_Border_With_Background.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_Simple_No_Background_With_Content_Border_With_Background.xaml.cs index 61bb80374a65..fedfbd137225 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_Simple_No_Background_With_Content_Border_With_Background.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_Simple_No_Background_With_Content_Border_With_Background.xaml.cs @@ -4,7 +4,6 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; -#if NETFX_CORE using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; @@ -14,10 +13,6 @@ using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; -#elif HAS_UNO -using Windows.UI.Xaml.Controls; -using System.Globalization; -#endif // The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236 diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_Simple_No_Background_With_TextBox.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_Simple_No_Background_With_TextBox.xaml.cs index 086848b131ea..aa9981fe64f8 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_Simple_No_Background_With_TextBox.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_Simple_No_Background_With_TextBox.xaml.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; using Uno.UI.Samples.Controls; -#if NETFX_CORE using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; @@ -14,11 +13,6 @@ using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; -#elif HAS_UNO -using Windows.UI.Xaml.Controls; -using System.Globalization; -#endif - // The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236 diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_Simple_with_Opacity.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_Simple_with_Opacity.xaml.cs index 4e661feff3e7..f80e0267229f 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_Simple_with_Opacity.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_Simple_with_Opacity.xaml.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; using Uno.UI.Samples.Controls; -#if NETFX_CORE using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; @@ -14,10 +13,6 @@ using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; -#elif HAS_UNO -using Windows.UI.Xaml.Controls; -using System.Globalization; -#endif namespace Uno.UI.Samples.UITests.BorderTestsControl { diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_Simple_with_Uniform_Thickness.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_Simple_with_Uniform_Thickness.xaml.cs index 1e9cedd472b0..fa99f8aa4468 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_Simple_with_Uniform_Thickness.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_Simple_with_Uniform_Thickness.xaml.cs @@ -4,7 +4,6 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; -#if NETFX_CORE using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; @@ -14,13 +13,6 @@ using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; -#elif HAS_UNO -using Windows.UI.Xaml.Controls; -using System.Globalization; -#endif - - -// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236 namespace Uno.UI.Samples.UITests.BorderTestsControl { diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_Simple_with_non_Uniform_Thickness.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_Simple_with_non_Uniform_Thickness.xaml.cs index b8e0cfbf8dbf..00c978113f1b 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_Simple_with_non_Uniform_Thickness.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Border_Simple_with_non_Uniform_Thickness.xaml.cs @@ -4,7 +4,6 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; -#if NETFX_CORE using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; @@ -14,11 +13,6 @@ using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; -#elif HAS_UNO -using Windows.UI.Xaml.Controls; -using System.Globalization; -#endif - // The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236 diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Circle.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Circle.xaml.cs index 907885c2316a..fa1b1b61f575 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Circle.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Circle.xaml.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; using Uno.UI.Samples.Controls; -#if NETFX_CORE using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; @@ -14,11 +13,6 @@ using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; -#elif HAS_UNO -using Windows.UI.Xaml.Controls; -using System.Globalization; -#endif - namespace Uno.UI.Samples.UITests.BorderTestsControl { diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/NonUniformThicknessandRadius.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/NonUniformThicknessandRadius.xaml.cs index 354c356c0153..f0558d575235 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/NonUniformThicknessandRadius.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/NonUniformThicknessandRadius.xaml.cs @@ -4,7 +4,6 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; -#if NETFX_CORE using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; @@ -14,13 +13,6 @@ using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; -#elif HAS_UNO -using Windows.UI.Xaml.Controls; -using System.Globalization; -#endif - - -// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236 namespace Uno.UI.Samples.UITests.BorderTestsControl { diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/OnepxThicknessandRadius.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/OnepxThicknessandRadius.xaml.cs index 4a30531f3982..bbbe09b10361 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/OnepxThicknessandRadius.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/OnepxThicknessandRadius.xaml.cs @@ -4,7 +4,6 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; -#if NETFX_CORE using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; @@ -14,13 +13,6 @@ using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; -#elif HAS_UNO -using Windows.UI.Xaml.Controls; -using System.Globalization; -#endif - - -// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236 namespace Uno.UI.Samples.UITests.BorderTestsControl { diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/OnepxThicknessandRadiusAndTextBlock.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/OnepxThicknessandRadiusAndTextBlock.xaml.cs index c9d570567196..4b3be23e8987 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/OnepxThicknessandRadiusAndTextBlock.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/OnepxThicknessandRadiusAndTextBlock.xaml.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; using Uno.UI.Samples.Controls; -#if NETFX_CORE using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; @@ -14,13 +13,6 @@ using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; -#elif HAS_UNO -using Windows.UI.Xaml.Controls; -using System.Globalization; -#endif - - -// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236 namespace Uno.UI.Samples.UITests.BorderTestsControl { diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Simple_with_Radius.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Simple_with_Radius.xaml.cs index 503ff268f7cc..436cc7a61998 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Simple_with_Radius.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Simple_with_Radius.xaml.cs @@ -4,7 +4,6 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; -#if NETFX_CORE using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; @@ -14,10 +13,6 @@ using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; -#elif HAS_UNO -using Windows.UI.Xaml.Controls; -using System.Globalization; -#endif namespace Uno.UI.Samples.UITests.BorderTestsControl { diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/SimplewithNonUnifmormRadius.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/SimplewithNonUnifmormRadius.xaml.cs index 21847b3746b4..e321a6c4e63f 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/SimplewithNonUnifmormRadius.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/SimplewithNonUnifmormRadius.xaml.cs @@ -4,7 +4,6 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; -#if NETFX_CORE using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; @@ -14,13 +13,6 @@ using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; -#elif HAS_UNO -using Windows.UI.Xaml.Controls; -using System.Globalization; -#endif - - -// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236 namespace Uno.UI.Samples.UITests.BorderTestsControl { diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/UniformThicknessandNonUniformRadius.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/UniformThicknessandNonUniformRadius.xaml.cs index 02e94653e6cd..ca35ea42a5d5 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/UniformThicknessandNonUniformRadius.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/UniformThicknessandNonUniformRadius.xaml.cs @@ -4,7 +4,6 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; -#if NETFX_CORE using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; @@ -14,13 +13,6 @@ using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; -#elif HAS_UNO -using Windows.UI.Xaml.Controls; -using System.Globalization; -#endif - - -// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236 namespace Uno.UI.Samples.UITests.BorderTestsControl { diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Uniform_Thickness_and_Large_Radius.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Uniform_Thickness_and_Large_Radius.xaml.cs index b1fb6c5d5c8a..5e567b56d6d0 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Uniform_Thickness_and_Large_Radius.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Uniform_Thickness_and_Large_Radius.xaml.cs @@ -4,7 +4,6 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; -#if NETFX_CORE using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; @@ -14,13 +13,6 @@ using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; -#elif HAS_UNO -using Windows.UI.Xaml.Controls; -using System.Globalization; -#endif - - -// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236 namespace Uno.UI.Samples.UITests.BorderTestsControl { diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Uniform_Thickness_and_Small_Radius.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Uniform_Thickness_and_Small_Radius.xaml.cs index c7bc2b40b5e6..7808638f53ca 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Uniform_Thickness_and_Small_Radius.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/Uniform_Thickness_and_Small_Radius.xaml.cs @@ -4,7 +4,6 @@ using System.IO; using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; -#if NETFX_CORE using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; @@ -14,13 +13,6 @@ using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; -#elif HAS_UNO -using Windows.UI.Xaml.Controls; -using System.Globalization; -#endif - - -// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236 namespace Uno.UI.Samples.UITests.BorderTestsControl { diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/ZeroThickness.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/ZeroThickness.xaml.cs index f05af56078d2..e04ead930298 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/ZeroThickness.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/ZeroThickness.xaml.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; using Uno.UI.Samples.Controls; -#if NETFX_CORE using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; @@ -14,13 +13,6 @@ using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; -#elif HAS_UNO -using Windows.UI.Xaml.Controls; -using System.Globalization; -#endif - - -// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236 namespace Uno.UI.Samples.UITests.BorderTestsControl { diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/ZeroThicknessWithRadius.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/ZeroThicknessWithRadius.xaml.cs index 8e3fa6cde9dd..033e16bb16d3 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/ZeroThicknessWithRadius.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/BorderTests/ZeroThicknessWithRadius.xaml.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Runtime.InteropServices.WindowsRuntime; using Uno.UI.Samples.Controls; -#if NETFX_CORE using Windows.Foundation; using Windows.Foundation.Collections; using Windows.UI.Xaml; @@ -14,13 +13,6 @@ using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Navigation; -#elif HAS_UNO -using Windows.UI.Xaml.Controls; -using System.Globalization; -#endif - - -// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236 namespace Uno.UI.Samples.UITests.BorderTestsControl { diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/Button/Button_UseUWPDefaultStyles.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/Button/Button_UseUWPDefaultStyles.xaml.cs index 14d67213f253..29c878d5ef4f 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/Button/Button_UseUWPDefaultStyles.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/Button/Button_UseUWPDefaultStyles.xaml.cs @@ -27,7 +27,7 @@ #else using _NativeType = Windows.UI.Xaml.Controls.Grid; // We use a 'fake' native style on WASM #endif -#if __WASM__ +#if NETSTANDARD using Uno.UI; #elif __MACOS__ using AppKit; diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/ImageTests/Models/ImageFilePathModel.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/ImageTests/Models/ImageFilePathModel.cs index 8bf499317f31..316bfec22a0b 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/ImageTests/Models/ImageFilePathModel.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/ImageTests/Models/ImageFilePathModel.cs @@ -73,7 +73,7 @@ private Uri FilePathUri private async Task GetAndCreateFilePath(CancellationToken ct) { -#if HAS_UNO && !__WASM__ && !__MACOS__ +#if HAS_UNO && !__WASM__ && !__SKIA__ && !__MACOS__ var bitmap = await CreateBitmap(); this.Log().Warn(bitmap.ToString()); diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/ScrollViewerTests/ScrollViewer_Padding.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/ScrollViewerTests/ScrollViewer_Padding.xaml.cs index aeda18d54d9d..d5546e89ad84 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/ScrollViewerTests/ScrollViewer_Padding.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/ScrollViewerTests/ScrollViewer_Padding.xaml.cs @@ -24,7 +24,7 @@ public ScrollViewer_Padding() private async void OnLoaded(object sender, RoutedEventArgs e) { await Task.Delay(300); -#if HAS_UNO && !__WASM__ +#if HAS_UNO && !__WASM__ && !__SKIA__ layout.Text = this.ShowLocalVisualTree(); #endif } diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/TextBlockControl/TextBlock_FontWeight_Dynamic.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/TextBlockControl/TextBlock_FontWeight_Dynamic.xaml.cs index 39f472ddb594..1a42ca9380dd 100644 --- a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/TextBlockControl/TextBlock_FontWeight_Dynamic.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/TextBlockControl/TextBlock_FontWeight_Dynamic.xaml.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using System.Reflection; -using FluentAssertions.Types; using Uno.UI.Samples.Controls; using Windows.UI.Text; using Windows.UI.Xaml.Controls; diff --git a/src/SolutionTemplate/Uno.ProjectTemplates.Dotnet/content/unoapp-prism/BlankApp.Wasm/BlankApp.Wasm.csproj b/src/SolutionTemplate/Uno.ProjectTemplates.Dotnet/content/unoapp-prism/BlankApp.Wasm/BlankApp.Wasm.csproj index e95de9bfb44a..eadba440869f 100644 --- a/src/SolutionTemplate/Uno.ProjectTemplates.Dotnet/content/unoapp-prism/BlankApp.Wasm/BlankApp.Wasm.csproj +++ b/src/SolutionTemplate/Uno.ProjectTemplates.Dotnet/content/unoapp-prism/BlankApp.Wasm/BlankApp.Wasm.csproj @@ -3,8 +3,6 @@ Exe netstandard2.0 - true - $(DefineConstants);__WASM__ NU1701 @@ -38,7 +36,7 @@ - + diff --git a/src/SolutionTemplate/Uno.ProjectTemplates.Dotnet/content/xamarinforms-wasm/UnoXFQuickStart.Wasm/UnoXFQuickStart.Wasm.csproj b/src/SolutionTemplate/Uno.ProjectTemplates.Dotnet/content/xamarinforms-wasm/UnoXFQuickStart.Wasm/UnoXFQuickStart.Wasm.csproj index d57e202ee98a..bb200a80eec6 100644 --- a/src/SolutionTemplate/Uno.ProjectTemplates.Dotnet/content/xamarinforms-wasm/UnoXFQuickStart.Wasm/UnoXFQuickStart.Wasm.csproj +++ b/src/SolutionTemplate/Uno.ProjectTemplates.Dotnet/content/xamarinforms-wasm/UnoXFQuickStart.Wasm/UnoXFQuickStart.Wasm.csproj @@ -3,7 +3,6 @@ Exe netstandard2.0 - true $(DefineConstants);__WASM__ NU1701 diff --git a/src/SolutionTemplate/UnoSolutionTemplate/Wasm/UnoQuickStart.Wasm.csproj b/src/SolutionTemplate/UnoSolutionTemplate/Wasm/UnoQuickStart.Wasm.csproj index 86f7f50e1850..01706e72762a 100644 --- a/src/SolutionTemplate/UnoSolutionTemplate/Wasm/UnoQuickStart.Wasm.csproj +++ b/src/SolutionTemplate/UnoSolutionTemplate/Wasm/UnoQuickStart.Wasm.csproj @@ -3,8 +3,6 @@ Exe netstandard2.0 - true - $(DefineConstants);__WASM__ NU1701 @@ -44,7 +42,7 @@ - + diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators/BindableTypeProviders/BindableTypeProvidersGenerationTask.cs b/src/SourceGenerators/Uno.UI.SourceGenerators/BindableTypeProviders/BindableTypeProvidersGenerationTask.cs index 0a100577e308..ce9ecb0ea238 100644 --- a/src/SourceGenerators/Uno.UI.SourceGenerators/BindableTypeProviders/BindableTypeProvidersGenerationTask.cs +++ b/src/SourceGenerators/Uno.UI.SourceGenerators/BindableTypeProviders/BindableTypeProvidersGenerationTask.cs @@ -97,12 +97,12 @@ private bool IsApplication(ProjectInstance projectInstance) var isiOSApp = projectInstance.GetPropertyValue("ProjectTypeGuids")?.Equals("{FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}", StringComparison.OrdinalIgnoreCase) ?? false; var ismacOSApp = projectInstance.GetPropertyValue("ProjectTypeGuids")?.Equals("{A3F8F2AB-B479-4A4A-A458-A89E7DC349F1};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}", StringComparison.OrdinalIgnoreCase) ?? false; var isExe = projectInstance.GetPropertyValue("OutputType")?.Equals("Exe", StringComparison.OrdinalIgnoreCase) ?? false; - var isWasm = projectInstance.GetPropertyValue("WasmHead")?.Equals("true", StringComparison.OrdinalIgnoreCase) ?? false; + var isUnoHead = projectInstance.GetPropertyValue("IsUnoHead")?.Equals("true", StringComparison.OrdinalIgnoreCase) ?? false; return isAndroidApp || (isiOSApp && isExe) || (ismacOSApp && isExe) - || isWasm; + || isUnoHead; } private string GenerateTypeProviders(IEnumerable modules) diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators/RemoteControl/RemoteControlGenerator.cs b/src/SourceGenerators/Uno.UI.SourceGenerators/RemoteControl/RemoteControlGenerator.cs index 5705d6e0385e..11a64c49db29 100644 --- a/src/SourceGenerators/Uno.UI.SourceGenerators/RemoteControl/RemoteControlGenerator.cs +++ b/src/SourceGenerators/Uno.UI.SourceGenerators/RemoteControl/RemoteControlGenerator.cs @@ -111,12 +111,12 @@ private bool IsApplication(ProjectInstance projectInstance) var isiOSApp = projectInstance.GetPropertyValue("ProjectTypeGuids")?.Equals("{FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}", StringComparison.OrdinalIgnoreCase) ?? false; var ismacOSApp = projectInstance.GetPropertyValue("ProjectTypeGuids")?.Equals("{A3F8F2AB-B479-4A4A-A458-A89E7DC349F1};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}", StringComparison.OrdinalIgnoreCase) ?? false; var isExe = projectInstance.GetPropertyValue("OutputType")?.Equals("Exe", StringComparison.OrdinalIgnoreCase) ?? false; - var isWasm = projectInstance.GetPropertyValue("WasmHead")?.Equals("true", StringComparison.OrdinalIgnoreCase) ?? false; + var isUnoHead = projectInstance.GetPropertyValue("IsUnoHead")?.Equals("true", StringComparison.OrdinalIgnoreCase) ?? false; return isAndroidApp || (isiOSApp && isExe) || (ismacOSApp && isExe) - || isWasm; + || isUnoHead; } } } diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlCodeGeneration.cs b/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlCodeGeneration.cs index b0e96793d264..12ba646951bc 100644 --- a/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlCodeGeneration.cs +++ b/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlCodeGeneration.cs @@ -224,12 +224,15 @@ public KeyValuePair[] Generate() var filesQuery = files .ToArray(); - var outputFiles = filesQuery - .Distinct() -#if !DEBUG - .AsParallel() -#endif - .Select(file => new KeyValuePair( + IEnumerable filesToProcess = filesQuery; + + if (!Debugger.IsAttached) + { + filesToProcess = filesToProcess.AsParallel(); + } + + var outputFiles = filesToProcess.Select(file => new KeyValuePair( + file.UniqueID, new XamlFileGenerator( file: file, @@ -531,7 +534,7 @@ private string GenerateGlobalResources(IEnumerable files, Xa } } - if (IsUnoAssembly) + if (IsUnoAssembly && _xamlSourceFiles.Any()) { // Build master dictionary foreach (var dictProperty in map.GetAllDictionaryProperties(_baseResourceDependencies)) diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.Reflection.cs b/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.Reflection.cs index 489a42bbccf6..e84bf64e095f 100644 --- a/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.Reflection.cs +++ b/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.Reflection.cs @@ -19,6 +19,7 @@ using Uno; using Uno.Logging; using Uno.UI.SourceGenerators.XamlGenerator.XamlRedirection; +using System.Diagnostics; namespace Uno.UI.SourceGenerators.XamlGenerator { diff --git a/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.cs b/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.cs index 88ed999dafac..6f1dd70660f8 100644 --- a/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.cs +++ b/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.cs @@ -286,7 +286,7 @@ private string InnerGenerateFile() writer.AppendLineInvariant("using _View = UIKit.UIView;"); writer.AppendLineInvariant("#elif __MACOS__"); writer.AppendLineInvariant("using _View = AppKit.NSView;"); - writer.AppendLineInvariant("#elif __WASM__"); + writer.AppendLineInvariant("#elif UNO_REFERENCE_API"); writer.AppendLineInvariant("using _View = Windows.UI.Xaml.UIElement;"); writer.AppendLineInvariant("#elif NET461"); writer.AppendLineInvariant("using _View = Windows.UI.Xaml.UIElement;"); diff --git a/src/SourceGenerators/XamlGenerationTests/XamlGenerationTests.csproj b/src/SourceGenerators/XamlGenerationTests/XamlGenerationTests.csproj index 3a0d6bd3bafc..67c55dc339c1 100644 --- a/src/SourceGenerators/XamlGenerationTests/XamlGenerationTests.csproj +++ b/src/SourceGenerators/XamlGenerationTests/XamlGenerationTests.csproj @@ -18,7 +18,7 @@ - $(DefineConstants);__WASM__ + $(DefineConstants);UNO_REFERENCE_API diff --git a/src/Uno.CrossTargetting.props b/src/Uno.CrossTargetting.props index 83c4b48fdbb2..448747d6db98 100644 --- a/src/Uno.CrossTargetting.props +++ b/src/Uno.CrossTargetting.props @@ -41,9 +41,16 @@ + + $(DefineConstants);__WASM__;UNO_REFERENCE_API;HAS_EXPENSIVE_TRYFINALLY + + + + $(DefineConstants);__SKIA__;UNO_REFERENCE_API + - - $(DefineConstants);__WASM__;HAS_EXPENSIVE_TRYFINALLY + + $(DefineConstants);__NETSTD_REFERENCE__;UNO_REFERENCE_API @@ -87,7 +94,7 @@ + Condition="'$(UnoNugetOverrideVersion)'!='' and ('$(UnoRuntimeIdentifier)'=='' or '$(UnoRuntimeIdentifier)'=='Reference')"> <_OverrideTargetFramework>$(TargetFramework) diff --git a/src/Uno.Foundation.Runtime.Wasm/AssemblyInfo.cs b/src/Uno.Foundation.Runtime.Wasm/AssemblyInfo.cs new file mode 100644 index 000000000000..4483ce7ff7e9 --- /dev/null +++ b/src/Uno.Foundation.Runtime.Wasm/AssemblyInfo.cs @@ -0,0 +1,15 @@ +using global::System.Reflection; +using global::System.Runtime.CompilerServices; +using global::System.Runtime.InteropServices; + +[assembly: InternalsVisibleTo("Uno.UI")] +[assembly: InternalsVisibleTo("Uno")] +[assembly: InternalsVisibleTo("Uno.UI.Wasm")] +[assembly: InternalsVisibleTo("Uno.Wasm")] +[assembly: InternalsVisibleTo("Uno.UI.Tests")] + +#if __IOS__ +[assembly: Foundation.LinkerSafe] +#elif __ANDROID__ +[assembly: Android.LinkerSafe] +#endif diff --git a/src/Uno.Foundation/Interop/IJSObject.wasm.cs b/src/Uno.Foundation.Runtime.Wasm/Interop/IJSObject.wasm.cs similarity index 100% rename from src/Uno.Foundation/Interop/IJSObject.wasm.cs rename to src/Uno.Foundation.Runtime.Wasm/Interop/IJSObject.wasm.cs diff --git a/src/Uno.Foundation/Interop/IJSObjectMetadata.wasm.cs b/src/Uno.Foundation.Runtime.Wasm/Interop/IJSObjectMetadata.wasm.cs similarity index 100% rename from src/Uno.Foundation/Interop/IJSObjectMetadata.wasm.cs rename to src/Uno.Foundation.Runtime.Wasm/Interop/IJSObjectMetadata.wasm.cs diff --git a/src/Uno.Foundation/Interop/JSObject.wasm.cs b/src/Uno.Foundation.Runtime.Wasm/Interop/JSObject.wasm.cs similarity index 98% rename from src/Uno.Foundation/Interop/JSObject.wasm.cs rename to src/Uno.Foundation.Runtime.Wasm/Interop/JSObject.wasm.cs index 6d38afd8cf46..5b5e752b6426 100644 --- a/src/Uno.Foundation/Interop/JSObject.wasm.cs +++ b/src/Uno.Foundation.Runtime.Wasm/Interop/JSObject.wasm.cs @@ -8,7 +8,6 @@ namespace Uno.Foundation.Interop { [Obfuscation(Feature = "renaming", Exclude = true)] - [Preserve] public sealed class JSObject { private static readonly Func _strToIntPtr = @@ -20,7 +19,6 @@ public sealed class JSObject /// Used by javascript to dispatch a method call to the managed object at . /// [Obfuscation(Feature = "renaming", Exclude = true)] - [Preserve] public static void Dispatch(string handlePtr, string method, string parameters) { var intPtr = _strToIntPtr(handlePtr); diff --git a/src/Uno.Foundation/Interop/JSObjectHandle.wasm.cs b/src/Uno.Foundation.Runtime.Wasm/Interop/JSObjectHandle.wasm.cs similarity index 100% rename from src/Uno.Foundation/Interop/JSObjectHandle.wasm.cs rename to src/Uno.Foundation.Runtime.Wasm/Interop/JSObjectHandle.wasm.cs diff --git a/src/Uno.Foundation/Interop/JSObjectMetadataProvider.wasm.cs b/src/Uno.Foundation.Runtime.Wasm/Interop/JSObjectMetadataProvider.wasm.cs similarity index 100% rename from src/Uno.Foundation/Interop/JSObjectMetadataProvider.wasm.cs rename to src/Uno.Foundation.Runtime.Wasm/Interop/JSObjectMetadataProvider.wasm.cs diff --git a/src/Uno.Foundation/Runtime.wasm.cs b/src/Uno.Foundation.Runtime.Wasm/Interop/Runtime.wasm.cs similarity index 99% rename from src/Uno.Foundation/Runtime.wasm.cs rename to src/Uno.Foundation.Runtime.Wasm/Interop/Runtime.wasm.cs index d415ffe7112c..8a5cbbad42ce 100644 --- a/src/Uno.Foundation/Runtime.wasm.cs +++ b/src/Uno.Foundation.Runtime.Wasm/Interop/Runtime.wasm.cs @@ -62,7 +62,6 @@ public static class WebAssemblyRuntime || RuntimeInformation.IsOSPlatform(OSPlatform.Create("BROWSER")); - [Preserve] public static class TraceProvider { // {0B273C3E-11F6-47E7-ABDE-5A777893F3C0} @@ -348,7 +347,6 @@ public static Task InvokeAsync(string promiseCode) return tcs.Task; } - [Preserve] [EditorBrowsable(EditorBrowsableState.Never)] public static void DispatchAsyncResult(long handle, string result) { @@ -362,7 +360,6 @@ public static void DispatchAsyncResult(long handle, string result) } } - [Preserve] [EditorBrowsable(EditorBrowsableState.Never)] public static void DispatchAsyncError(long handle, string error) { diff --git a/src/Uno.Foundation/Interop/TSInteropMarshaller.wasm.cs b/src/Uno.Foundation.Runtime.Wasm/Interop/TSInteropMarshaller.wasm.cs similarity index 100% rename from src/Uno.Foundation/Interop/TSInteropMarshaller.wasm.cs rename to src/Uno.Foundation.Runtime.Wasm/Interop/TSInteropMarshaller.wasm.cs diff --git a/src/Uno.Foundation/Interop/TSInteropMessageAttribute.wasm.cs b/src/Uno.Foundation.Runtime.Wasm/Interop/TSInteropMessageAttribute.wasm.cs similarity index 100% rename from src/Uno.Foundation/Interop/TSInteropMessageAttribute.wasm.cs rename to src/Uno.Foundation.Runtime.Wasm/Interop/TSInteropMessageAttribute.wasm.cs diff --git a/src/Uno.Foundation.Runtime.Wasm/LinkerDefinition.Wasm.xml b/src/Uno.Foundation.Runtime.Wasm/LinkerDefinition.Wasm.xml new file mode 100644 index 000000000000..c6d88abe94ef --- /dev/null +++ b/src/Uno.Foundation.Runtime.Wasm/LinkerDefinition.Wasm.xml @@ -0,0 +1,4 @@ + + + + diff --git a/src/Uno.Foundation.Runtime.Wasm/Uno.Foundation.Runtime.Wasm.csproj b/src/Uno.Foundation.Runtime.Wasm/Uno.Foundation.Runtime.Wasm.csproj new file mode 100644 index 000000000000..3637e24423b3 --- /dev/null +++ b/src/Uno.Foundation.Runtime.Wasm/Uno.Foundation.Runtime.Wasm.csproj @@ -0,0 +1,53 @@ + + + netstandard2.0 + + + + $(NoWarn);NU1701 + true + + false + true + + WebAssembly + + + + true + nventive + https://github.com/unoplatform/uno + https://nv-assets.azurewebsites.net/logos/uno.png + uno.png + https://github.com/unoplatform/uno + This package provides the .NET interoperability support for WebAssembly in Uno Platform projects. + Copyright (C) 2015-2020 nventive inc. - all rights reserved + + + + + + + + + + + + + + + + + + + $(AssemblyName).xml + + + + + + + + + + diff --git a/src/Uno.Foundation.Skia/AssemblyInfo.skia.cs b/src/Uno.Foundation.Skia/AssemblyInfo.skia.cs new file mode 100644 index 000000000000..3c8eb736fb22 --- /dev/null +++ b/src/Uno.Foundation.Skia/AssemblyInfo.skia.cs @@ -0,0 +1,3 @@ +using global::System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Uno.UI.Skia.Platform")] diff --git a/src/Uno.Foundation.Skia/Uno.Foundation.Skia.csproj b/src/Uno.Foundation.Skia/Uno.Foundation.Skia.csproj new file mode 100644 index 000000000000..b001ef830f72 --- /dev/null +++ b/src/Uno.Foundation.Skia/Uno.Foundation.Skia.csproj @@ -0,0 +1,30 @@ + + + netstandard2.0 + + + + Uno.Foundation + Windows.Foundation + $(NoWarn);NU1701 + true + + false + true + + Skia + ..\Uno.Foundation\ + + + + + + + + + + + + + + diff --git a/src/Uno.Foundation.Wasm/Uno.Foundation.Wasm.csproj b/src/Uno.Foundation.Wasm/Uno.Foundation.Wasm.csproj new file mode 100644 index 000000000000..5797e20fb59a --- /dev/null +++ b/src/Uno.Foundation.Wasm/Uno.Foundation.Wasm.csproj @@ -0,0 +1,33 @@ + + + netstandard2.0 + + + + Uno.Foundation + Windows.Foundation + $(NoWarn);NU1701 + true + + false + true + + WebAssembly + ..\Uno.Foundation\ + + + + + + + + + + + + + + + + + diff --git a/src/Uno.Foundation/Eventing/EventActivity.cs b/src/Uno.Foundation/Eventing/EventActivity.cs deleted file mode 100644 index 70322aa21da2..000000000000 --- a/src/Uno.Foundation/Eventing/EventActivity.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Uno.Diagnostics.Eventing -{ - /// - /// Identifies a tracing event activity. - /// - public class EventActivity - { - public EventActivity(long activityId) - { - Id = activityId; - } - - public long Id { get; } - } -} diff --git a/src/Uno.Foundation/Eventing/EventDescriptor.cs b/src/Uno.Foundation/Eventing/EventDescriptor.cs deleted file mode 100644 index 643a35ec48db..000000000000 --- a/src/Uno.Foundation/Eventing/EventDescriptor.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Uno.Diagnostics.Eventing -{ - /// - /// Defines an event for the tracing subsystem - /// - public class EventDescriptor - { - public EventDescriptor(int eventId, int? task = null, EventOpcode opcode = EventOpcode.Info, byte channel = 0, byte level = 0, long keywords = 0, byte version = 1, long activityId = 0, long relatedActivityId = 0) - { - EventId = eventId; - Version = version; - Channel = channel; - Level = level; - Opcode = opcode; - Task = task ?? EventId; - Keywords = keywords; - ActivityId = activityId; - RelatedActivityId = relatedActivityId; - } - - public int EventId { get; } - - public byte Version { get; } - - public byte Channel { get; } - - public byte Level { get; } - - public EventOpcode Opcode { get; } - - public int Task { get; } - - public long Keywords { get; } - - public long ActivityId { get; } - - public long RelatedActivityId { get; } - } -} diff --git a/src/Uno.Foundation/Eventing/EventOpcode.cs b/src/Uno.Foundation/Eventing/EventOpcode.cs deleted file mode 100644 index 128c830f26e7..000000000000 --- a/src/Uno.Foundation/Eventing/EventOpcode.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Uno.Diagnostics.Eventing -{ - public enum EventOpcode : byte - { - Info, - Start, - Stop, - DataCollectionStart, - DataCollectionStop, - Extension, - Reply, - Resume, - Suspend, - Send, - Receive = 240 - } -} diff --git a/src/Uno.Foundation/Eventing/EventProviderExtensions.cs b/src/Uno.Foundation/Eventing/EventProviderExtensions.cs deleted file mode 100644 index 09527a0084f9..000000000000 --- a/src/Uno.Foundation/Eventing/EventProviderExtensions.cs +++ /dev/null @@ -1,228 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; - -namespace Uno.Diagnostics.Eventing -{ - public static class EventProviderExtensions - { - /// - /// This counter will be mapped in the ETL transform tool to an actual - /// activity ID. - /// - private static long _activityCounter = 0; - - /// - /// Writes an event in the specified provider. - /// - /// The event provider to use - /// The event ID to use - /// The payload for the event - public static void WriteEvent(this IEventProvider provider, int eventId, object[] payload = null) - { - provider.WriteEvent(new EventDescriptor(eventId), payload); - } - - /// - /// Writes an event in the specified provider. - /// - /// The event provider to use - /// The event ID to use - /// The opcode for the event - /// The payload for the event - public static void WriteEvent(this IEventProvider provider, int eventId, EventOpcode opCode, object[] payload = null) - { - provider.WriteEvent(new EventDescriptor(eventId: eventId, opcode: opCode), payload); - } - - /// - /// Write a single activity event, to be used with the stopping opcode later on. - /// - /// The event provider to use - /// The event ID to write - /// The opcode of the event - /// An optional payload - /// An activity identifier, to be used as a relatedActivityId, or activity id for the stopping event. - public static EventActivity WriteEventActivity(this IEventProvider provider, int eventId, EventOpcode opCode, object[] payload = null) - { - var activity = CreateEventActivity(); - - provider.WriteEvent(new EventDescriptor(eventId: eventId, opcode: opCode, activityId: activity?.Id ?? 0), payload); - - return activity; - } - - /// - /// Write a single activity event, to be used with the stopping opcode later on. - /// - /// The event provider to use - /// The event ID to write - /// The opcode of the event - /// The current activity - /// An optional payload - /// An activity identifier, to be used as a relatedActivityId, or activity id for the stopping event. - public static void WriteEventActivity(this IEventProvider provider, int eventId, EventOpcode opCode, EventActivity activity, object[] payload = null) - { - provider.WriteEvent(new EventDescriptor(eventId: eventId, opcode: opCode, activityId: activity?.Id ?? 0), payload); - } - - /// - /// Writes an activity event, used to correlate start and stop events properly. - /// - /// The event provider to use - /// The starting event ID to write - /// The stopping event ID to write - /// The activity to be disposed when stopped - public static DisposableEventActivity WriteEventActivity(this IEventProvider provider, int startEventId, int stopEventId) - { - if (provider.IsEnabled) - { - var activity = CreateEventActivity(); - - provider.WriteEvent( - new EventDescriptor( - eventId: startEventId, - opcode: EventOpcode.Start, - activityId: activity?.Id ?? 0 - ) - ); - - return new DisposableEventActivity( - activity, - () => provider.WriteEvent( - new EventDescriptor( - eventId: stopEventId, - opcode: EventOpcode.Stop, - activityId: activity?.Id ?? 0 - ) - ) - ); - } - else - { - // the using statement handles null disposable properly. - return null; - } - } - - /// - /// Writes an activity event, used to correlate start and stop events properly. - /// - /// The event provider to use - /// The starting event ID to write - /// The stopping event ID to write - /// The payload for this event - /// The activity to be disposed when stopped - public static DisposableEventActivity WriteEventActivity(this IEventProvider provider, int startEventId, int stopEventId, object[] payload = null) - { - if (provider.IsEnabled) - { - var activity = CreateEventActivity(); - - provider.WriteEvent( - new EventDescriptor( - eventId: startEventId, - opcode: EventOpcode.Start, - activityId: activity?.Id ?? 0 - ), - payload - ); - - return new DisposableEventActivity( - activity, - () => provider.WriteEvent( - new EventDescriptor( - eventId: stopEventId, - opcode: EventOpcode.Stop, - activityId: activity?.Id ?? 0 - ), - payload - ) - ); - } - else - { - // the using statement handles null disposable properly. - return null; - } - } - - /// - /// Writes an activity event, used to correlate start and stop events properly, with the ability to provide a related activity. - /// - /// The event provider to use - /// The starting event ID to write - /// The stopping event ID to write - /// The new activity will be marked with this related activity. - /// The payload for this event - /// The activity to be disposed when stopped - public static DisposableEventActivity WriteEventActivity( - this IEventProvider provider, - int startEventId, - int stopEventId, - EventActivity relatedActivity, - object[] payload = null - ) - { - if (provider.IsEnabled) - { - var activity = CreateEventActivity(); - - provider.WriteEvent( - new EventDescriptor( - eventId: startEventId, - opcode: EventOpcode.Start, - activityId: activity?.Id ?? 0, - relatedActivityId: relatedActivity?.Id ?? 0 - ), - payload - ); - - return new DisposableEventActivity( - activity, - () => provider.WriteEvent( - new EventDescriptor( - eventId: stopEventId, - opcode: EventOpcode.Stop, - activityId: activity?.Id ?? 0, - relatedActivityId: relatedActivity?.Id ?? 0 - ), - payload - ) - ); - } - else - { - // the using statement handles null disposable properly. - return null; - } - } - - private static EventActivity CreateEventActivity() - { - return new EventActivity(Interlocked.Increment(ref _activityCounter)); - } - - /// - /// A EventActivity identifier. - /// - public class DisposableEventActivity : IDisposable - { - private Action _disposable; - - public DisposableEventActivity(EventActivity eventActivity, Action disposable) - { - _disposable = disposable; - EventActivity = eventActivity; - } - - public EventActivity EventActivity { get; } - - public void Dispose() - { - _disposable(); - } - } - } -} diff --git a/src/Uno.Foundation/Eventing/IEventProvider.cs b/src/Uno.Foundation/Eventing/IEventProvider.cs deleted file mode 100644 index ab46c55ffda6..000000000000 --- a/src/Uno.Foundation/Eventing/IEventProvider.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Uno.Diagnostics.Eventing -{ - /// - /// An event provider that sends event to the tracing subsystem - /// - public interface IEventProvider - { - /// - /// Defines if the provider is enabled. - /// - bool IsEnabled { get; } - - /// - /// Writes a string message to the provider - /// - /// The string to write - /// True if the write succeeded, otherwise false. - bool WriteMessageEvent(string eventMessage); - - /// - /// Writes a full event descriptor with a message to the provider - /// - /// An event descriptor - /// A string to add as payload - /// True if the write succeeded, otherwise false. - bool WriteEvent(EventDescriptor eventDescriptor, string data); - - /// - /// Writes a full event descriptor with an array of objects to the provider - /// - /// An event descriptor - /// A string to add as payload - /// True if the write succeeded, otherwise false. - /// Data can be of Int32, Int64 or String. - bool WriteEvent(EventDescriptor eventDescriptor, params object[] data); - } -} diff --git a/src/Uno.Foundation/Eventing/IEventProviderFactory.cs b/src/Uno.Foundation/Eventing/IEventProviderFactory.cs deleted file mode 100644 index cddc458a3ec1..000000000000 --- a/src/Uno.Foundation/Eventing/IEventProviderFactory.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace Uno.Diagnostics.Eventing -{ - /// - /// Defines a factory of EventProviders - /// - public interface IEventProviderFactory - { - /// - /// Gets a event provider. - /// - /// The ID of the event provider - /// An event provider - IEventProvider GetProvider(Guid provider); - } -} \ No newline at end of file diff --git a/src/Uno.Foundation/Eventing/NullEventProvider.cs b/src/Uno.Foundation/Eventing/NullEventProvider.cs deleted file mode 100644 index 9c1defceecf9..000000000000 --- a/src/Uno.Foundation/Eventing/NullEventProvider.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; - -namespace Uno.Diagnostics.Eventing -{ - /// - /// Defines a disabled provider - /// - public class NullEventProvider : IEventProvider - { - public static IEventProvider Instance { get; } = new NullEventProvider(); - - bool IEventProvider.IsEnabled { get; } = false; - - bool IEventProvider.WriteMessageEvent(string eventMessage) - { - return false; - } - - bool IEventProvider.WriteEvent(EventDescriptor eventDescriptor, object[] data) - { - return false; - } - - bool IEventProvider.WriteEvent(EventDescriptor eventDescriptor, string data) - { - return false; - } - } -} \ No newline at end of file diff --git a/src/Uno.Foundation/Eventing/Tracing.cs b/src/Uno.Foundation/Eventing/Tracing.cs deleted file mode 100644 index eef94d6caab9..000000000000 --- a/src/Uno.Foundation/Eventing/Tracing.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Uno.Diagnostics.Eventing -{ - /// - /// A common entry point for all event tracing APIs - /// - public static class Tracing - { - /// - /// Provides the current EventProvider factory. - /// - public static IEventProviderFactory Factory { get; set; } - - /// - /// Provides the enabled state for the whole tracing subsystem. - /// - public static bool IsEnabled { get; set; } - - /// - /// Gets an event provider for the specified ID - /// - /// The ID of the provider - /// An event provider - public static IEventProvider Get(Guid provider) - { - if(Factory != null && IsEnabled) - { - return Factory.GetProvider(provider); - } - else - { - return NullEventProvider.Instance; - } - } - } -} diff --git a/src/Uno.Foundation/Extensions/RectExtensions.cs b/src/Uno.Foundation/Extensions/RectExtensions.cs new file mode 100644 index 000000000000..c36099b31e64 --- /dev/null +++ b/src/Uno.Foundation/Extensions/RectExtensions.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Windows.Foundation +{ + internal static class RectExtensions + { + internal static double GetMidX(this Rect rect) + => rect.Left + ((rect.Right - rect.Left) / 2); + + internal static double GetMidY(this Rect rect) + => rect.Top + ((rect.Bottom - rect.Top) / 2); + } +} diff --git a/src/Uno.Foundation/LinkerDefinition.Wasm.xml b/src/Uno.Foundation/LinkerDefinition.Wasm.xml deleted file mode 100644 index cffb3e689361..000000000000 --- a/src/Uno.Foundation/LinkerDefinition.Wasm.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/src/Uno.Foundation/NotImplementedAttribute.cs b/src/Uno.Foundation/NotImplementedAttribute.cs index e0d0c63196e4..288adf9c9c06 100644 --- a/src/Uno.Foundation/NotImplementedAttribute.cs +++ b/src/Uno.Foundation/NotImplementedAttribute.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using System.Collections.Generic; using System.Text; @@ -7,6 +8,13 @@ namespace Uno [System.AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = false)] public sealed class NotImplementedAttribute : Attribute { - + public NotImplementedAttribute() { } + + public NotImplementedAttribute(params string[] platforms) + { + Platforms = platforms; + } + + public string[]? Platforms { get; } } } diff --git a/src/Uno.Foundation/Uno.Foundation.csproj b/src/Uno.Foundation/Uno.Foundation.csproj index a63ec117fd6b..93ef2040b7be 100644 --- a/src/Uno.Foundation/Uno.Foundation.csproj +++ b/src/Uno.Foundation/Uno.Foundation.csproj @@ -16,12 +16,15 @@ false true + + Reference + @@ -40,12 +43,10 @@ - - - $(AssemblyName).xml - - - + + + + diff --git a/src/Uno.ReferenceImplComparer/Program.cs b/src/Uno.ReferenceImplComparer/Program.cs new file mode 100644 index 000000000000..45407a8553ad --- /dev/null +++ b/src/Uno.ReferenceImplComparer/Program.cs @@ -0,0 +1,124 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Transactions; +using Mono.Cecil; +using Mono.Collections.Generic; + +namespace Uno.ReferenceImplComparer +{ + class Program + { + static int Main(string[] args) + { + var hasErrors = false; + var filePath = UnpackArchive(args[0]); + + Console.WriteLine($"Validating package {args[0]}"); + + foreach(var assembly in Directory.GetFiles(Path.Combine(filePath, "lib", "netstandard2.0"), "*.dll")) + { + var referenceAssemblyDefinition = ReadAssemblyDefinition(assembly); + + foreach(var runtimeAssembly in Directory.GetFiles(Path.Combine(filePath, "uno-runtime"), Path.GetFileName(assembly), SearchOption.AllDirectories)) + { + var identifier = $"{Path.GetFileName(runtimeAssembly)}/{Path.GetFileName(Path.GetDirectoryName(runtimeAssembly))}"; + Console.WriteLine($"Validating {identifier}"); + + var runtimeAssemblyDefinition = ReadAssemblyDefinition(runtimeAssembly); + + hasErrors |= CompareAssemblies(referenceAssemblyDefinition, runtimeAssemblyDefinition, identifier); + } + } + + return hasErrors ? 1 : 0; + } + + private static bool CompareAssemblies(AssemblyDefinition referenceAssemby, AssemblyDefinition runtimeAssembly, string identifier) + { + var hasError = false; + var referenceTypes = referenceAssemby.MainModule.GetTypes(); + var runtimeTypes = runtimeAssembly.MainModule.GetTypes().ToDictionary(t => t.FullName); + + foreach(var referenceType in referenceTypes.Where(t => t.IsPublic)) + { + if(referenceType.FullName == "Windows.UI.Xaml.Documents.TextElement") + { + Console.WriteLine("Skipping Windows.UI.Xaml.Documents.TextElement comparison"); + continue; + } + + if(runtimeTypes.TryGetValue(referenceType.FullName, out var runtimeType)) + { + if(referenceType.BaseType?.FullName != runtimeType.BaseType?.FullName) + { + Console.WriteLine($"{referenceType.FullName} base type is different {referenceType.BaseType?.FullName} in reference, {runtimeType.BaseType?.FullName} in {identifier}"); + hasError = true; + } + + hasError |= CompareMembers(referenceType.Methods.Where(m => m.IsPublic), runtimeType.Methods, identifier); + hasError |= CompareMembers(referenceType.Properties.Where(m => m.GetMethod?.IsPublic ?? false), runtimeType.Properties, identifier); + hasError |= CompareMembers(referenceType.Fields.Where(m => m.IsPublic), runtimeType.Fields, identifier); + hasError |= CompareMembers(referenceType.Events.Where(m => m.AddMethod?.IsPublic ?? false), runtimeType.Events, identifier); + } + else + { + hasError = true; + Console.WriteLine($"The type {referenceType} is missing from "); + } + } + + return hasError; + } + + private static bool CompareMembers(IEnumerable referenceMembers, IEnumerable runtimeMembers, string identifier) + { + var hasError = false; + var runtimeMembersLookup = runtimeMembers.ToDictionary(m => m.ToString()); + + foreach(var referenceMember in referenceMembers) + { + if (!runtimeMembersLookup.ContainsKey(referenceMember.ToString())) + { + Console.WriteLine($"The member {referenceMember} cannot be found in {identifier}"); + hasError = true; + } + } + + return hasError; + } + + private static AssemblyDefinition ReadAssemblyDefinition(string assemblyPath) + => AssemblyDefinition.ReadAssembly(assemblyPath, new ReaderParameters() { AssemblyResolver = new DefaultAssemblyResolver() }); + + private static string UnpackArchive(string packagePath) + { + var path = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString().Trim('{', '}')); + + Directory.CreateDirectory(path); + + Console.WriteLine($"Extracting {packagePath} -> {path}"); + using (var file = File.OpenRead(packagePath)) + { + using (var archive = new ZipArchive(file, ZipArchiveMode.Read)) + { + archive.ExtractToDirectory(path); + } + } + + if (Directory.GetFiles(path, "*.nuspec", SearchOption.AllDirectories).FirstOrDefault() is string nuspecFile) + { + return path; + } + else + { + throw new InvalidOperationException($"Unable to find nuspec file in {packagePath}"); + } + } + + } +} diff --git a/src/Uno.ReferenceImplComparer/Properties/launchSettings.json b/src/Uno.ReferenceImplComparer/Properties/launchSettings.json new file mode 100644 index 000000000000..d93d473c14fe --- /dev/null +++ b/src/Uno.ReferenceImplComparer/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "Uno.ReferenceImplComparer": { + "commandName": "Project", + "commandLineArgs": "\"C:\\Temp\\nuget-local\\Uno.UI.3.0.0-dev.wasm-separation.682.nupkg\"" + } + } +} \ No newline at end of file diff --git a/src/Uno.ReferenceImplComparer/Uno.ReferenceImplComparer.csproj b/src/Uno.ReferenceImplComparer/Uno.ReferenceImplComparer.csproj new file mode 100644 index 000000000000..0601713861eb --- /dev/null +++ b/src/Uno.ReferenceImplComparer/Uno.ReferenceImplComparer.csproj @@ -0,0 +1,13 @@ + + + + Exe + netcoreapp3.1 + false + + + + + + + diff --git a/src/Uno.UI-Skia-only.slnf b/src/Uno.UI-Skia-only.slnf new file mode 100644 index 000000000000..5faddc6b6b25 --- /dev/null +++ b/src/Uno.UI-Skia-only.slnf @@ -0,0 +1,43 @@ +{ + "solution": { + "path": "Uno.UI.sln", + "projects": [ + "AddIns\\Uno.UI.Lottie.Skia\\Uno.UI.Lottie.Skia.csproj", + "AddIns\\Uno.UI.Lottie\\Uno.UI.Lottie.csproj", + "AddIns\\Uno.UI.MSAL.Skia\\Uno.UI.MSAL.Skia.csproj", + "AddIns\\Uno.UI.MSAL\\Uno.UI.MSAL.csproj", + "SamplesApp\\Benchmarks.Shared\\SamplesApp.Benchmarks.shproj", + "SamplesApp\\SamplesApp.Shared\\SamplesApp.Shared.shproj", + "SamplesApp\\SamplesApp.Skia.Gtk\\SamplesApp.Skia.Gtk.csproj", + "SamplesApp\\SamplesApp.Skia.WPF\\SamplesApp.Skia.WPF.csproj", + "SamplesApp\\SamplesApp.Skia\\SamplesApp.Skia.csproj", + "SamplesApp\\SamplesApp.UITests.Generator\\Uno.Samples.UITest.Generator.csproj", + "SamplesApp\\SamplesApp.UITests\\SamplesApp.UITests.csproj", + "SamplesApp\\SamplesApp.UWP.Design\\SamplesApp.UWP.Design.csproj", + "SamplesApp\\SamplesApp.UnitTests.Shared\\SamplesApp.UnitTests.Shared.shproj", + "SamplesApp\\UITests.Shared\\UITests.Shared.shproj", + "SolutionTemplate\\Uno.ProjectTemplates.Dotnet\\Uno.ProjectTemplates.Dotnet.csproj", + "SourceGenerators\\System.Xaml\\Uno.Xaml.csproj", + "SourceGenerators\\Uno.UI.SourceGenerators\\Uno.UI.SourceGenerators.csproj", + "SourceGenerators\\Uno.UI.Tasks\\Uno.UI.Tasks.csproj", + "T4Generator\\T4Generator.csproj", + "Uno.Foundation.Skia\\Uno.Foundation.Skia.csproj", + "Uno.Foundation\\Uno.Foundation.csproj", + "Uno.UI.BindingHelper.Android\\Uno.UI.BindingHelper.Android.csproj", + "Uno.UI.RemoteControl\\Uno.UI.RemoteControl.csproj", + "Uno.UI.Runtime.Skia.Gtk\\Uno.UI.Runtime.Skia.Gtk.csproj", + "Uno.UI.Runtime.Skia.Wpf\\Uno.UI.Runtime.Skia.Wpf.csproj", + "Uno.UI.RuntimeTests.Skia\\Uno.UI.RuntimeTests.Skia.csproj", + "Uno.UI.RuntimeTests\\Uno.UI.RuntimeTests.csproj", + "Uno.UI.Skia\\Uno.UI.Skia.csproj", + "Uno.UI.TestComparer\\Uno.UI.TestComparer.csproj", + "Uno.UI.Toolkit.Skia\\Uno.UI.Toolkit.Skia.csproj", + "Uno.UI.Toolkit\\Uno.UI.Toolkit.csproj", + "Uno.UI\\Uno.UI.csproj", + "Uno.UWP.Skia\\Uno.Skia.csproj", + "Uno.UWPSyncGenerator.Reference\\Uno.UWPSyncGenerator.Reference.csproj", + "Uno.UWPSyncGenerator\\Uno.UWPSyncGenerator.csproj", + "Uno.UWP\\Uno.csproj" + ] + } +} \ No newline at end of file diff --git a/src/Uno.UI-Wasm-only.slnf b/src/Uno.UI-Wasm-only.slnf index e38450926db0..f94e8cf0f912 100644 --- a/src/Uno.UI-Wasm-only.slnf +++ b/src/Uno.UI-Wasm-only.slnf @@ -2,7 +2,10 @@ "solution": { "path": "Uno.UI.sln", "projects": [ + "..\\build\\Uno.UI.Build.csproj", + "AddIns\\Uno.UI.Lottie.Wasm\\Uno.UI.Lottie.Wasm.csproj", "AddIns\\Uno.UI.Lottie\\Uno.UI.Lottie.csproj", + "AddIns\\Uno.UI.MSAL.Wasm\\Uno.UI.MSAL.Wasm.csproj", "AddIns\\Uno.UI.MSAL\\Uno.UI.MSAL.csproj", "SamplesApp\\Benchmarks.Shared\\SamplesApp.Benchmarks.shproj", "SamplesApp\\SamplesApp.Shared\\SamplesApp.Shared.shproj", @@ -17,15 +20,24 @@ "SourceGenerators\\Uno.UI.SourceGenerators\\Uno.UI.SourceGenerators.csproj", "SourceGenerators\\Uno.UI.Tasks\\Uno.UI.Tasks.csproj", "T4Generator\\T4Generator.csproj", + "Uno.Foundation.Runtime.Wasm\\Uno.Foundation.Runtime.Wasm.csproj", + "Uno.Foundation.Wasm\\Uno.Foundation.Wasm.csproj", "Uno.Foundation\\Uno.Foundation.csproj", "Uno.UI.BindingHelper.Android\\Uno.UI.BindingHelper.Android.csproj", + "Uno.UI.RemoteControl.Wasm\\Uno.UI.RemoteControl.Wasm.csproj", "Uno.UI.RemoteControl\\Uno.UI.RemoteControl.csproj", + "Uno.UI.Runtime.Wasm\\Uno.UI.Runtime.Wasm.csproj", + "Uno.UI.RuntimeTests.Wasm\\Uno.UI.RuntimeTests.Wasm.csproj", "Uno.UI.RuntimeTests\\Uno.UI.RuntimeTests.csproj", "Uno.UI.TestComparer\\Uno.UI.TestComparer.csproj", + "Uno.UI.Toolkit.Wasm\\Uno.UI.Toolkit.Wasm.csproj", "Uno.UI.Toolkit\\Uno.UI.Toolkit.csproj", "Uno.UI.Wasm.Tests\\Uno.UI.Wasm.Tests.csproj", "Uno.UI.Wasm\\Uno.UI.Wasm.csproj", "Uno.UI\\Uno.UI.csproj", + "Uno.UWP.Wasm\\Uno.Wasm.csproj", + "Uno.UWPSyncGenerator.Reference\\Uno.UWPSyncGenerator.Reference.csproj", + "Uno.UWPSyncGenerator\\Uno.UWPSyncGenerator.csproj", "Uno.UWP\\Uno.csproj" ] } diff --git a/src/Uno.UI.RemoteControl/LinkerDefinition.Wasm.xml b/src/Uno.UI.RemoteControl.Skia/LinkerDefinition.Wasm.xml similarity index 100% rename from src/Uno.UI.RemoteControl/LinkerDefinition.Wasm.xml rename to src/Uno.UI.RemoteControl.Skia/LinkerDefinition.Wasm.xml diff --git a/src/Uno.UI.RemoteControl.Skia/Uno.UI.RemoteControl.Skia.csproj b/src/Uno.UI.RemoteControl.Skia/Uno.UI.RemoteControl.Skia.csproj new file mode 100644 index 000000000000..ee940d769dd0 --- /dev/null +++ b/src/Uno.UI.RemoteControl.Skia/Uno.UI.RemoteControl.Skia.csproj @@ -0,0 +1,88 @@ + + + + netstandard2.0 + + + + true + + True + obj\$(TargetFramework)\Resources\Resource.Designer.cs + + + true + + $(NoWarn);NU1701 + + Uno.UI.RemoteControl + Uno.UI.RemoteControl + + false + true + + Skia + ..\Uno.UI.RemoteControl\ + + Uno.WinUI.RemoteControl + + + + + + + + + + + $(AssemblyName).xml + + + + + + + + + + + + + + + + + false + true + TargetFramework + + + + + + false + true + TargetFramework + + + + + + + + + <_OverrideTargetFramework>$(TargetFramework) + <_TargetNugetFolder>$(USERPROFILE)\.nuget\packages\Uno.UI.RemoteControl\$(UnoNugetOverrideVersion)\uno-runtime\$(UnoRuntimeIdentifier.ToLowerInvariant()) + + + <_OutputFiles Include="$(TargetDir)**" /> + + + + + + + + + + diff --git a/src/Uno.UI.RemoteControl.Wasm/LinkerDefinition.Wasm.xml b/src/Uno.UI.RemoteControl.Wasm/LinkerDefinition.Wasm.xml new file mode 100644 index 000000000000..be369875a5fe --- /dev/null +++ b/src/Uno.UI.RemoteControl.Wasm/LinkerDefinition.Wasm.xml @@ -0,0 +1,4 @@ + + + + diff --git a/src/Uno.UI.RemoteControl.Wasm/Uno.UI.RemoteControl.Wasm.csproj b/src/Uno.UI.RemoteControl.Wasm/Uno.UI.RemoteControl.Wasm.csproj new file mode 100644 index 000000000000..8b9dd2c8b9e6 --- /dev/null +++ b/src/Uno.UI.RemoteControl.Wasm/Uno.UI.RemoteControl.Wasm.csproj @@ -0,0 +1,92 @@ + + + + netstandard2.0 + + + + true + + True + obj\$(TargetFramework)\Resources\Resource.Designer.cs + + + true + + $(NoWarn);NU1701 + + Uno.UI.RemoteControl + Uno.UI.RemoteControl + + false + true + + WebAssembly + ..\Uno.UI.RemoteControl\ + + Uno.WinUI.RemoteControl + + + + + + + + + + + $(AssemblyName).xml + + + + + + + + + + + + + + + + + + + + + false + true + TargetFramework + + + + + + false + true + TargetFramework + + + + + + + + + <_OverrideTargetFramework>$(TargetFramework) + <_TargetNugetFolder>$(USERPROFILE)\.nuget\packages\Uno.UI.RemoteControl\$(UnoNugetOverrideVersion)\uno-runtime\$(UnoRuntimeIdentifier.ToLowerInvariant()) + + + <_OutputFiles Include="$(TargetDir)**" /> + + + + + + + + + + diff --git a/src/Uno.UI.RemoteControl/Uno.UI.RemoteControl.csproj b/src/Uno.UI.RemoteControl/Uno.UI.RemoteControl.csproj index 285b01617de5..6f32bad0aa48 100644 --- a/src/Uno.UI.RemoteControl/Uno.UI.RemoteControl.csproj +++ b/src/Uno.UI.RemoteControl/Uno.UI.RemoteControl.csproj @@ -32,18 +32,16 @@ - - - $(AssemblyName).xml - - - $(AssemblyName).xml + + + + @@ -60,6 +58,13 @@ + + + build + true + + + diff --git a/src/Uno.UI.RemoteControl/buildTransitive/Uno.UI.RemoteControl.targets b/src/Uno.UI.RemoteControl/buildTransitive/Uno.UI.RemoteControl.targets new file mode 100644 index 000000000000..b77e484f0ff2 --- /dev/null +++ b/src/Uno.UI.RemoteControl/buildTransitive/Uno.UI.RemoteControl.targets @@ -0,0 +1,16 @@ + + + + + + + <_ItemsFromUnoToRemove Include="@(RuntimeCopyLocalItems)" Condition="'%(RuntimeCopyLocalItems.NuGetPackageId)'=='Uno.UI.RemoteControl' or '%(RuntimeCopyLocalItems.NuGetPackageId)'=='Uno.WinUI.RemoteControl'" /> + + + + + + + diff --git a/src/Uno.UI.Runtime.Skia.Gtk/GTK/GtkCoreWindowExtension.cs b/src/Uno.UI.Runtime.Skia.Gtk/GTK/GtkCoreWindowExtension.cs new file mode 100644 index 000000000000..ed6443c60fc2 --- /dev/null +++ b/src/Uno.UI.Runtime.Skia.Gtk/GTK/GtkCoreWindowExtension.cs @@ -0,0 +1,230 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Gdk; +using Gtk; +using Uno.Extensions; +using Uno.Foundation.Extensibility; +using Uno.Logging; +using Uno.UI.Runtime.Skia; +using Windows.Devices.Input; +using Windows.Foundation; +using Windows.UI.Composition; +using Windows.UI.Core; +using Windows.UI.Input; + +namespace Uno.UI.Runtime.Skia +{ + public class GtkUIElementPointersSupport : ICoreWindowExtension + { + private readonly CoreWindow _owner; + private ICoreWindowEvents _ownerEvents; + + public GtkUIElementPointersSupport(object owner) + { + _owner = (CoreWindow)owner; + _ownerEvents = (ICoreWindowEvents)owner; + + GtkHost.Window.AddEvents((int)( + Gdk.EventMask.PointerMotionMask + | EventMask.ButtonPressMask + | EventMask.ScrollMask + | EventMask.SmoothScrollMask + )); + GtkHost.Window.MotionNotifyEvent += OnMotionEvent; + GtkHost.Window.ButtonPressEvent += Window_ButtonPressEvent; + GtkHost.Window.ButtonReleaseEvent += Window_ButtonReleaseEvent; + GtkHost.Window.EnterNotifyEvent += Window_EnterEvent; + GtkHost.Window.LeaveNotifyEvent += Window_LeaveEvent; + GtkHost.Window.ScrollEvent += Window_ScrollEvent; + } + private void Window_ScrollEvent(object o, ScrollEventArgs args) + { + try + { + _ownerEvents.RaisePointerWheelChanged( + new PointerEventArgs( + new Windows.UI.Input.PointerPoint( + frameId: 0, + timestamp: args.Event.Time, + device: PointerDevice.For(PointerDeviceType.Mouse), + pointerId: 0, + rawPosition: new Windows.Foundation.Point(args.Event.X, args.Event.Y), + position: new Windows.Foundation.Point(args.Event.X, args.Event.Y), + isInContact: false, + properties: BuildProperties(args.Event) + ) + ) + ); + } + catch (Exception e) + { + this.Log().Error("Failed to raise PointerExited", e); + } + } + + private PointerPointProperties BuildProperties(EventScroll scrollEvent) + => new PointerPointProperties + { + MouseWheelDelta = scrollEvent.DeltaX != 0 ? (int)scrollEvent.DeltaX : (int)scrollEvent.DeltaY, + IsHorizontalMouseWheel = scrollEvent.DeltaX != 0, + }; + + private void Window_LeaveEvent(object o, LeaveNotifyEventArgs args) + { + try + { + _ownerEvents.RaisePointerExited( + new PointerEventArgs( + new Windows.UI.Input.PointerPoint( + frameId: 0, + timestamp: args.Event.Time, + device: PointerDevice.For(PointerDeviceType.Mouse), + pointerId: 0, + rawPosition: new Windows.Foundation.Point(args.Event.X, args.Event.Y), + position: new Windows.Foundation.Point(args.Event.X, args.Event.Y), + isInContact: false, + properties: BuildProperties(args.Event) + ) + ) + ); + } + catch(Exception e) + { + this.Log().Error("Failed to raise PointerExited", e); + } + } + + private void Window_EnterEvent(object o, EnterNotifyEventArgs args) + { + try + { + _ownerEvents.RaisePointerEntered( + new PointerEventArgs( + new Windows.UI.Input.PointerPoint( + frameId: 0, + timestamp: args.Event.Time, + device: PointerDevice.For(PointerDeviceType.Mouse), + pointerId: 0, + rawPosition: new Windows.Foundation.Point(args.Event.X, args.Event.Y), + position: new Windows.Foundation.Point(args.Event.X, args.Event.Y), + isInContact: false, + properties: BuildProperties(args.Event) + ) + ) + ); + } + catch (Exception e) + { + this.Log().Error("Failed to raise PointerEntered", e); + } + } + + private void Window_ButtonReleaseEvent(object o, ButtonReleaseEventArgs args) + { + try + { + _ownerEvents.RaisePointerReleased( + new PointerEventArgs( + new Windows.UI.Input.PointerPoint( + frameId: 0, + timestamp: args.Event.Time, + device: PointerDevice.For(PointerDeviceType.Mouse), + pointerId: 0, + rawPosition: new Windows.Foundation.Point(args.Event.X, args.Event.Y), + position: new Windows.Foundation.Point(args.Event.X, args.Event.Y), + isInContact: false, + properties: BuildProperties(args.Event) + ) + ) + ); + } + catch (Exception e) + { + this.Log().Error("Failed to raise PointerReleased", e); + } + } + + private void Window_ButtonPressEvent(object o, ButtonPressEventArgs args) + { + try + { + _ownerEvents.RaisePointerPressed( + new PointerEventArgs( + new Windows.UI.Input.PointerPoint( + frameId: 0, + timestamp: args.Event.Time, + device: PointerDevice.For(PointerDeviceType.Mouse), + pointerId: 0, + rawPosition: new Windows.Foundation.Point(args.Event.X, args.Event.Y), + position: new Windows.Foundation.Point(args.Event.X, args.Event.Y), + isInContact: false, + properties: BuildProperties(args.Event) + ) + ) + ); + } + catch (Exception e) + { + this.Log().Error("Failed to raise PointerPressed", e); + } + } + + private PointerPointProperties BuildProperties(EventButton eventButton) + => new PointerPointProperties + { + IsLeftButtonPressed = eventButton.Button == 1, + IsRightButtonPressed = eventButton.Button == 3, + }; + + private PointerPointProperties BuildProperties(EventCrossing eventCrossing) + => new PointerPointProperties + { + IsLeftButtonPressed = (eventCrossing.State & ModifierType.Button1Mask) != 0, + IsRightButtonPressed = (eventCrossing.State & ModifierType.Button4Mask) != 0, + }; + + private void OnMotionEvent(object o, MotionNotifyEventArgs args) + { + try + { + switch (args.Event.Type) + { + case Gdk.EventType.MotionNotify: + _ownerEvents.RaisePointerMoved( + new PointerEventArgs( + new Windows.UI.Input.PointerPoint( + frameId: 0, + timestamp: args.Event.Time, + device: PointerDevice.For(PointerDeviceType.Mouse), + pointerId: 0, + rawPosition: new Windows.Foundation.Point(args.Event.X, args.Event.Y), + position: new Windows.Foundation.Point(args.Event.X, args.Event.Y), + isInContact: false, + properties: BuildProperties(args.Event) + ) + ) + ); + break; + + default: + Console.WriteLine($"Unknown event: {args.Event.State}"); + break; + } + } + catch (Exception e) + { + this.Log().Error("Failed to raise PointerMoved", e); + } + } + + private PointerPointProperties BuildProperties(EventMotion eventMotion) + => new Windows.UI.Input.PointerPointProperties() + { + IsLeftButtonPressed = (eventMotion.State & Gdk.ModifierType.Button1Mask) != 0, + IsRightButtonPressed = (eventMotion.State & Gdk.ModifierType.Button2Mask) != 0 + }; + } +} diff --git a/src/Uno.UI.Runtime.Skia.Gtk/GTK/GtkHost.cs b/src/Uno.UI.Runtime.Skia.Gtk/GTK/GtkHost.cs new file mode 100644 index 000000000000..b8e47613d3e2 --- /dev/null +++ b/src/Uno.UI.Runtime.Skia.Gtk/GTK/GtkHost.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Uno.Foundation.Extensibility; +using Windows.UI.Xaml; +using WUX = Windows.UI.Xaml; + +namespace Uno.UI.Runtime.Skia +{ + public class GtkHost + { + private Func _appBuilder; + private static Gtk.Window _window; + + public static Gtk.Window Window => _window; + + public GtkHost(Func appBuilder, string[] args) + { + _appBuilder = appBuilder; + } + + public void Run() + { + Gtk.Application.Init(); + + ApiExtensibility.Register(typeof(Windows.UI.Core.ICoreWindowExtension), o => new GtkUIElementPointersSupport(o)); + + _window = new Gtk.Window("Uno Host"); + _window.SetDefaultSize(1024, 800); + _window.SetPosition(Gtk.WindowPosition.Center); + + _window.DeleteEvent += delegate + { + Gtk.Application.Quit(); + }; + + Windows.UI.Core.CoreDispatcher.DispatchOverride + = d => + { + if (Gtk.Application.EventsPending()) + { + Gtk.Application.RunIteration(false); + } + + GLib.Idle.Add(delegate + { + Console.WriteLine("iteration"); + try + { + d(); + } + catch (Exception e) + { + Console.WriteLine(e); + } + return false; + }); + }; + + _window.Realized += (s, e) => + { + WUX.Window.Current.OnNativeSizeChanged(new Windows.Foundation.Size(_window.AllocatedWidth, _window.AllocatedHeight)); + }; + + _window.SizeAllocated += (s, e) => + { + WUX.Window.Current.OnNativeSizeChanged(new Windows.Foundation.Size(e.Allocation.Width, e.Allocation.Height)); + }; + + var area = new UnoDrawingArea(); + _window.Add(area); + + /* avoids double invokes at window level */ + area.AddEvents((int)( + Gdk.EventMask.PointerMotionMask + | Gdk.EventMask.ButtonPressMask + | Gdk.EventMask.ButtonReleaseMask + )); + + _window.ShowAll(); + + WUX.Application.Start(_ => _appBuilder()); + + Gtk.Application.Run(); + } + } +} diff --git a/src/Uno.UI.Runtime.Skia.Gtk/GTK/UnoDrawingArea.cs b/src/Uno.UI.Runtime.Skia.Gtk/GTK/UnoDrawingArea.cs new file mode 100644 index 000000000000..d701e8c7b9a8 --- /dev/null +++ b/src/Uno.UI.Runtime.Skia.Gtk/GTK/UnoDrawingArea.cs @@ -0,0 +1,60 @@ +using System; +using SkiaSharp; +using WUX = Windows.UI.Xaml; + +namespace Uno.UI.Runtime.Skia +{ + internal class UnoDrawingArea : Gtk.DrawingArea + { + private SKBitmap bitmap; + private int renderCount; + private int InvalidateRenderCount; + + public UnoDrawingArea() + { + WUX.Window.Current.InvalidateRender + += () => + { + QueueDrawArea(0, 0, 10000, 1000); + }; + } + + protected override bool OnDrawn(Cairo.Context cr) + { + int width, height; + + Console.WriteLine($"Render {renderCount++}"); + + width = (int)AllocatedWidth; + height = (int)AllocatedHeight; + + var info = new SKImageInfo(width, height, SKImageInfo.PlatformColorType, SKAlphaType.Premul); + + // reset the bitmap if the size has changed + if (bitmap == null || info.Width != bitmap.Width || info.Height != bitmap.Height) + { + bitmap = new SKBitmap(width, height, SKColorType.Rgba8888, SKAlphaType.Premul); + } + + using (var surface = SKSurface.Create(info, bitmap.GetPixels(out var len))) + { + surface.Canvas.Clear(SKColors.White); + + WUX.Window.Current.Compositor.Render(surface, info); + + using (var gtkSurface = new Cairo.ImageSurface( + bitmap.GetPixels(out _), + Cairo.Format.Argb32, + bitmap.Width, bitmap.Height, + bitmap.Width * 4)) + { + gtkSurface.MarkDirty(); + cr.SetSourceSurface(gtkSurface, 0, 0); + cr.Paint(); + } + } + + return true; + } + } +} diff --git a/src/Uno.UI.Runtime.Skia.Gtk/Uno.UI.Runtime.Skia.Gtk.csproj b/src/Uno.UI.Runtime.Skia.Gtk/Uno.UI.Runtime.Skia.Gtk.csproj new file mode 100644 index 000000000000..b92db524c044 --- /dev/null +++ b/src/Uno.UI.Runtime.Skia.Gtk/Uno.UI.Runtime.Skia.Gtk.csproj @@ -0,0 +1,49 @@ + + + + netcoreapp3.1 + + + + true + nventive + https://github.com/unoplatform/uno + https://nv-assets.azurewebsites.net/logos/uno.png + uno.png + https://github.com/unoplatform/uno + This package provides the platform support for Skia in Uno Platform projects. + Copyright (C) 2015-2020 nventive inc. - all rights reserved + + Uno.WinUI.Runtime.Skia.Gtk + + + + + + + + + + + + + + + + + + + + + + + + + + + true + buildTransitive + + + + diff --git a/src/Uno.UI.Runtime.Skia.Gtk/buildTransitive/Uno.UI.Runtime.Skia.Gtk.props b/src/Uno.UI.Runtime.Skia.Gtk/buildTransitive/Uno.UI.Runtime.Skia.Gtk.props new file mode 100644 index 000000000000..b57453a75cd0 --- /dev/null +++ b/src/Uno.UI.Runtime.Skia.Gtk/buildTransitive/Uno.UI.Runtime.Skia.Gtk.props @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/Uno.UI.Runtime.Skia.Gtk/buildTransitive/Uno.UI.Runtime.Skia.Gtk.targets b/src/Uno.UI.Runtime.Skia.Gtk/buildTransitive/Uno.UI.Runtime.Skia.Gtk.targets new file mode 100644 index 000000000000..384315bf6a8f --- /dev/null +++ b/src/Uno.UI.Runtime.Skia.Gtk/buildTransitive/Uno.UI.Runtime.Skia.Gtk.targets @@ -0,0 +1,21 @@ + + + + + + + + + + $(UnoDefineConstants);HAS_UNO_SKIA;HAS_UNO_SKIA_GTK + + + + + + + + + + diff --git a/src/Uno.UI.Runtime.Skia.Wpf/Uno.UI.Runtime.Skia.Wpf.csproj b/src/Uno.UI.Runtime.Skia.Wpf/Uno.UI.Runtime.Skia.Wpf.csproj new file mode 100644 index 000000000000..ffd16c1e08dd --- /dev/null +++ b/src/Uno.UI.Runtime.Skia.Wpf/Uno.UI.Runtime.Skia.Wpf.csproj @@ -0,0 +1,49 @@ + + + + net47 + + + + true + nventive + https://github.com/unoplatform/uno + https://nv-assets.azurewebsites.net/logos/uno.png + uno.png + https://github.com/unoplatform/uno + This package provides the platform support for Skia in Uno Platform projects. + Copyright (C) 2015-2020 nventive inc. - all rights reserved + + Uno.WinUI.Runtime.Skia.Wpf + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + buildTransitive + + + diff --git a/src/Uno.UI.Runtime.Skia.Wpf/WPF/WpfHost.cs b/src/Uno.UI.Runtime.Skia.Wpf/WPF/WpfHost.cs new file mode 100644 index 000000000000..191485f3d159 --- /dev/null +++ b/src/Uno.UI.Runtime.Skia.Wpf/WPF/WpfHost.cs @@ -0,0 +1,119 @@ +#if NETFRAMEWORK +using SkiaSharp; +using System; +using System.ComponentModel; +using System.Windows; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using WinUI = Windows.UI.Xaml; + +namespace Uno.UI.Skia.Platform +{ + public class WpfHost : FrameworkElement + { + private readonly bool designMode; + private readonly Func _appBuilder; + private WriteableBitmap bitmap; + private bool ignorePixelScaling; + + public WpfHost(Func appBuilder) + { + designMode = DesignerProperties.GetIsInDesignMode(this); + _appBuilder = appBuilder; + + WinUI.Application.Start(_ => appBuilder()); + + WinUI.Window.Current.InvalidateRender += () => InvalidateVisual(); + + SizeChanged += WpfHost_SizeChanged; + Loaded += WpfHost_Loaded; + } + + private void WpfHost_Loaded(object sender, RoutedEventArgs e) + { + WinUI.Window.Current.OnNativeSizeChanged(new Windows.Foundation.Size(ActualWidth, ActualHeight)); + } + + private void WpfHost_SizeChanged(object sender, SizeChangedEventArgs e) + { + WinUI.Window.Current.OnNativeSizeChanged( + new Windows.Foundation.Size( + e.NewSize.Width, + e.NewSize.Height + ) + ); + } + + public SKSize CanvasSize => bitmap == null ? SKSize.Empty : new SKSize(bitmap.PixelWidth, bitmap.PixelHeight); + + public bool IgnorePixelScaling + { + get => ignorePixelScaling; + set + { + ignorePixelScaling = value; + InvalidateVisual(); + } + } + + protected override void OnRender(DrawingContext drawingContext) + { + base.OnRender(drawingContext); + + if (designMode) + { + return; + } + + if (ActualWidth == 0 + || ActualHeight == 0 + || double.IsNaN(ActualWidth) + || double.IsNaN(ActualHeight) + || double.IsInfinity(ActualWidth) + || double.IsInfinity(ActualHeight) + || Visibility != Visibility.Visible) + { + return; + } + + int width, height; + double dpiScaleX = 1.0; + double dpiScaleY = 1.0; + if (IgnorePixelScaling) + { + width = (int)ActualWidth; + height = (int)ActualHeight; + } + else + { + var matrix = PresentationSource.FromVisual(this).CompositionTarget.TransformToDevice; + dpiScaleX = matrix.M11; + dpiScaleY = matrix.M22; + width = (int)(ActualWidth * dpiScaleX); + height = (int)(ActualHeight * dpiScaleY); + } + + var info = new SKImageInfo(width, height, SKImageInfo.PlatformColorType, SKAlphaType.Premul); + + // reset the bitmap if the size has changed + if (bitmap == null || info.Width != bitmap.PixelWidth || info.Height != bitmap.PixelHeight) + { + bitmap = new WriteableBitmap(width, height, 96 * dpiScaleX, 96 * dpiScaleY, PixelFormats.Pbgra32, null); + } + + // draw on the bitmap + bitmap.Lock(); + using (var surface = SKSurface.Create(info, bitmap.BackBuffer, bitmap.BackBufferStride)) + { + surface.Canvas.Clear(SKColors.White); + WinUI.Window.Current.Compositor.Render(surface, info); + } + + // draw the bitmap to the screen + bitmap.AddDirtyRect(new Int32Rect(0, 0, width, height)); + bitmap.Unlock(); + drawingContext.DrawImage(bitmap, new Rect(0, 0, ActualWidth, ActualHeight)); + } + } +} +#endif diff --git a/src/Uno.UI.Runtime.Skia.Wpf/buildTransitive/Uno.UI.Runtime.Skia.Wpf.props b/src/Uno.UI.Runtime.Skia.Wpf/buildTransitive/Uno.UI.Runtime.Skia.Wpf.props new file mode 100644 index 000000000000..9abbed6843d5 --- /dev/null +++ b/src/Uno.UI.Runtime.Skia.Wpf/buildTransitive/Uno.UI.Runtime.Skia.Wpf.props @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/Uno.UI.Runtime.Skia.Wpf/buildTransitive/Uno.UI.Runtime.Skia.Wpf.targets b/src/Uno.UI.Runtime.Skia.Wpf/buildTransitive/Uno.UI.Runtime.Skia.Wpf.targets new file mode 100644 index 000000000000..73169d480fa2 --- /dev/null +++ b/src/Uno.UI.Runtime.Skia.Wpf/buildTransitive/Uno.UI.Runtime.Skia.Wpf.targets @@ -0,0 +1,20 @@ + + + + + + + + + + $(UnoDefineConstants);HAS_UNO_SKIA;HAS_UNO_SKIA_WPF + + + + + + + + + diff --git a/src/Uno.UI.Runtime.Wasm/AssemblyInfo.cs b/src/Uno.UI.Runtime.Wasm/AssemblyInfo.cs new file mode 100644 index 000000000000..4483ce7ff7e9 --- /dev/null +++ b/src/Uno.UI.Runtime.Wasm/AssemblyInfo.cs @@ -0,0 +1,15 @@ +using global::System.Reflection; +using global::System.Runtime.CompilerServices; +using global::System.Runtime.InteropServices; + +[assembly: InternalsVisibleTo("Uno.UI")] +[assembly: InternalsVisibleTo("Uno")] +[assembly: InternalsVisibleTo("Uno.UI.Wasm")] +[assembly: InternalsVisibleTo("Uno.Wasm")] +[assembly: InternalsVisibleTo("Uno.UI.Tests")] + +#if __IOS__ +[assembly: Foundation.LinkerSafe] +#elif __ANDROID__ +[assembly: Android.LinkerSafe] +#endif diff --git a/src/Uno.UI.Runtime.Wasm/HtmlElement.cs b/src/Uno.UI.Runtime.Wasm/HtmlElement.cs new file mode 100644 index 000000000000..c2d19d68a0f2 --- /dev/null +++ b/src/Uno.UI.Runtime.Wasm/HtmlElement.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Uno.UI.Runtime.Wasm +{ + /// + /// Defines the HtmlElement properties to use for the WebAssembly+Html target. + /// + [System.AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)] + public sealed class HtmlElementAttribute : Attribute + { + public HtmlElementAttribute(string tag) + { + Tag = tag; + } + + public string Tag { get; } + } +} diff --git a/src/Uno.UI.Runtime.Wasm/LinkerDefinition.xml b/src/Uno.UI.Runtime.Wasm/LinkerDefinition.xml new file mode 100644 index 000000000000..1844924f9fac --- /dev/null +++ b/src/Uno.UI.Runtime.Wasm/LinkerDefinition.xml @@ -0,0 +1,4 @@ + + + + diff --git a/src/Uno.UI.Runtime.Wasm/RuntimeAnchor.cs b/src/Uno.UI.Runtime.Wasm/RuntimeAnchor.cs new file mode 100644 index 000000000000..ce64f2f933ff --- /dev/null +++ b/src/Uno.UI.Runtime.Wasm/RuntimeAnchor.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text; + +namespace Uno.UI.Runtime.Wasm +{ + /// + /// Class used to ensure that Uno.UI.Runtime.Wasm will be included properly + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public class CompileAnchor + { + } +} diff --git a/src/Uno.UI.Runtime.Wasm/Uno.UI.Runtime.Wasm.csproj b/src/Uno.UI.Runtime.Wasm/Uno.UI.Runtime.Wasm.csproj new file mode 100644 index 000000000000..51cf9ee72064 --- /dev/null +++ b/src/Uno.UI.Runtime.Wasm/Uno.UI.Runtime.Wasm.csproj @@ -0,0 +1,68 @@ + + + netstandard2.0 + + + + true + + $(NoWarn);NU1701 + $(DefineConstants);IS_UNO + + false + true + + WebAssembly + + Uno.WinUI.Runtime.Wasm + + + + + + + + all + + + + + + + + + + + + + $(AssemblyName).xml + + + + + + + + + <_OverrideTargetFramework>$(TargetFramework) + <_TargetNugetFolder>$(USERPROFILE)\.nuget\packages\$(PackageId)\$(UnoNugetOverrideVersion)\lib\$(TargetFramework) + + + <_OutputFiles Include="$(TargetDir)**" /> + + + + + + + + + + + + true + buildTransitive + + + + diff --git a/src/Uno.UI.Wasm/WasmHttpHandler.cs b/src/Uno.UI.Runtime.Wasm/WasmHttpHandler.cs similarity index 100% rename from src/Uno.UI.Wasm/WasmHttpHandler.cs rename to src/Uno.UI.Runtime.Wasm/WasmHttpHandler.cs diff --git a/src/Uno.UI.Runtime.Wasm/buildTransitive/Uno.UI.Runtime.Wasm.props b/src/Uno.UI.Runtime.Wasm/buildTransitive/Uno.UI.Runtime.Wasm.props new file mode 100644 index 000000000000..9abbed6843d5 --- /dev/null +++ b/src/Uno.UI.Runtime.Wasm/buildTransitive/Uno.UI.Runtime.Wasm.props @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/Uno.UI.Runtime.Wasm/buildTransitive/Uno.UI.Runtime.Wasm.targets b/src/Uno.UI.Runtime.Wasm/buildTransitive/Uno.UI.Runtime.Wasm.targets new file mode 100644 index 000000000000..c6fb5fb68899 --- /dev/null +++ b/src/Uno.UI.Runtime.Wasm/buildTransitive/Uno.UI.Runtime.Wasm.targets @@ -0,0 +1,42 @@ + + + + + + + + + + $(UnoDefineConstants);HAS_UNO_WASM;__WASM__ + + + + + + + + + + + + <_unouiruntimewasm_keepalive>$(IntermediateOutputPath)/unouiruntimewasm_keepalive.g.cs + + + + + + + + + + + + + diff --git a/src/Uno.UI.RuntimeTests.Skia/LinkerDefinition.Skia.xml b/src/Uno.UI.RuntimeTests.Skia/LinkerDefinition.Skia.xml new file mode 100644 index 000000000000..b955d5942c7c --- /dev/null +++ b/src/Uno.UI.RuntimeTests.Skia/LinkerDefinition.Skia.xml @@ -0,0 +1,3 @@ + + + diff --git a/src/Uno.UI.RuntimeTests.Skia/Uno.UI.RuntimeTests.Skia.csproj b/src/Uno.UI.RuntimeTests.Skia/Uno.UI.RuntimeTests.Skia.csproj new file mode 100644 index 000000000000..8759a28dd18d --- /dev/null +++ b/src/Uno.UI.RuntimeTests.Skia/Uno.UI.RuntimeTests.Skia.csproj @@ -0,0 +1,81 @@ + + + + netstandard2.0 + + + + Uno.UI.RuntimeTests + Uno.UI.RuntimeTests + + Skia + ..\Uno.UI.RuntimeTests\ + + + + + true + + + + + + + + + + + + + UnitTests\Windows_UI_Xaml\FrameworkElementTests\%(RecursiveDir)%(FileName)%(Extension) + + + UnitTests\Windows_UI_Xaml_Controls\GridTests\%(RecursiveDir)%(FileName)%(Extension) + + + UnitTests\Windows_UI_Xaml_Controls\GridTests\%(RecursiveDir)%(FileName)%(Extension) + + + UnitTests\Windows_UI_Xaml_Controls\BorderTests\%(RecursiveDir)%(FileName)%(Extension) + + + + + + $(AssemblyName).xml + + + + + + + + + + + + ..\SourceGenerators\Uno.UI.SourceGenerators\bin\$(Configuration) + + + + + false + true + TargetFramework + + + + + + + + + + + + + + + + diff --git a/src/Uno.UI.RuntimeTests.Wasm/LinkerDefinition.Wasm.xml b/src/Uno.UI.RuntimeTests.Wasm/LinkerDefinition.Wasm.xml new file mode 100644 index 000000000000..b955d5942c7c --- /dev/null +++ b/src/Uno.UI.RuntimeTests.Wasm/LinkerDefinition.Wasm.xml @@ -0,0 +1,3 @@ + + + diff --git a/src/Uno.UI.RuntimeTests.Wasm/Uno.UI.RuntimeTests.Wasm.csproj b/src/Uno.UI.RuntimeTests.Wasm/Uno.UI.RuntimeTests.Wasm.csproj new file mode 100644 index 000000000000..e396125ddcaf --- /dev/null +++ b/src/Uno.UI.RuntimeTests.Wasm/Uno.UI.RuntimeTests.Wasm.csproj @@ -0,0 +1,94 @@ + + + + netstandard2.0 + + + + Uno.UI.RuntimeTests + Uno.UI.RuntimeTests + + WebAssembly + ..\Uno.UI.RuntimeTests\ + + + + + true + + + + + + + + + + + + + + + UnitTests\Windows_UI_Xaml\FrameworkElementTests\%(RecursiveDir)%(FileName)%(Extension) + + + UnitTests\Windows_UI_Xaml_Controls\GridTests\%(RecursiveDir)%(FileName)%(Extension) + + + UnitTests\Windows_UI_Xaml_Controls\GridTests\%(RecursiveDir)%(FileName)%(Extension) + + + UnitTests\Windows_UI_Xaml_Controls\BorderTests\%(RecursiveDir)%(FileName)%(Extension) + + + + + + $(AssemblyName).xml + + + + + + + + + + + + + + + + + + + + $(DefineConstants);WINDOWS_UWP + + + + ..\SourceGenerators\Uno.UI.SourceGenerators\bin\$(Configuration) + + + + + false + true + TargetFramework + + + + + + + + + + + + + + + diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/HtmlElementAttributeTests/Given_HtmlElementAttribute.Wasm.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/HtmlElementAttributeTests/Given_HtmlElementAttribute.Wasm.cs new file mode 100644 index 000000000000..00f3888d71ac --- /dev/null +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/HtmlElementAttributeTests/Given_HtmlElementAttribute.Wasm.cs @@ -0,0 +1,29 @@ +#if __WASM__ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Uno.UI.Runtime.Wasm; +using Windows.UI.Xaml; + +namespace Uno.UI.RuntimeTests.Tests.Windows_UI_Xaml_Controls.HtmlElementAttributeTests +{ + [TestClass] + class Given_HtmlElementAttribute + { + [TestMethod] + public void Given_TagOverride() + { + var p = new TestControl(); + + Assert.AreEqual("p", p.HtmlTag); + } + } + + [HtmlElement("p")] + public class TestControl : FrameworkElement + { + + } +} +#endif diff --git a/src/Uno.UI.RuntimeTests/Uno.UI.RuntimeTests.csproj b/src/Uno.UI.RuntimeTests/Uno.UI.RuntimeTests.csproj index 2cb36f4235a9..752ff38daa30 100644 --- a/src/Uno.UI.RuntimeTests/Uno.UI.RuntimeTests.csproj +++ b/src/Uno.UI.RuntimeTests/Uno.UI.RuntimeTests.csproj @@ -5,15 +5,13 @@ true - + + Reference + $(UnoTargetFrameworkOverride) - - - $(DefineConstants);__WASM__ - @@ -29,12 +27,6 @@ - - - - - - UnitTests\Windows_UI_Xaml\FrameworkElementTests\%(RecursiveDir)%(FileName)%(Extension) @@ -75,6 +67,16 @@ $(DefineConstants);WINDOWS_UWP + + + + + + + + + + ..\SourceGenerators\Uno.UI.SourceGenerators\bin\$(Configuration) @@ -86,6 +88,10 @@ TargetFramework + + + + diff --git a/src/Uno.UI.Skia/AssemblyInfo.skia.cs b/src/Uno.UI.Skia/AssemblyInfo.skia.cs new file mode 100644 index 000000000000..11e611065afc --- /dev/null +++ b/src/Uno.UI.Skia/AssemblyInfo.skia.cs @@ -0,0 +1,4 @@ +using global::System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Uno.UI.Runtime.Skia.Gtk")] +[assembly: InternalsVisibleTo("Uno.UI.Runtime.Skia.Wpf")] diff --git a/src/Uno.UI.Skia/LinkerDefinition.xml b/src/Uno.UI.Skia/LinkerDefinition.xml new file mode 100644 index 000000000000..bf52e6088fa0 --- /dev/null +++ b/src/Uno.UI.Skia/LinkerDefinition.xml @@ -0,0 +1,2 @@ + + diff --git a/src/Uno.UI.Skia/Uno.UI.Skia.csproj b/src/Uno.UI.Skia/Uno.UI.Skia.csproj new file mode 100644 index 000000000000..413614d33b2b --- /dev/null +++ b/src/Uno.UI.Skia/Uno.UI.Skia.csproj @@ -0,0 +1,112 @@ + + + netstandard2.0 + + + + false + $(NoWarn);NU1701 + $(DefineConstants);IS_UNO + + false + true + Uno.UI + Uno.UI + + Skia + ..\Uno.UI\ + + + + + $(AssemblyName).xml + + + + + + + + + all + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\SourceGenerators\Uno.UI.SourceGenerators\bin\$(Configuration) + $(MSBuildThisFileDirectory)..\SourceGenerators\Uno.UI.Tasks\bin\$(Configuration)_Shadow + + _UnoSourceGenerator; $(CompileTypeScriptDependsOn) + + + + + + + + + <_OverrideTargetFramework>$(TargetFramework) + <_TargetNugetFolder>$(USERPROFILE)\.nuget\packages\$(PackageId)\$(UnoNugetOverrideVersion)\uno-runtime\$(UnoRuntimeIdentifier.ToLowerInvariant()) + + + <_OutputFiles Include="$(TargetDir)**" /> + + + + + + + + + + + + false + true + TargetFramework + + + false + true + TargetFramework + + + false + true + TargetFramework + + + + diff --git a/src/Uno.UI.Toolkit.Skia/Uno.UI.Toolkit.Skia.csproj b/src/Uno.UI.Toolkit.Skia/Uno.UI.Toolkit.Skia.csproj new file mode 100644 index 000000000000..7efa136ec882 --- /dev/null +++ b/src/Uno.UI.Toolkit.Skia/Uno.UI.Toolkit.Skia.csproj @@ -0,0 +1,72 @@ + + + netstandard2.0 + + + + Uno.UI.Toolkit + Uno.UI.Toolkit + $(AssemblyName) ($(TargetFramework)) + en-US + + false + true + + Skia + ..\Uno.UI.Toolkit\ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\SourceGenerators\Uno.UI.SourceGenerators\bin\$(Configuration) + + + + + + + + + + <_OverrideTargetFramework>$(TargetFramework) + <_TargetNugetFolder>$(USERPROFILE)\.nuget\packages\Uno.UI\$(UnoNugetOverrideVersion)\uno-runtime\$(_OverrideTargetFramework) + + + <_OutputFiles Include="$(TargetDir)**" /> + + + + + + + + + diff --git a/src/Uno.UI.Toolkit.Wasm/Uno.UI.Toolkit.Wasm.csproj b/src/Uno.UI.Toolkit.Wasm/Uno.UI.Toolkit.Wasm.csproj new file mode 100644 index 000000000000..4a5c068e26af --- /dev/null +++ b/src/Uno.UI.Toolkit.Wasm/Uno.UI.Toolkit.Wasm.csproj @@ -0,0 +1,75 @@ + + + netstandard2.0 + + + + $(UnoTargetFrameworkOverride) + + + + Uno.UI.Toolkit + Uno.UI.Toolkit + $(AssemblyName) ($(TargetFramework)) + en-US + + false + true + + WebAssembly + ..\Uno.UI.Toolkit\ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\SourceGenerators\Uno.UI.SourceGenerators\bin\$(Configuration) + + + + + + + + + + <_OverrideTargetFramework>$(TargetFramework) + <_TargetNugetFolder>$(USERPROFILE)\.nuget\packages\Uno.UI\$(UnoNugetOverrideVersion)\uno-runtime\$(_OverrideTargetFramework) + + + <_OutputFiles Include="$(TargetDir)**" /> + + + + + + + + + diff --git a/src/Uno.UI.Toolkit/RectExtensions.cs b/src/Uno.UI.Toolkit/RectExtensions.cs index a186bd890d84..a23a10ec14c1 100644 --- a/src/Uno.UI.Toolkit/RectExtensions.cs +++ b/src/Uno.UI.Toolkit/RectExtensions.cs @@ -10,7 +10,7 @@ namespace Uno.UI.Toolkit.Extensions { internal static class RectExtensions { -#if !XAMARIN && !__WASM__ +#if !XAMARIN && !NETSTANDARD2_0 /// /// Returns the orientation of the rectangle. /// diff --git a/src/Uno.UI.Toolkit/Uno.UI.Toolkit.csproj b/src/Uno.UI.Toolkit/Uno.UI.Toolkit.csproj index b476cf3e5752..0c6932afcb48 100644 --- a/src/Uno.UI.Toolkit/Uno.UI.Toolkit.csproj +++ b/src/Uno.UI.Toolkit/Uno.UI.Toolkit.csproj @@ -16,6 +16,8 @@ false true + + Reference + + + diff --git a/src/Uno.UI.Wasm.Tests/Uno.UI.Wasm.Tests.csproj b/src/Uno.UI.Wasm.Tests/Uno.UI.Wasm.Tests.csproj index 0e5b83156ca4..785d88d4a9af 100644 --- a/src/Uno.UI.Wasm.Tests/Uno.UI.Wasm.Tests.csproj +++ b/src/Uno.UI.Wasm.Tests/Uno.UI.Wasm.Tests.csproj @@ -23,10 +23,9 @@ - - - + + diff --git a/src/Uno.UI.Wasm/LinkerDefinition.xml b/src/Uno.UI.Wasm/LinkerDefinition.xml index 519015a3fdb4..9b984928d83f 100644 --- a/src/Uno.UI.Wasm/LinkerDefinition.xml +++ b/src/Uno.UI.Wasm/LinkerDefinition.xml @@ -1,5 +1,60 @@  - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Uno.UI.Wasm/Uno.UI.Wasm.csproj b/src/Uno.UI.Wasm/Uno.UI.Wasm.csproj index 2af22a73ddc3..593a2c0a11ba 100644 --- a/src/Uno.UI.Wasm/Uno.UI.Wasm.csproj +++ b/src/Uno.UI.Wasm/Uno.UI.Wasm.csproj @@ -1,16 +1,22 @@  - netstandard2.0 + netstandard2.0 false $(NoWarn);NU1701 - + $(DefineConstants);IS_UNO + false true + Uno.UI + Uno.UI $(MSBuildThisFileDirectory)tsBindings + + WebAssembly + ..\Uno.UI\ @@ -38,12 +44,22 @@ + + + all + + + + + + + + - - - + + @@ -53,7 +69,29 @@ + + + + + + + + + + + + + + + + + + + + + + ..\SourceGenerators\Uno.UI.SourceGenerators\bin\$(Configuration) @@ -63,12 +101,13 @@ + - + <_OverrideTargetFramework>$(TargetFramework) - <_TargetNugetFolder>$(USERPROFILE)\.nuget\packages\Uno.UI\$(UnoNugetOverrideVersion)\lib\$(_OverrideTargetFramework) + <_TargetNugetFolder>$(USERPROFILE)\.nuget\packages\$(PackageId)\$(UnoNugetOverrideVersion)\uno-runtime\$(UnoRuntimeIdentifier.ToLowerInvariant()) <_OutputFiles Include="$(TargetDir)**" /> @@ -81,4 +120,22 @@ + + + false + true + TargetFramework + + + false + true + TargetFramework + + + false + true + TargetFramework + + + diff --git a/src/Uno.UI.Wasm/WasmScripts/Uno.UI.js b/src/Uno.UI.Wasm/WasmScripts/Uno.UI.js index 0dfd8a580ede..e84cb1160dcf 100644 --- a/src/Uno.UI.Wasm/WasmScripts/Uno.UI.js +++ b/src/Uno.UI.Wasm/WasmScripts/Uno.UI.js @@ -214,7 +214,7 @@ var Uno; if (this.dispatchResponseMethod) { return; // already initialized. } - const asm = MonoRuntime.assembly_load("Uno.UI.Wasm"); + const asm = MonoRuntime.assembly_load("Uno.UI.Runtime.Wasm"); const httpClass = MonoRuntime.find_class(asm, "Uno.UI.Wasm", "WasmHttpHandler"); this.dispatchResponseMethod = MonoRuntime.find_method(httpClass, "DispatchResponse", -1); this.dispatchErrorMethod = MonoRuntime.find_method(httpClass, "DispatchError", -1); @@ -2777,9 +2777,9 @@ var Uno; } const w = window; AsyncInteropHelper.dispatchResultMethod = - w.Module.mono_bind_static_method("[Uno.Foundation] Uno.Foundation.WebAssemblyRuntime:DispatchAsyncResult"); + w.Module.mono_bind_static_method("[Uno.Foundation.Runtime.Wasm] Uno.Foundation.WebAssemblyRuntime:DispatchAsyncResult"); AsyncInteropHelper.dispatchErrorMethod = - w.Module.mono_bind_static_method("[Uno.Foundation] Uno.Foundation.WebAssemblyRuntime:DispatchAsyncError"); + w.Module.mono_bind_static_method("[Uno.Foundation.Runtime.Wasm] Uno.Foundation.WebAssemblyRuntime:DispatchAsyncError"); } static Invoke(handle, promiseFunction) { AsyncInteropHelper.init(); @@ -2814,7 +2814,7 @@ var Uno; (function (Interop) { class ManagedObject { static init() { - ManagedObject.dispatchMethod = Module.mono_bind_static_method("[Uno.Foundation] Uno.Foundation.Interop.JSObject:Dispatch"); + ManagedObject.dispatchMethod = Module.mono_bind_static_method("[Uno.Foundation.Runtime.Wasm] Uno.Foundation.Interop.JSObject:Dispatch"); } static dispatch(handle, method, parameters) { if (!ManagedObject.dispatchMethod) { @@ -3400,6 +3400,9 @@ var Windows; DisplayRequest.activeScreenLockPromise = navigator.wakeLock.request(WakeLockType.screen); DisplayRequest.activeScreenLockPromise.catch(reason => console.log("Could not acquire screen lock (" + reason + ")")); } + else { + console.log("Wake Lock API is not available in this browser."); + } } static deactivateScreenLock() { if (DisplayRequest.activeScreenLockPromise) { diff --git a/src/Uno.UI.Wasm/ts/HttpClient.ts b/src/Uno.UI.Wasm/ts/HttpClient.ts index 077b2c2f646a..3270c07fb448 100644 --- a/src/Uno.UI.Wasm/ts/HttpClient.ts +++ b/src/Uno.UI.Wasm/ts/HttpClient.ts @@ -89,7 +89,7 @@ return; // already initialized. } - const asm = MonoRuntime.assembly_load("Uno.UI.Wasm"); + const asm = MonoRuntime.assembly_load("Uno.UI.Runtime.Wasm"); const httpClass = MonoRuntime.find_class(asm, "Uno.UI.Wasm", "WasmHttpHandler"); this.dispatchResponseMethod = MonoRuntime.find_method(httpClass, "DispatchResponse", -1); this.dispatchErrorMethod = MonoRuntime.find_method(httpClass, "DispatchError", -1); diff --git a/src/Uno.UI.Wasm/ts/Interop/AsyncInteropHelper.ts b/src/Uno.UI.Wasm/ts/Interop/AsyncInteropHelper.ts index 86f1fae8c335..abdc14ba7184 100644 --- a/src/Uno.UI.Wasm/ts/Interop/AsyncInteropHelper.ts +++ b/src/Uno.UI.Wasm/ts/Interop/AsyncInteropHelper.ts @@ -10,9 +10,9 @@ } const w = window as any; AsyncInteropHelper.dispatchResultMethod = - w.Module.mono_bind_static_method("[Uno.Foundation] Uno.Foundation.WebAssemblyRuntime:DispatchAsyncResult"); + w.Module.mono_bind_static_method("[Uno.Foundation.Runtime.Wasm] Uno.Foundation.WebAssemblyRuntime:DispatchAsyncResult"); AsyncInteropHelper.dispatchErrorMethod = - w.Module.mono_bind_static_method("[Uno.Foundation] Uno.Foundation.WebAssemblyRuntime:DispatchAsyncError"); + w.Module.mono_bind_static_method("[Uno.Foundation.Runtime.Wasm] Uno.Foundation.WebAssemblyRuntime:DispatchAsyncError"); } public static Invoke(handle: number, promiseFunction: () => Promise): void { diff --git a/src/Uno.UI.Wasm/ts/Interop/ManagedObject.ts b/src/Uno.UI.Wasm/ts/Interop/ManagedObject.ts index 6a2cc93fab99..3797487ef182 100644 --- a/src/Uno.UI.Wasm/ts/Interop/ManagedObject.ts +++ b/src/Uno.UI.Wasm/ts/Interop/ManagedObject.ts @@ -4,7 +4,7 @@ private static dispatchMethod: (handle: string, method: string, parameters: string) => number; private static init() { - ManagedObject.dispatchMethod = (Module).mono_bind_static_method("[Uno.Foundation] Uno.Foundation.Interop.JSObject:Dispatch"); + ManagedObject.dispatchMethod = (Module).mono_bind_static_method("[Uno.Foundation.Runtime.Wasm] Uno.Foundation.Interop.JSObject:Dispatch"); } public static dispatch(handle: string, method: string, parameters: string): void { diff --git a/src/Uno.UI.sln b/src/Uno.UI.sln index 6fb58d52c949..418e5788a64d 100644 --- a/src/Uno.UI.sln +++ b/src/Uno.UI.sln @@ -147,8 +147,54 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.UI.Tests.ViewLibrary", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.UI.MSAL", "AddIns\Uno.UI.MSAL\Uno.UI.MSAL.csproj", "{2569663D-293A-4A1D-BB84-AA8C7B4B7F92}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.Wasm", "Uno.UWP.Wasm\Uno.Wasm.csproj", "{E52D214F-8A34-43C8-95D9-0A1F74F9847E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.Foundation.Wasm", "Uno.Foundation.Wasm\Uno.Foundation.Wasm.csproj", "{5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.UI.Toolkit.Wasm", "Uno.UI.Toolkit.Wasm\Uno.UI.Toolkit.Wasm.csproj", "{2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.UI.RemoteControl.Wasm", "Uno.UI.RemoteControl.Wasm\Uno.UI.RemoteControl.Wasm.csproj", "{0AC8FEA5-B89C-47C5-8169-77E053F10274}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.UI.RuntimeTests.Wasm", "Uno.UI.RuntimeTests.Wasm\Uno.UI.RuntimeTests.Wasm.csproj", "{136055A3-C008-4EFA-9FA0-50B20B87B09A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.UI.Lottie.Wasm", "AddIns\Uno.UI.Lottie.Wasm\Uno.UI.Lottie.Wasm.csproj", "{304F9F00-11E8-46A4-992B-32D9581DB756}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.NUnitTransformTool", "Uno.NUnitTransformTool\Uno.NUnitTransformTool.csproj", "{CE3CD566-7D8C-474C-A554-F5A4A698EA48}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.UI.MSAL.Wasm", "AddIns\Uno.UI.MSAL.Wasm\Uno.UI.MSAL.Wasm.csproj", "{C1543178-9756-4739-BF96-30633E07B2ED}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.Foundation.Runtime.Wasm", "Uno.Foundation.Runtime.Wasm\Uno.Foundation.Runtime.Wasm.csproj", "{D13CB6DD-3934-4858-8BBE-FDCF1B699789}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.UI.Runtime.Wasm", "Uno.UI.Runtime.Wasm\Uno.UI.Runtime.Wasm.csproj", "{07C6B075-9EA2-4B03-B756-B7D607BC1844}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.Foundation.Skia", "Uno.Foundation.Skia\Uno.Foundation.Skia.csproj", "{E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.Skia", "Uno.UWP.Skia\Uno.Skia.csproj", "{5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.UI.Skia", "Uno.UI.Skia\Uno.UI.Skia.csproj", "{D1179327-BA1D-4554-AA74-36C3EA585863}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.UI.Runtime.Skia.Gtk", "Uno.UI.Runtime.Skia.Gtk\Uno.UI.Runtime.Skia.Gtk.csproj", "{C24F4B8B-7C5F-4126-A38A-F6F5CF461582}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SamplesApp.Skia", "SamplesApp\SamplesApp.Skia\SamplesApp.Skia.csproj", "{C8C4395C-602F-45AB-AED4-40A8A4EF0089}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SamplesApp.Skia.Gtk", "SamplesApp\SamplesApp.Skia.Gtk\SamplesApp.Skia.Gtk.csproj", "{4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SamplesApp.Skia.WPF", "SamplesApp\SamplesApp.Skia.WPF\SamplesApp.Skia.WPF.csproj", "{27B81C58-B74E-4BC9-BD17-1811C82D0507}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.UI.Toolkit.Skia", "Uno.UI.Toolkit.Skia\Uno.UI.Toolkit.Skia.csproj", "{F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.UI.Lottie.Skia", "AddIns\Uno.UI.Lottie.Skia\Uno.UI.Lottie.Skia.csproj", "{902AFE53-B676-4F67-9F9E-67423439A6AC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.UI.MSAL.Skia", "AddIns\Uno.UI.MSAL.Skia\Uno.UI.MSAL.Skia.csproj", "{BF3E32F0-67BF-4406-8348-FC6315FB360B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.UI.RuntimeTests.Skia", "Uno.UI.RuntimeTests.Skia\Uno.UI.RuntimeTests.Skia.csproj", "{AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.ReferenceImplComparer", "Uno.ReferenceImplComparer\Uno.ReferenceImplComparer.csproj", "{73131285-509B-4019-8047-3F3FCA4FFDC8}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.UI.Runtime.Skia.Wpf", "Uno.UI.Runtime.Skia.Wpf\Uno.UI.Runtime.Skia.Wpf.csproj", "{DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Uno.UI.RemoteControl.Skia", "Uno.UI.RemoteControl.Skia\Uno.UI.RemoteControl.Skia.csproj", "{A95B814B-6BEC-4C06-BC8A-04E62FD63245}" +EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution SamplesApp\SamplesApp.UnitTests.Shared\SamplesApp.UnitTests.Shared.projitems*{04b1b5eb-d42e-47de-ada0-eb863e5574fd}*SharedItemsImports = 13 @@ -171,6 +217,9 @@ Global SamplesApp\SamplesApp.UnitTests.Shared\SamplesApp.UnitTests.Shared.projitems*{b71ae380-558c-4d6c-81d8-9c043b50262c}*SharedItemsImports = 4 SamplesApp\UITests.Shared\UITests.Shared.projitems*{b71ae380-558c-4d6c-81d8-9c043b50262c}*SharedItemsImports = 4 SamplesApp\UITests.Shared\UITests.Shared.projitems*{beb0ab3a-16a7-49cf-ad5e-f4a53b985afe}*SharedItemsImports = 13 + SamplesApp\SamplesApp.Shared\SamplesApp.Shared.projitems*{c8c4395c-602f-45ab-aed4-40a8a4ef0089}*SharedItemsImports = 5 + SamplesApp\SamplesApp.UnitTests.Shared\SamplesApp.UnitTests.Shared.projitems*{c8c4395c-602f-45ab-aed4-40a8a4ef0089}*SharedItemsImports = 5 + SamplesApp\UITests.Shared\UITests.Shared.projitems*{c8c4395c-602f-45ab-aed4-40a8a4ef0089}*SharedItemsImports = 5 SamplesApp\SamplesApp.UnitTests.Shared\SamplesApp.UnitTests.Shared.projitems*{e3b940da-15a4-4104-b96b-6951d932fe0e}*SharedItemsImports = 4 SamplesApp\UITests.Shared\UITests.Shared.projitems*{e3b940da-15a4-4104-b96b-6951d932fe0e}*SharedItemsImports = 4 SamplesApp\Benchmarks.Shared\Benchmarks.Shared.projitems*{f4581f51-40d6-4035-8a1d-65cc6917d0a9}*SharedItemsImports = 13 @@ -2276,6 +2325,258 @@ Global {2569663D-293A-4A1D-BB84-AA8C7B4B7F92}.Release|x64.Build.0 = Release|Any CPU {2569663D-293A-4A1D-BB84-AA8C7B4B7F92}.Release|x86.ActiveCfg = Release|Any CPU {2569663D-293A-4A1D-BB84-AA8C7B4B7F92}.Release|x86.Build.0 = Release|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Debug|ARM.ActiveCfg = Debug|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Debug|ARM.Build.0 = Debug|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Debug|ARM64.Build.0 = Debug|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Debug|iPhone.Build.0 = Debug|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Debug|x64.ActiveCfg = Debug|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Debug|x64.Build.0 = Debug|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Debug|x86.ActiveCfg = Debug|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Debug|x86.Build.0 = Debug|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Release_NoSamples|Any CPU.ActiveCfg = Release|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Release_NoSamples|Any CPU.Build.0 = Release|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Release_NoSamples|ARM.ActiveCfg = Release|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Release_NoSamples|ARM.Build.0 = Release|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Release_NoSamples|ARM64.ActiveCfg = Release|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Release_NoSamples|ARM64.Build.0 = Release|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Release_NoSamples|iPhone.ActiveCfg = Release|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Release_NoSamples|iPhone.Build.0 = Release|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Release_NoSamples|iPhoneSimulator.ActiveCfg = Release|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Release_NoSamples|iPhoneSimulator.Build.0 = Release|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Release_NoSamples|x64.ActiveCfg = Release|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Release_NoSamples|x64.Build.0 = Release|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Release_NoSamples|x86.ActiveCfg = Release|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Release_NoSamples|x86.Build.0 = Release|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Release|Any CPU.Build.0 = Release|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Release|ARM.ActiveCfg = Release|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Release|ARM.Build.0 = Release|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Release|ARM64.ActiveCfg = Release|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Release|ARM64.Build.0 = Release|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Release|iPhone.ActiveCfg = Release|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Release|iPhone.Build.0 = Release|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Release|x64.ActiveCfg = Release|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Release|x64.Build.0 = Release|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Release|x86.ActiveCfg = Release|Any CPU + {E52D214F-8A34-43C8-95D9-0A1F74F9847E}.Release|x86.Build.0 = Release|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Debug|ARM.ActiveCfg = Debug|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Debug|ARM.Build.0 = Debug|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Debug|ARM64.Build.0 = Debug|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Debug|iPhone.Build.0 = Debug|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Debug|x64.ActiveCfg = Debug|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Debug|x64.Build.0 = Debug|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Debug|x86.ActiveCfg = Debug|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Debug|x86.Build.0 = Debug|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Release_NoSamples|Any CPU.ActiveCfg = Release|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Release_NoSamples|Any CPU.Build.0 = Release|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Release_NoSamples|ARM.ActiveCfg = Release|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Release_NoSamples|ARM.Build.0 = Release|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Release_NoSamples|ARM64.ActiveCfg = Release|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Release_NoSamples|ARM64.Build.0 = Release|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Release_NoSamples|iPhone.ActiveCfg = Release|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Release_NoSamples|iPhone.Build.0 = Release|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Release_NoSamples|iPhoneSimulator.ActiveCfg = Release|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Release_NoSamples|iPhoneSimulator.Build.0 = Release|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Release_NoSamples|x64.ActiveCfg = Release|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Release_NoSamples|x64.Build.0 = Release|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Release_NoSamples|x86.ActiveCfg = Release|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Release_NoSamples|x86.Build.0 = Release|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Release|Any CPU.Build.0 = Release|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Release|ARM.ActiveCfg = Release|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Release|ARM.Build.0 = Release|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Release|ARM64.ActiveCfg = Release|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Release|ARM64.Build.0 = Release|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Release|iPhone.ActiveCfg = Release|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Release|iPhone.Build.0 = Release|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Release|x64.ActiveCfg = Release|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Release|x64.Build.0 = Release|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Release|x86.ActiveCfg = Release|Any CPU + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C}.Release|x86.Build.0 = Release|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Debug|ARM.ActiveCfg = Debug|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Debug|ARM.Build.0 = Debug|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Debug|ARM64.Build.0 = Debug|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Debug|iPhone.Build.0 = Debug|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Debug|x64.ActiveCfg = Debug|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Debug|x64.Build.0 = Debug|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Debug|x86.ActiveCfg = Debug|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Debug|x86.Build.0 = Debug|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Release_NoSamples|Any CPU.ActiveCfg = Release|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Release_NoSamples|Any CPU.Build.0 = Release|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Release_NoSamples|ARM.ActiveCfg = Release|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Release_NoSamples|ARM.Build.0 = Release|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Release_NoSamples|ARM64.ActiveCfg = Release|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Release_NoSamples|ARM64.Build.0 = Release|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Release_NoSamples|iPhone.ActiveCfg = Release|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Release_NoSamples|iPhone.Build.0 = Release|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Release_NoSamples|iPhoneSimulator.ActiveCfg = Release|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Release_NoSamples|iPhoneSimulator.Build.0 = Release|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Release_NoSamples|x64.ActiveCfg = Release|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Release_NoSamples|x64.Build.0 = Release|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Release_NoSamples|x86.ActiveCfg = Release|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Release_NoSamples|x86.Build.0 = Release|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Release|Any CPU.Build.0 = Release|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Release|ARM.ActiveCfg = Release|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Release|ARM.Build.0 = Release|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Release|ARM64.ActiveCfg = Release|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Release|ARM64.Build.0 = Release|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Release|iPhone.ActiveCfg = Release|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Release|iPhone.Build.0 = Release|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Release|x64.ActiveCfg = Release|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Release|x64.Build.0 = Release|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Release|x86.ActiveCfg = Release|Any CPU + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C}.Release|x86.Build.0 = Release|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Debug|ARM.ActiveCfg = Debug|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Debug|ARM.Build.0 = Debug|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Debug|ARM64.Build.0 = Debug|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Debug|iPhone.Build.0 = Debug|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Debug|x64.ActiveCfg = Debug|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Debug|x64.Build.0 = Debug|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Debug|x86.ActiveCfg = Debug|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Debug|x86.Build.0 = Debug|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Release_NoSamples|Any CPU.ActiveCfg = Release|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Release_NoSamples|Any CPU.Build.0 = Release|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Release_NoSamples|ARM.ActiveCfg = Release|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Release_NoSamples|ARM.Build.0 = Release|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Release_NoSamples|ARM64.ActiveCfg = Release|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Release_NoSamples|ARM64.Build.0 = Release|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Release_NoSamples|iPhone.ActiveCfg = Release|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Release_NoSamples|iPhone.Build.0 = Release|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Release_NoSamples|iPhoneSimulator.ActiveCfg = Release|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Release_NoSamples|iPhoneSimulator.Build.0 = Release|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Release_NoSamples|x64.ActiveCfg = Release|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Release_NoSamples|x64.Build.0 = Release|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Release_NoSamples|x86.ActiveCfg = Release|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Release_NoSamples|x86.Build.0 = Release|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Release|Any CPU.Build.0 = Release|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Release|ARM.ActiveCfg = Release|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Release|ARM.Build.0 = Release|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Release|ARM64.ActiveCfg = Release|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Release|ARM64.Build.0 = Release|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Release|iPhone.ActiveCfg = Release|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Release|iPhone.Build.0 = Release|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Release|x64.ActiveCfg = Release|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Release|x64.Build.0 = Release|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Release|x86.ActiveCfg = Release|Any CPU + {0AC8FEA5-B89C-47C5-8169-77E053F10274}.Release|x86.Build.0 = Release|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Debug|ARM.ActiveCfg = Debug|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Debug|ARM.Build.0 = Debug|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Debug|ARM64.Build.0 = Debug|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Debug|iPhone.Build.0 = Debug|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Debug|x64.ActiveCfg = Debug|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Debug|x64.Build.0 = Debug|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Debug|x86.ActiveCfg = Debug|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Debug|x86.Build.0 = Debug|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Release_NoSamples|Any CPU.ActiveCfg = Release|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Release_NoSamples|Any CPU.Build.0 = Release|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Release_NoSamples|ARM.ActiveCfg = Release|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Release_NoSamples|ARM.Build.0 = Release|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Release_NoSamples|ARM64.ActiveCfg = Release|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Release_NoSamples|ARM64.Build.0 = Release|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Release_NoSamples|iPhone.ActiveCfg = Release|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Release_NoSamples|iPhone.Build.0 = Release|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Release_NoSamples|iPhoneSimulator.ActiveCfg = Release|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Release_NoSamples|iPhoneSimulator.Build.0 = Release|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Release_NoSamples|x64.ActiveCfg = Release|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Release_NoSamples|x64.Build.0 = Release|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Release_NoSamples|x86.ActiveCfg = Release|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Release_NoSamples|x86.Build.0 = Release|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Release|Any CPU.Build.0 = Release|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Release|ARM.ActiveCfg = Release|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Release|ARM.Build.0 = Release|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Release|ARM64.ActiveCfg = Release|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Release|ARM64.Build.0 = Release|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Release|iPhone.ActiveCfg = Release|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Release|iPhone.Build.0 = Release|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Release|x64.ActiveCfg = Release|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Release|x64.Build.0 = Release|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Release|x86.ActiveCfg = Release|Any CPU + {136055A3-C008-4EFA-9FA0-50B20B87B09A}.Release|x86.Build.0 = Release|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Debug|Any CPU.Build.0 = Debug|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Debug|ARM.ActiveCfg = Debug|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Debug|ARM.Build.0 = Debug|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Debug|ARM64.Build.0 = Debug|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Debug|iPhone.Build.0 = Debug|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Debug|x64.ActiveCfg = Debug|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Debug|x64.Build.0 = Debug|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Debug|x86.ActiveCfg = Debug|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Debug|x86.Build.0 = Debug|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Release_NoSamples|Any CPU.ActiveCfg = Release|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Release_NoSamples|Any CPU.Build.0 = Release|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Release_NoSamples|ARM.ActiveCfg = Release|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Release_NoSamples|ARM.Build.0 = Release|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Release_NoSamples|ARM64.ActiveCfg = Release|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Release_NoSamples|ARM64.Build.0 = Release|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Release_NoSamples|iPhone.ActiveCfg = Release|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Release_NoSamples|iPhone.Build.0 = Release|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Release_NoSamples|iPhoneSimulator.ActiveCfg = Release|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Release_NoSamples|iPhoneSimulator.Build.0 = Release|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Release_NoSamples|x64.ActiveCfg = Release|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Release_NoSamples|x64.Build.0 = Release|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Release_NoSamples|x86.ActiveCfg = Release|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Release_NoSamples|x86.Build.0 = Release|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Release|Any CPU.ActiveCfg = Release|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Release|Any CPU.Build.0 = Release|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Release|ARM.ActiveCfg = Release|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Release|ARM.Build.0 = Release|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Release|ARM64.ActiveCfg = Release|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Release|ARM64.Build.0 = Release|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Release|iPhone.ActiveCfg = Release|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Release|iPhone.Build.0 = Release|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Release|x64.ActiveCfg = Release|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Release|x64.Build.0 = Release|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Release|x86.ActiveCfg = Release|Any CPU + {304F9F00-11E8-46A4-992B-32D9581DB756}.Release|x86.Build.0 = Release|Any CPU {CE3CD566-7D8C-474C-A554-F5A4A698EA48}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CE3CD566-7D8C-474C-A554-F5A4A698EA48}.Debug|Any CPU.Build.0 = Debug|Any CPU {CE3CD566-7D8C-474C-A554-F5A4A698EA48}.Debug|ARM.ActiveCfg = Debug|Any CPU @@ -2318,6 +2619,720 @@ Global {CE3CD566-7D8C-474C-A554-F5A4A698EA48}.Release|x64.Build.0 = Release|Any CPU {CE3CD566-7D8C-474C-A554-F5A4A698EA48}.Release|x86.ActiveCfg = Release|Any CPU {CE3CD566-7D8C-474C-A554-F5A4A698EA48}.Release|x86.Build.0 = Release|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Debug|ARM.ActiveCfg = Debug|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Debug|ARM.Build.0 = Debug|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Debug|ARM64.Build.0 = Debug|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Debug|iPhone.Build.0 = Debug|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Debug|x64.ActiveCfg = Debug|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Debug|x64.Build.0 = Debug|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Debug|x86.ActiveCfg = Debug|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Debug|x86.Build.0 = Debug|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Release_NoSamples|Any CPU.ActiveCfg = Release|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Release_NoSamples|Any CPU.Build.0 = Release|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Release_NoSamples|ARM.ActiveCfg = Release|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Release_NoSamples|ARM.Build.0 = Release|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Release_NoSamples|ARM64.ActiveCfg = Release|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Release_NoSamples|ARM64.Build.0 = Release|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Release_NoSamples|iPhone.ActiveCfg = Release|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Release_NoSamples|iPhone.Build.0 = Release|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Release_NoSamples|iPhoneSimulator.ActiveCfg = Release|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Release_NoSamples|iPhoneSimulator.Build.0 = Release|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Release_NoSamples|x64.ActiveCfg = Release|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Release_NoSamples|x64.Build.0 = Release|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Release_NoSamples|x86.ActiveCfg = Release|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Release_NoSamples|x86.Build.0 = Release|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Release|Any CPU.Build.0 = Release|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Release|ARM.ActiveCfg = Release|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Release|ARM.Build.0 = Release|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Release|ARM64.ActiveCfg = Release|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Release|ARM64.Build.0 = Release|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Release|iPhone.ActiveCfg = Release|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Release|iPhone.Build.0 = Release|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Release|x64.ActiveCfg = Release|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Release|x64.Build.0 = Release|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Release|x86.ActiveCfg = Release|Any CPU + {C1543178-9756-4739-BF96-30633E07B2ED}.Release|x86.Build.0 = Release|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Debug|ARM.ActiveCfg = Debug|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Debug|ARM.Build.0 = Debug|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Debug|ARM64.Build.0 = Debug|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Debug|iPhone.Build.0 = Debug|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Debug|x64.ActiveCfg = Debug|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Debug|x64.Build.0 = Debug|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Debug|x86.ActiveCfg = Debug|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Debug|x86.Build.0 = Debug|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Release_NoSamples|Any CPU.ActiveCfg = Release|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Release_NoSamples|Any CPU.Build.0 = Release|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Release_NoSamples|ARM.ActiveCfg = Release|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Release_NoSamples|ARM.Build.0 = Release|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Release_NoSamples|ARM64.ActiveCfg = Release|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Release_NoSamples|ARM64.Build.0 = Release|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Release_NoSamples|iPhone.ActiveCfg = Release|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Release_NoSamples|iPhone.Build.0 = Release|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Release_NoSamples|iPhoneSimulator.ActiveCfg = Release|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Release_NoSamples|iPhoneSimulator.Build.0 = Release|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Release_NoSamples|x64.ActiveCfg = Release|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Release_NoSamples|x64.Build.0 = Release|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Release_NoSamples|x86.ActiveCfg = Release|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Release_NoSamples|x86.Build.0 = Release|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Release|Any CPU.Build.0 = Release|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Release|ARM.ActiveCfg = Release|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Release|ARM.Build.0 = Release|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Release|ARM64.ActiveCfg = Release|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Release|ARM64.Build.0 = Release|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Release|iPhone.ActiveCfg = Release|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Release|iPhone.Build.0 = Release|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Release|x64.ActiveCfg = Release|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Release|x64.Build.0 = Release|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Release|x86.ActiveCfg = Release|Any CPU + {D13CB6DD-3934-4858-8BBE-FDCF1B699789}.Release|x86.Build.0 = Release|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Debug|Any CPU.Build.0 = Debug|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Debug|ARM.ActiveCfg = Debug|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Debug|ARM.Build.0 = Debug|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Debug|ARM64.Build.0 = Debug|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Debug|iPhone.Build.0 = Debug|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Debug|x64.ActiveCfg = Debug|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Debug|x64.Build.0 = Debug|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Debug|x86.ActiveCfg = Debug|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Debug|x86.Build.0 = Debug|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Release_NoSamples|Any CPU.ActiveCfg = Release|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Release_NoSamples|Any CPU.Build.0 = Release|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Release_NoSamples|ARM.ActiveCfg = Release|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Release_NoSamples|ARM.Build.0 = Release|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Release_NoSamples|ARM64.ActiveCfg = Release|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Release_NoSamples|ARM64.Build.0 = Release|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Release_NoSamples|iPhone.ActiveCfg = Release|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Release_NoSamples|iPhone.Build.0 = Release|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Release_NoSamples|iPhoneSimulator.ActiveCfg = Release|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Release_NoSamples|iPhoneSimulator.Build.0 = Release|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Release_NoSamples|x64.ActiveCfg = Release|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Release_NoSamples|x64.Build.0 = Release|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Release_NoSamples|x86.ActiveCfg = Release|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Release_NoSamples|x86.Build.0 = Release|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Release|Any CPU.ActiveCfg = Release|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Release|Any CPU.Build.0 = Release|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Release|ARM.ActiveCfg = Release|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Release|ARM.Build.0 = Release|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Release|ARM64.ActiveCfg = Release|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Release|ARM64.Build.0 = Release|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Release|iPhone.ActiveCfg = Release|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Release|iPhone.Build.0 = Release|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Release|x64.ActiveCfg = Release|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Release|x64.Build.0 = Release|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Release|x86.ActiveCfg = Release|Any CPU + {07C6B075-9EA2-4B03-B756-B7D607BC1844}.Release|x86.Build.0 = Release|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Debug|ARM.ActiveCfg = Debug|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Debug|ARM.Build.0 = Debug|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Debug|ARM64.Build.0 = Debug|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Debug|iPhone.Build.0 = Debug|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Debug|x64.ActiveCfg = Debug|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Debug|x64.Build.0 = Debug|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Debug|x86.ActiveCfg = Debug|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Debug|x86.Build.0 = Debug|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Release_NoSamples|Any CPU.ActiveCfg = Release|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Release_NoSamples|Any CPU.Build.0 = Release|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Release_NoSamples|ARM.ActiveCfg = Release|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Release_NoSamples|ARM.Build.0 = Release|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Release_NoSamples|ARM64.ActiveCfg = Release|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Release_NoSamples|ARM64.Build.0 = Release|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Release_NoSamples|iPhone.ActiveCfg = Release|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Release_NoSamples|iPhone.Build.0 = Release|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Release_NoSamples|iPhoneSimulator.ActiveCfg = Release|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Release_NoSamples|iPhoneSimulator.Build.0 = Release|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Release_NoSamples|x64.ActiveCfg = Release|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Release_NoSamples|x64.Build.0 = Release|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Release_NoSamples|x86.ActiveCfg = Release|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Release_NoSamples|x86.Build.0 = Release|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Release|Any CPU.Build.0 = Release|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Release|ARM.ActiveCfg = Release|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Release|ARM.Build.0 = Release|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Release|ARM64.ActiveCfg = Release|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Release|ARM64.Build.0 = Release|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Release|iPhone.ActiveCfg = Release|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Release|iPhone.Build.0 = Release|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Release|x64.ActiveCfg = Release|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Release|x64.Build.0 = Release|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Release|x86.ActiveCfg = Release|Any CPU + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16}.Release|x86.Build.0 = Release|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Debug|ARM.ActiveCfg = Debug|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Debug|ARM.Build.0 = Debug|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Debug|ARM64.Build.0 = Debug|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Debug|iPhone.Build.0 = Debug|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Debug|x64.ActiveCfg = Debug|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Debug|x64.Build.0 = Debug|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Debug|x86.ActiveCfg = Debug|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Debug|x86.Build.0 = Debug|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Release_NoSamples|Any CPU.ActiveCfg = Release|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Release_NoSamples|Any CPU.Build.0 = Release|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Release_NoSamples|ARM.ActiveCfg = Release|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Release_NoSamples|ARM.Build.0 = Release|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Release_NoSamples|ARM64.ActiveCfg = Release|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Release_NoSamples|ARM64.Build.0 = Release|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Release_NoSamples|iPhone.ActiveCfg = Release|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Release_NoSamples|iPhone.Build.0 = Release|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Release_NoSamples|iPhoneSimulator.ActiveCfg = Release|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Release_NoSamples|iPhoneSimulator.Build.0 = Release|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Release_NoSamples|x64.ActiveCfg = Release|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Release_NoSamples|x64.Build.0 = Release|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Release_NoSamples|x86.ActiveCfg = Release|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Release_NoSamples|x86.Build.0 = Release|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Release|Any CPU.Build.0 = Release|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Release|ARM.ActiveCfg = Release|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Release|ARM.Build.0 = Release|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Release|ARM64.ActiveCfg = Release|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Release|ARM64.Build.0 = Release|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Release|iPhone.ActiveCfg = Release|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Release|iPhone.Build.0 = Release|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Release|x64.ActiveCfg = Release|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Release|x64.Build.0 = Release|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Release|x86.ActiveCfg = Release|Any CPU + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3}.Release|x86.Build.0 = Release|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Debug|ARM.ActiveCfg = Debug|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Debug|ARM.Build.0 = Debug|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Debug|ARM64.Build.0 = Debug|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Debug|iPhone.Build.0 = Debug|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Debug|x64.ActiveCfg = Debug|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Debug|x64.Build.0 = Debug|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Debug|x86.ActiveCfg = Debug|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Debug|x86.Build.0 = Debug|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Release_NoSamples|Any CPU.ActiveCfg = Release|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Release_NoSamples|Any CPU.Build.0 = Release|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Release_NoSamples|ARM.ActiveCfg = Release|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Release_NoSamples|ARM.Build.0 = Release|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Release_NoSamples|ARM64.ActiveCfg = Release|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Release_NoSamples|ARM64.Build.0 = Release|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Release_NoSamples|iPhone.ActiveCfg = Release|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Release_NoSamples|iPhone.Build.0 = Release|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Release_NoSamples|iPhoneSimulator.ActiveCfg = Release|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Release_NoSamples|iPhoneSimulator.Build.0 = Release|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Release_NoSamples|x64.ActiveCfg = Release|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Release_NoSamples|x64.Build.0 = Release|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Release_NoSamples|x86.ActiveCfg = Release|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Release_NoSamples|x86.Build.0 = Release|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Release|Any CPU.Build.0 = Release|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Release|ARM.ActiveCfg = Release|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Release|ARM.Build.0 = Release|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Release|ARM64.ActiveCfg = Release|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Release|ARM64.Build.0 = Release|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Release|iPhone.ActiveCfg = Release|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Release|iPhone.Build.0 = Release|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Release|x64.ActiveCfg = Release|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Release|x64.Build.0 = Release|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Release|x86.ActiveCfg = Release|Any CPU + {D1179327-BA1D-4554-AA74-36C3EA585863}.Release|x86.Build.0 = Release|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Debug|ARM.ActiveCfg = Debug|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Debug|ARM.Build.0 = Debug|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Debug|ARM64.Build.0 = Debug|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Debug|iPhone.Build.0 = Debug|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Debug|x64.ActiveCfg = Debug|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Debug|x64.Build.0 = Debug|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Debug|x86.ActiveCfg = Debug|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Debug|x86.Build.0 = Debug|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Release_NoSamples|Any CPU.ActiveCfg = Release|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Release_NoSamples|Any CPU.Build.0 = Release|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Release_NoSamples|ARM.ActiveCfg = Release|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Release_NoSamples|ARM.Build.0 = Release|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Release_NoSamples|ARM64.ActiveCfg = Release|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Release_NoSamples|ARM64.Build.0 = Release|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Release_NoSamples|iPhone.ActiveCfg = Release|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Release_NoSamples|iPhone.Build.0 = Release|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Release_NoSamples|iPhoneSimulator.ActiveCfg = Release|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Release_NoSamples|iPhoneSimulator.Build.0 = Release|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Release_NoSamples|x64.ActiveCfg = Release|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Release_NoSamples|x64.Build.0 = Release|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Release_NoSamples|x86.ActiveCfg = Release|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Release_NoSamples|x86.Build.0 = Release|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Release|Any CPU.Build.0 = Release|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Release|ARM.ActiveCfg = Release|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Release|ARM.Build.0 = Release|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Release|ARM64.ActiveCfg = Release|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Release|ARM64.Build.0 = Release|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Release|iPhone.ActiveCfg = Release|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Release|iPhone.Build.0 = Release|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Release|x64.ActiveCfg = Release|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Release|x64.Build.0 = Release|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Release|x86.ActiveCfg = Release|Any CPU + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582}.Release|x86.Build.0 = Release|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Debug|ARM.ActiveCfg = Debug|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Debug|ARM.Build.0 = Debug|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Debug|ARM64.Build.0 = Debug|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Debug|iPhone.Build.0 = Debug|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Debug|x64.ActiveCfg = Debug|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Debug|x64.Build.0 = Debug|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Debug|x86.ActiveCfg = Debug|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Debug|x86.Build.0 = Debug|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Release_NoSamples|Any CPU.ActiveCfg = Release|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Release_NoSamples|Any CPU.Build.0 = Release|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Release_NoSamples|ARM.ActiveCfg = Release|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Release_NoSamples|ARM.Build.0 = Release|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Release_NoSamples|ARM64.ActiveCfg = Release|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Release_NoSamples|ARM64.Build.0 = Release|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Release_NoSamples|iPhone.ActiveCfg = Release|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Release_NoSamples|iPhone.Build.0 = Release|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Release_NoSamples|iPhoneSimulator.ActiveCfg = Release|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Release_NoSamples|iPhoneSimulator.Build.0 = Release|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Release_NoSamples|x64.ActiveCfg = Release|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Release_NoSamples|x64.Build.0 = Release|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Release_NoSamples|x86.ActiveCfg = Release|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Release_NoSamples|x86.Build.0 = Release|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Release|Any CPU.Build.0 = Release|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Release|ARM.ActiveCfg = Release|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Release|ARM.Build.0 = Release|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Release|ARM64.ActiveCfg = Release|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Release|ARM64.Build.0 = Release|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Release|iPhone.ActiveCfg = Release|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Release|iPhone.Build.0 = Release|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Release|x64.ActiveCfg = Release|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Release|x64.Build.0 = Release|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Release|x86.ActiveCfg = Release|Any CPU + {C8C4395C-602F-45AB-AED4-40A8A4EF0089}.Release|x86.Build.0 = Release|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Debug|ARM.ActiveCfg = Debug|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Debug|ARM.Build.0 = Debug|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Debug|ARM64.Build.0 = Debug|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Debug|iPhone.Build.0 = Debug|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Debug|x64.ActiveCfg = Debug|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Debug|x64.Build.0 = Debug|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Debug|x86.ActiveCfg = Debug|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Debug|x86.Build.0 = Debug|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Release_NoSamples|Any CPU.ActiveCfg = Release|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Release_NoSamples|Any CPU.Build.0 = Release|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Release_NoSamples|ARM.ActiveCfg = Release|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Release_NoSamples|ARM.Build.0 = Release|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Release_NoSamples|ARM64.ActiveCfg = Release|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Release_NoSamples|ARM64.Build.0 = Release|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Release_NoSamples|iPhone.ActiveCfg = Release|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Release_NoSamples|iPhone.Build.0 = Release|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Release_NoSamples|iPhoneSimulator.ActiveCfg = Release|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Release_NoSamples|iPhoneSimulator.Build.0 = Release|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Release_NoSamples|x64.ActiveCfg = Release|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Release_NoSamples|x64.Build.0 = Release|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Release_NoSamples|x86.ActiveCfg = Release|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Release_NoSamples|x86.Build.0 = Release|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Release|Any CPU.Build.0 = Release|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Release|ARM.ActiveCfg = Release|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Release|ARM.Build.0 = Release|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Release|ARM64.ActiveCfg = Release|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Release|ARM64.Build.0 = Release|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Release|iPhone.ActiveCfg = Release|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Release|iPhone.Build.0 = Release|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Release|x64.ActiveCfg = Release|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Release|x64.Build.0 = Release|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Release|x86.ActiveCfg = Release|Any CPU + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A}.Release|x86.Build.0 = Release|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Debug|Any CPU.Build.0 = Debug|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Debug|ARM.ActiveCfg = Debug|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Debug|ARM.Build.0 = Debug|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Debug|ARM64.Build.0 = Debug|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Debug|iPhone.Build.0 = Debug|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Debug|x64.ActiveCfg = Debug|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Debug|x64.Build.0 = Debug|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Debug|x86.ActiveCfg = Debug|x86 + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Debug|x86.Build.0 = Debug|x86 + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Release_NoSamples|Any CPU.ActiveCfg = Release|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Release_NoSamples|Any CPU.Build.0 = Release|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Release_NoSamples|ARM.ActiveCfg = Release|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Release_NoSamples|ARM.Build.0 = Release|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Release_NoSamples|ARM64.ActiveCfg = Release|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Release_NoSamples|ARM64.Build.0 = Release|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Release_NoSamples|iPhone.ActiveCfg = Release|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Release_NoSamples|iPhone.Build.0 = Release|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Release_NoSamples|iPhoneSimulator.ActiveCfg = Release|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Release_NoSamples|iPhoneSimulator.Build.0 = Release|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Release_NoSamples|x64.ActiveCfg = Release|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Release_NoSamples|x64.Build.0 = Release|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Release_NoSamples|x86.ActiveCfg = Release|x86 + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Release_NoSamples|x86.Build.0 = Release|x86 + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Release|Any CPU.ActiveCfg = Release|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Release|Any CPU.Build.0 = Release|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Release|ARM.ActiveCfg = Release|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Release|ARM.Build.0 = Release|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Release|ARM64.ActiveCfg = Release|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Release|ARM64.Build.0 = Release|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Release|iPhone.ActiveCfg = Release|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Release|iPhone.Build.0 = Release|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Release|x64.ActiveCfg = Release|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Release|x64.Build.0 = Release|Any CPU + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Release|x86.ActiveCfg = Release|x86 + {27B81C58-B74E-4BC9-BD17-1811C82D0507}.Release|x86.Build.0 = Release|x86 + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Debug|ARM.ActiveCfg = Debug|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Debug|ARM.Build.0 = Debug|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Debug|ARM64.Build.0 = Debug|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Debug|iPhone.Build.0 = Debug|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Debug|x64.ActiveCfg = Debug|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Debug|x64.Build.0 = Debug|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Debug|x86.ActiveCfg = Debug|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Debug|x86.Build.0 = Debug|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Release_NoSamples|Any CPU.ActiveCfg = Release|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Release_NoSamples|Any CPU.Build.0 = Release|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Release_NoSamples|ARM.ActiveCfg = Release|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Release_NoSamples|ARM.Build.0 = Release|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Release_NoSamples|ARM64.ActiveCfg = Release|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Release_NoSamples|ARM64.Build.0 = Release|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Release_NoSamples|iPhone.ActiveCfg = Release|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Release_NoSamples|iPhone.Build.0 = Release|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Release_NoSamples|iPhoneSimulator.ActiveCfg = Release|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Release_NoSamples|iPhoneSimulator.Build.0 = Release|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Release_NoSamples|x64.ActiveCfg = Release|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Release_NoSamples|x64.Build.0 = Release|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Release_NoSamples|x86.ActiveCfg = Release|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Release_NoSamples|x86.Build.0 = Release|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Release|Any CPU.Build.0 = Release|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Release|ARM.ActiveCfg = Release|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Release|ARM.Build.0 = Release|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Release|ARM64.ActiveCfg = Release|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Release|ARM64.Build.0 = Release|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Release|iPhone.ActiveCfg = Release|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Release|iPhone.Build.0 = Release|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Release|x64.ActiveCfg = Release|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Release|x64.Build.0 = Release|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Release|x86.ActiveCfg = Release|Any CPU + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4}.Release|x86.Build.0 = Release|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Debug|ARM.ActiveCfg = Debug|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Debug|ARM.Build.0 = Debug|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Debug|ARM64.Build.0 = Debug|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Debug|iPhone.Build.0 = Debug|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Debug|x64.ActiveCfg = Debug|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Debug|x64.Build.0 = Debug|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Debug|x86.ActiveCfg = Debug|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Debug|x86.Build.0 = Debug|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Release_NoSamples|Any CPU.ActiveCfg = Release|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Release_NoSamples|Any CPU.Build.0 = Release|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Release_NoSamples|ARM.ActiveCfg = Release|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Release_NoSamples|ARM.Build.0 = Release|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Release_NoSamples|ARM64.ActiveCfg = Release|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Release_NoSamples|ARM64.Build.0 = Release|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Release_NoSamples|iPhone.ActiveCfg = Release|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Release_NoSamples|iPhone.Build.0 = Release|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Release_NoSamples|iPhoneSimulator.ActiveCfg = Release|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Release_NoSamples|iPhoneSimulator.Build.0 = Release|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Release_NoSamples|x64.ActiveCfg = Release|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Release_NoSamples|x64.Build.0 = Release|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Release_NoSamples|x86.ActiveCfg = Release|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Release_NoSamples|x86.Build.0 = Release|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Release|Any CPU.Build.0 = Release|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Release|ARM.ActiveCfg = Release|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Release|ARM.Build.0 = Release|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Release|ARM64.ActiveCfg = Release|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Release|ARM64.Build.0 = Release|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Release|iPhone.ActiveCfg = Release|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Release|iPhone.Build.0 = Release|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Release|x64.ActiveCfg = Release|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Release|x64.Build.0 = Release|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Release|x86.ActiveCfg = Release|Any CPU + {902AFE53-B676-4F67-9F9E-67423439A6AC}.Release|x86.Build.0 = Release|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Debug|ARM.ActiveCfg = Debug|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Debug|ARM.Build.0 = Debug|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Debug|ARM64.Build.0 = Debug|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Debug|iPhone.Build.0 = Debug|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Debug|x64.ActiveCfg = Debug|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Debug|x64.Build.0 = Debug|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Debug|x86.ActiveCfg = Debug|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Debug|x86.Build.0 = Debug|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Release_NoSamples|Any CPU.ActiveCfg = Release|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Release_NoSamples|Any CPU.Build.0 = Release|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Release_NoSamples|ARM.ActiveCfg = Release|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Release_NoSamples|ARM.Build.0 = Release|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Release_NoSamples|ARM64.ActiveCfg = Release|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Release_NoSamples|ARM64.Build.0 = Release|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Release_NoSamples|iPhone.ActiveCfg = Release|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Release_NoSamples|iPhone.Build.0 = Release|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Release_NoSamples|iPhoneSimulator.ActiveCfg = Release|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Release_NoSamples|iPhoneSimulator.Build.0 = Release|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Release_NoSamples|x64.ActiveCfg = Release|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Release_NoSamples|x64.Build.0 = Release|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Release_NoSamples|x86.ActiveCfg = Release|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Release_NoSamples|x86.Build.0 = Release|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Release|Any CPU.Build.0 = Release|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Release|ARM.ActiveCfg = Release|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Release|ARM.Build.0 = Release|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Release|ARM64.ActiveCfg = Release|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Release|ARM64.Build.0 = Release|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Release|iPhone.ActiveCfg = Release|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Release|iPhone.Build.0 = Release|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Release|x64.ActiveCfg = Release|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Release|x64.Build.0 = Release|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Release|x86.ActiveCfg = Release|Any CPU + {BF3E32F0-67BF-4406-8348-FC6315FB360B}.Release|x86.Build.0 = Release|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Debug|ARM.ActiveCfg = Debug|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Debug|ARM.Build.0 = Debug|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Debug|ARM64.Build.0 = Debug|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Debug|iPhone.Build.0 = Debug|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Debug|x64.ActiveCfg = Debug|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Debug|x64.Build.0 = Debug|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Debug|x86.ActiveCfg = Debug|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Debug|x86.Build.0 = Debug|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Release_NoSamples|Any CPU.ActiveCfg = Release|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Release_NoSamples|Any CPU.Build.0 = Release|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Release_NoSamples|ARM.ActiveCfg = Release|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Release_NoSamples|ARM.Build.0 = Release|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Release_NoSamples|ARM64.ActiveCfg = Release|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Release_NoSamples|ARM64.Build.0 = Release|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Release_NoSamples|iPhone.ActiveCfg = Release|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Release_NoSamples|iPhone.Build.0 = Release|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Release_NoSamples|iPhoneSimulator.ActiveCfg = Release|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Release_NoSamples|iPhoneSimulator.Build.0 = Release|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Release_NoSamples|x64.ActiveCfg = Release|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Release_NoSamples|x64.Build.0 = Release|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Release_NoSamples|x86.ActiveCfg = Release|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Release_NoSamples|x86.Build.0 = Release|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Release|Any CPU.Build.0 = Release|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Release|ARM.ActiveCfg = Release|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Release|ARM.Build.0 = Release|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Release|ARM64.ActiveCfg = Release|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Release|ARM64.Build.0 = Release|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Release|iPhone.ActiveCfg = Release|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Release|iPhone.Build.0 = Release|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Release|x64.ActiveCfg = Release|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Release|x64.Build.0 = Release|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Release|x86.ActiveCfg = Release|Any CPU + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8}.Release|x86.Build.0 = Release|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Debug|ARM.ActiveCfg = Debug|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Debug|ARM.Build.0 = Debug|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Debug|ARM64.Build.0 = Debug|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Debug|iPhone.Build.0 = Debug|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Debug|x64.ActiveCfg = Debug|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Debug|x64.Build.0 = Debug|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Debug|x86.ActiveCfg = Debug|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Debug|x86.Build.0 = Debug|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Release_NoSamples|Any CPU.ActiveCfg = Release|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Release_NoSamples|Any CPU.Build.0 = Release|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Release_NoSamples|ARM.ActiveCfg = Release|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Release_NoSamples|ARM.Build.0 = Release|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Release_NoSamples|ARM64.ActiveCfg = Release|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Release_NoSamples|ARM64.Build.0 = Release|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Release_NoSamples|iPhone.ActiveCfg = Release|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Release_NoSamples|iPhone.Build.0 = Release|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Release_NoSamples|iPhoneSimulator.ActiveCfg = Release|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Release_NoSamples|iPhoneSimulator.Build.0 = Release|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Release_NoSamples|x64.ActiveCfg = Release|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Release_NoSamples|x64.Build.0 = Release|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Release_NoSamples|x86.ActiveCfg = Release|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Release_NoSamples|x86.Build.0 = Release|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Release|Any CPU.Build.0 = Release|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Release|ARM.ActiveCfg = Release|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Release|ARM.Build.0 = Release|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Release|ARM64.ActiveCfg = Release|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Release|ARM64.Build.0 = Release|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Release|iPhone.ActiveCfg = Release|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Release|iPhone.Build.0 = Release|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Release|x64.ActiveCfg = Release|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Release|x64.Build.0 = Release|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Release|x86.ActiveCfg = Release|Any CPU + {73131285-509B-4019-8047-3F3FCA4FFDC8}.Release|x86.Build.0 = Release|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Debug|ARM.ActiveCfg = Debug|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Debug|ARM.Build.0 = Debug|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Debug|ARM64.Build.0 = Debug|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Debug|iPhone.Build.0 = Debug|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Debug|x64.ActiveCfg = Debug|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Debug|x64.Build.0 = Debug|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Debug|x86.ActiveCfg = Debug|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Debug|x86.Build.0 = Debug|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Release_NoSamples|Any CPU.ActiveCfg = Release|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Release_NoSamples|Any CPU.Build.0 = Release|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Release_NoSamples|ARM.ActiveCfg = Release|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Release_NoSamples|ARM.Build.0 = Release|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Release_NoSamples|ARM64.ActiveCfg = Release|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Release_NoSamples|ARM64.Build.0 = Release|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Release_NoSamples|iPhone.ActiveCfg = Release|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Release_NoSamples|iPhone.Build.0 = Release|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Release_NoSamples|iPhoneSimulator.ActiveCfg = Release|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Release_NoSamples|iPhoneSimulator.Build.0 = Release|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Release_NoSamples|x64.ActiveCfg = Release|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Release_NoSamples|x64.Build.0 = Release|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Release_NoSamples|x86.ActiveCfg = Release|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Release_NoSamples|x86.Build.0 = Release|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Release|Any CPU.Build.0 = Release|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Release|ARM.ActiveCfg = Release|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Release|ARM.Build.0 = Release|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Release|ARM64.ActiveCfg = Release|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Release|ARM64.Build.0 = Release|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Release|iPhone.ActiveCfg = Release|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Release|iPhone.Build.0 = Release|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Release|x64.ActiveCfg = Release|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Release|x64.Build.0 = Release|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Release|x86.ActiveCfg = Release|Any CPU + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5}.Release|x86.Build.0 = Release|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Debug|ARM.ActiveCfg = Debug|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Debug|ARM.Build.0 = Debug|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Debug|ARM64.Build.0 = Debug|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Debug|iPhone.Build.0 = Debug|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Debug|x64.ActiveCfg = Debug|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Debug|x64.Build.0 = Debug|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Debug|x86.ActiveCfg = Debug|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Debug|x86.Build.0 = Debug|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Release_NoSamples|Any CPU.ActiveCfg = Release|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Release_NoSamples|Any CPU.Build.0 = Release|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Release_NoSamples|ARM.ActiveCfg = Release|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Release_NoSamples|ARM.Build.0 = Release|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Release_NoSamples|ARM64.ActiveCfg = Release|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Release_NoSamples|ARM64.Build.0 = Release|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Release_NoSamples|iPhone.ActiveCfg = Release|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Release_NoSamples|iPhone.Build.0 = Release|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Release_NoSamples|iPhoneSimulator.ActiveCfg = Release|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Release_NoSamples|iPhoneSimulator.Build.0 = Release|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Release_NoSamples|x64.ActiveCfg = Release|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Release_NoSamples|x64.Build.0 = Release|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Release_NoSamples|x86.ActiveCfg = Release|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Release_NoSamples|x86.Build.0 = Release|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Release|Any CPU.Build.0 = Release|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Release|ARM.ActiveCfg = Release|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Release|ARM.Build.0 = Release|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Release|ARM64.ActiveCfg = Release|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Release|ARM64.Build.0 = Release|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Release|iPhone.ActiveCfg = Release|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Release|iPhone.Build.0 = Release|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Release|x64.ActiveCfg = Release|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Release|x64.Build.0 = Release|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Release|x86.ActiveCfg = Release|Any CPU + {A95B814B-6BEC-4C06-BC8A-04E62FD63245}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2381,7 +3396,30 @@ Global {C598D6FA-81F1-4B54-8028-ED8987F88FFA} = {62907CED-829B-441B-893A-9F663342F6EA} {99D067E3-E70B-45F1-BC3C-931FBD89FD95} = {416684CF-A4E3-4079-B380-3FF0B00E433C} {2569663D-293A-4A1D-BB84-AA8C7B4B7F92} = {E872CD33-A455-4DC4-8A87-5FEEC1C39A44} + {E52D214F-8A34-43C8-95D9-0A1F74F9847E} = {416684CF-A4E3-4079-B380-3FF0B00E433C} + {5B7EBD0B-7D02-4CF3-8F90-34E08C626F2C} = {416684CF-A4E3-4079-B380-3FF0B00E433C} + {2FA71F02-1C31-4307-B6E1-5CC8FD5D905C} = {416684CF-A4E3-4079-B380-3FF0B00E433C} + {0AC8FEA5-B89C-47C5-8169-77E053F10274} = {416684CF-A4E3-4079-B380-3FF0B00E433C} + {136055A3-C008-4EFA-9FA0-50B20B87B09A} = {416684CF-A4E3-4079-B380-3FF0B00E433C} + {304F9F00-11E8-46A4-992B-32D9581DB756} = {E872CD33-A455-4DC4-8A87-5FEEC1C39A44} {CE3CD566-7D8C-474C-A554-F5A4A698EA48} = {62907CED-829B-441B-893A-9F663342F6EA} + {C1543178-9756-4739-BF96-30633E07B2ED} = {E872CD33-A455-4DC4-8A87-5FEEC1C39A44} + {D13CB6DD-3934-4858-8BBE-FDCF1B699789} = {416684CF-A4E3-4079-B380-3FF0B00E433C} + {07C6B075-9EA2-4B03-B756-B7D607BC1844} = {416684CF-A4E3-4079-B380-3FF0B00E433C} + {E1AFCB3E-0FD1-4063-BC2E-5B76670D5B16} = {416684CF-A4E3-4079-B380-3FF0B00E433C} + {5536CE52-68CC-4C6A-A7F2-7BB24F2A47F3} = {416684CF-A4E3-4079-B380-3FF0B00E433C} + {D1179327-BA1D-4554-AA74-36C3EA585863} = {416684CF-A4E3-4079-B380-3FF0B00E433C} + {C24F4B8B-7C5F-4126-A38A-F6F5CF461582} = {416684CF-A4E3-4079-B380-3FF0B00E433C} + {C8C4395C-602F-45AB-AED4-40A8A4EF0089} = {995C1054-AB61-42EE-9A17-C32155BD6D13} + {4A03CFBB-4D4E-4589-BD51-69B7251A2A0A} = {995C1054-AB61-42EE-9A17-C32155BD6D13} + {27B81C58-B74E-4BC9-BD17-1811C82D0507} = {995C1054-AB61-42EE-9A17-C32155BD6D13} + {F61C6C86-F6B4-44B3-9821-72E7EBD2A3E4} = {416684CF-A4E3-4079-B380-3FF0B00E433C} + {902AFE53-B676-4F67-9F9E-67423439A6AC} = {E872CD33-A455-4DC4-8A87-5FEEC1C39A44} + {BF3E32F0-67BF-4406-8348-FC6315FB360B} = {E872CD33-A455-4DC4-8A87-5FEEC1C39A44} + {AE25869B-B4C2-4F27-8260-A0B2B96B1DF8} = {416684CF-A4E3-4079-B380-3FF0B00E433C} + {73131285-509B-4019-8047-3F3FCA4FFDC8} = {62907CED-829B-441B-893A-9F663342F6EA} + {DD7DAEC9-8F20-440A-81CD-8ED00DBC96D5} = {416684CF-A4E3-4079-B380-3FF0B00E433C} + {A95B814B-6BEC-4C06-BC8A-04E62FD63245} = {416684CF-A4E3-4079-B380-3FF0B00E433C} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {9B2608F4-D82B-4B72-B399-33E822DF01D0} diff --git a/src/Uno.UI/AssemblyInfo.cs b/src/Uno.UI/AssemblyInfo.cs index 76b37349fa81..ffd5fd6e446b 100644 --- a/src/Uno.UI/AssemblyInfo.cs +++ b/src/Uno.UI/AssemblyInfo.cs @@ -6,7 +6,10 @@ [assembly: InternalsVisibleTo("Uno.UI.Toolkit")] [assembly: InternalsVisibleTo("Uno.UI.RemoteControl")] [assembly: InternalsVisibleTo("Uno.UI.RuntimeTests")] +[assembly: InternalsVisibleTo("Uno.UI.RuntimeTests.Wasm")] +[assembly: InternalsVisibleTo("Uno.UI.RuntimeTests.Skia")] [assembly: InternalsVisibleTo("SamplesApp")] [assembly: InternalsVisibleTo("SamplesApp.Droid")] [assembly: InternalsVisibleTo("SamplesApp.macOS")] [assembly: InternalsVisibleTo("SamplesApp.Wasm")] +[assembly: InternalsVisibleTo("SamplesApp.Skia")] diff --git a/src/Uno.UI/Extensions/ViewExtensions.wasmnet.cs b/src/Uno.UI/Extensions/ViewExtensions.wasmnet.cs index 743116df3b23..e8519391d54b 100644 --- a/src/Uno.UI/Extensions/ViewExtensions.wasmnet.cs +++ b/src/Uno.UI/Extensions/ViewExtensions.wasmnet.cs @@ -1,4 +1,4 @@ -#if NET461 || __WASM__ +#if NET461 || NETSTANDARD2_0 using System; using System.Collections.Generic; using System.Linq; diff --git a/src/Uno.UI/Extensions/ViewHelper.net.cs b/src/Uno.UI/Extensions/ViewHelper.cs similarity index 94% rename from src/Uno.UI/Extensions/ViewHelper.net.cs rename to src/Uno.UI/Extensions/ViewHelper.cs index c254e0d712ef..d9e5a4d91ccc 100644 --- a/src/Uno.UI/Extensions/ViewHelper.net.cs +++ b/src/Uno.UI/Extensions/ViewHelper.cs @@ -1,4 +1,5 @@ -using System; +#if NET461 || NETSTANDARD +using System; using System.Linq; using System.Runtime.CompilerServices; using Windows.Foundation; @@ -32,3 +33,4 @@ public static Point LogicalToPhysicalPixels(this Point point) => point; } } +#endif diff --git a/src/Uno.UI/Extensions/ViewHelper.wasm.cs b/src/Uno.UI/Extensions/ViewHelper.wasm.cs deleted file mode 100644 index c254e0d712ef..000000000000 --- a/src/Uno.UI/Extensions/ViewHelper.wasm.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.Linq; -using System.Runtime.CompilerServices; -using Windows.Foundation; - -namespace Uno.UI -{ - public static class ViewHelper - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Size PhysicalToLogicalPixels(this Size size) - => size; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Size LogicalToPhysicalPixels(this Size size) - => size; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rect LogicalToPhysicalPixels(this Rect rect) - => rect; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rect PhysicalToLogicalPixels(this Rect rect) - => rect; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Point PhysicalToLogicalPixels(this Point point) - => point; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Point LogicalToPhysicalPixels(this Point point) - => point; - } -} diff --git a/src/Uno.UI/FeatureConfiguration.cs b/src/Uno.UI/FeatureConfiguration.cs index 856624ecf63f..05bddba5b827 100644 --- a/src/Uno.UI/FeatureConfiguration.cs +++ b/src/Uno.UI/FeatureConfiguration.cs @@ -153,9 +153,8 @@ public static class FrameworkElement public static bool AndroidUseManagedLoadedUnloaded { get; set; } = true; #endif -#if __WASM__ /// - /// Controls the propagation of and + /// [WebAssembly Only] Controls the propagation of and /// events through managed /// or native visual tree traversal. /// @@ -164,7 +163,6 @@ public static class FrameworkElement /// Setting it to avoids the use of costly JavaScript->C# interop. /// public static bool WasmUseManagedLoadedUnloaded { get; set; } = true; -#endif } public static class Image @@ -178,14 +176,12 @@ public static class Image public static class Interop { -#if __WASM__ /// - /// Used to control the behavior of the C#/Javascript interop. Setting this + /// [WebAssembly Only] Used to control the behavior of the C#/Javascript interop. Setting this /// flag to true forces the use of the Javascript eval mode, instead of binary interop. /// This flag has no effect when running in hosted mode. /// public static bool ForceJavascriptInterop { get; set; } = false; -#endif } public static class Binding @@ -290,7 +286,7 @@ public static class Style public static class TextBlock { /// - /// Determines if the measure cache is enabled. (WASM only) + /// [WebAssembly Only] Determines if the measure cache is enabled. /// public static bool IsMeasureCacheEnabled { get; set; } = true; } @@ -366,21 +362,20 @@ public static class UIElement /// public static bool ShowClippingBounds { get; set; } = false; -#if __WASM__ /// - /// Enable the assignation of the "xamlname", "xuid" and "xamlautomationid" attributes on DOM elements created + /// [WebAssembly Only] Enable the assignation of the "xamlname", "xuid" and "xamlautomationid" attributes on DOM elements created /// from the XAML visual tree. This enables tools such as Puppeteer to select elements /// in the DOM for automation purposes. /// public static bool AssignDOMXamlName { get; set; } = false; /// - /// Enable UIElement.ToString() to return the element's unique ID + /// [WebAssembly Only] Enable UIElement.ToString() to return the element's unique ID /// public static bool RenderToStringWithId { get; set; } = true; /// - /// Enables the assignation of properties from the XAML visual tree as DOM attributes: Height -> "xamlheight", + /// [WebAssembly Only] Enables the assignation of properties from the XAML visual tree as DOM attributes: Height -> "xamlheight", /// HorizontalAlignment -> "xamlhorizontalalignment" etc. /// /// @@ -390,7 +385,8 @@ public static class UIElement /// the values change subsequently. This restriction doesn't apply to debug Uno builds. /// public static bool AssignDOMXamlProperties { get; set; } = false; -#elif __ANDROID__ + +#if __ANDROID__ /// /// When this is set, non-UIElements will always be clipped to their bounds ( will /// always be set to true on their parent). diff --git a/src/Uno.UI/LinkerDefinition.Wasm.xml b/src/Uno.UI/LinkerDefinition.Wasm.xml index 6e3f70c0d9f2..bf52e6088fa0 100644 --- a/src/Uno.UI/LinkerDefinition.Wasm.xml +++ b/src/Uno.UI/LinkerDefinition.Wasm.xml @@ -1,59 +1,2 @@  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Uno.UI/Media/NativeRenderTransformAdapter.Skia.cs b/src/Uno.UI/Media/NativeRenderTransformAdapter.Skia.cs new file mode 100644 index 000000000000..a64aed33af06 --- /dev/null +++ b/src/Uno.UI/Media/NativeRenderTransformAdapter.Skia.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Numerics; +using System.Text; +using Uno.Extensions; + +namespace Uno.UI.Media +{ + partial class NativeRenderTransformAdapter + { + partial void Initialized() + { + // Apply the transform as soon as its been declared + Update(); + } + + partial void Apply(bool isSizeChanged, bool isOriginChanged) + { + if (isSizeChanged) + { + // As we use the 'transform-origin', the transform matrix is independent of the size of the control + } + else if (isOriginChanged) + { + Owner.Visual.CenterPoint = new Vector3((float)CurrentOrigin.X, (float)CurrentOrigin.Y, 0); + return; + } + else + { + Owner.Visual.TransformMatrix = new Matrix4x4(Transform.MatrixCore); + } + } + + partial void Cleanup() + { + Owner.Visual.TransformMatrix = Matrix4x4.Identity; + } + } +} diff --git a/src/Uno.UI/Media/NativeRenderTransformAdapter.cs b/src/Uno.UI/Media/NativeRenderTransformAdapter.cs index 881616257c6a..b3b761d67e64 100644 --- a/src/Uno.UI/Media/NativeRenderTransformAdapter.cs +++ b/src/Uno.UI/Media/NativeRenderTransformAdapter.cs @@ -12,7 +12,7 @@ using _View = UIKit.UIView; #elif __MACOS__ using _View = AppKit.NSView; -#elif __WASM__ +#elif NETSTANDARD using _View = Windows.UI.Xaml.UIElement; #else using _View = System.Object; diff --git a/src/Uno.UI/Media/PathStreamGeometryContext.cs b/src/Uno.UI/Media/PathStreamGeometryContext.cs index 2c1a0ef735f2..b9b0fba244a3 100644 --- a/src/Uno.UI/Media/PathStreamGeometryContext.cs +++ b/src/Uno.UI/Media/PathStreamGeometryContext.cs @@ -17,6 +17,8 @@ using Android.Graphics.Drawables.Shapes; using Path = Android.Graphics.Path; using Uno.UI; +#elif __SKIA__ +using Path = Windows.UI.Composition.SkiaGeometrySource2D; #else using Path = System.Object; #endif @@ -41,6 +43,8 @@ public override void BeginFigure(Point startPoint, bool isFilled, bool isClosed) #elif __ANDROID__ var physicalStartPoint = LogicalToPhysicalNoRounding(startPoint); bezierPath.MoveTo((float)physicalStartPoint.X, (float)physicalStartPoint.Y); +#elif __SKIA__ + bezierPath.Geometry.MoveTo(new SkiaSharp.SKPoint((float)startPoint.X, (float)startPoint.Y)); #endif _points.Add(startPoint); @@ -55,6 +59,8 @@ public override void LineTo(Point point, bool isStroked, bool isSmoothJoin) #elif __ANDROID__ var physicalPoint = LogicalToPhysicalNoRounding(point); bezierPath.LineTo((float)physicalPoint.X, (float)physicalPoint.Y); +#elif __SKIA__ + bezierPath.Geometry.LineTo((float)point.X, (float)point.Y); #endif _points.Add(point); @@ -71,6 +77,8 @@ public override void BezierTo(Point point1, Point point2, Point point3, bool isS var physicalPoint2 = LogicalToPhysicalNoRounding(point2); var physicalPoint3 = LogicalToPhysicalNoRounding(point3); bezierPath.CubicTo((float)physicalPoint1.X, (float)physicalPoint1.Y, (float)physicalPoint2.X, (float)physicalPoint2.Y, (float)physicalPoint3.X, (float)physicalPoint3.Y); +#elif __SKIA__ + bezierPath.Geometry.CubicTo((float)point1.X, (float)point1.Y, (float)point2.X, (float)point2.Y, (float)point3.X, (float)point3.Y); #endif _points.Add(point3); } @@ -92,6 +100,8 @@ public override void QuadraticBezierTo(Point point1, Point point2, bool isStroke var physicalPoint1 = LogicalToPhysicalNoRounding(point1); var physicalPoint2 = LogicalToPhysicalNoRounding(point2); bezierPath.QuadTo((float)physicalPoint1.X, (float)physicalPoint1.Y, (float)physicalPoint2.X, (float)physicalPoint2.Y); +#elif __SKIA__ + bezierPath.Geometry.QuadTo((float)point1.X, (float)point1.Y, (float)point2.X, (float)point2.Y); #endif _points.Add(point2); @@ -150,6 +160,29 @@ public override void ArcTo(Point point, Size size, double rotationAngle, bool is (float)startAngle, (float)sweepAngle ); +#elif __SKIA__ + var sweepAngle = endAngle - startAngle; + + // Convert to degrees + startAngle = startAngle * (180 / PI); + sweepAngle = sweepAngle * (180 / PI); + + // Invert y-axis + startAngle = (startAngle + 360) % 360; + sweepAngle = (sweepAngle + 360) % 360; + + // Apply direction + if (sweepDirection == SweepDirection.Counterclockwise) + { + sweepAngle -= 360; + } + + bezierPath.Geometry.ArcTo( + new SkiaSharp.SKRect((float)circle.Left, (float)circle.Top, (float)circle.Right, (float)circle.Bottom), + (float)startAngle, + (float)sweepAngle, + false + ); #endif _points.Add(point); diff --git a/src/Uno.UI/Media/StreamGeometry.cs b/src/Uno.UI/Media/StreamGeometry.cs index 734a42c1113f..a654ee175513 100644 --- a/src/Uno.UI/Media/StreamGeometry.cs +++ b/src/Uno.UI/Media/StreamGeometry.cs @@ -20,6 +20,8 @@ using Path = AppKit.NSBezierPath; #elif XAMARIN_ANDROID using Android.Graphics; +#elif __SKIA__ +using Path = Windows.UI.Composition.SkiaGeometrySource2D; #else using Path = System.Object; #endif @@ -43,6 +45,14 @@ internal void Close(Path bezierPath_) bezierPath = bezierPath_; } +#if __SKIA__ + internal Path GetGeometrySource2D() + { + return bezierPath; + } +#endif + + #if XAMARIN_IOS_UNIFIED || XAMARIN_IOS || __MACOS__ public override UIImage ToNativeImage () { @@ -127,6 +137,6 @@ public override void Dispose() #endif } - #endregion +#endregion } } diff --git a/src/Uno.UI/MixinGeneration.targets b/src/Uno.UI/MixinGeneration.targets new file mode 100644 index 000000000000..951ba30ae95b --- /dev/null +++ b/src/Uno.UI/MixinGeneration.targets @@ -0,0 +1,195 @@ + + + + + $(MSBuildThisFileDirectory)..\T4Generator\bin\$(Configuration) + $(T4Path)\T4Generator.exe + + $(TargetFramework.ToLower().StartsWith('monoandroid')) + $(TargetFramework.ToLower().StartsWith('xamarinios')) + $(TargetFramework.ToLower().StartsWith('xamarinmac')) + + + <_IsUnoUIProjectForMixins Condition="'$(MSBuildProjectName)'=='Uno.UI'">true + + + + + false + true + TargetFramework + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TextTemplatingFileGenerator + %(RecursiveDir)%(Filename).g.cs + + + + True + True + %(RecursiveDir)$([System.String]::new(%(FileName)).Replace('.g','.tt')) + + + %(RecursiveDir)$([System.String]::new(%(FileName)).Replace('.g','.tt')) + + + + + + + + + + + + TextTemplatingFileGenerator + %(RecursiveDir)%(Filename).g.cs + + + True + True + %(RecursiveDir)$([System.String]::new(%(FileName)).Replace('.g','.tt')) + + + %(RecursiveDir)$([System.String]::new(%(FileName)).Replace('.g','.tt')) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + InputFile=$(MSBuildThisFileDirectory)Mixins\Android\BaseActivity.Callbacks.tt;OutputPath=$(MSBuildThisFileDirectory)Mixins\Android;Configuration=$(Configuration);Platform=$(Platform) + + + InputFile=$(MSBuildThisFileDirectory)Mixins\Android\FrameworkElementMixins.tt;OutputPath=$(MSBuildThisFileDirectory)Mixins\Android;Configuration=$(Configuration);Platform=$(Platform) + + + InputFile=$(MSBuildThisFileDirectory)Mixins\Android\VisualStatesMixins.tt;OutputPath=$(MSBuildThisFileDirectory)Mixins\Android;Configuration=$(Configuration);Platform=$(Platform) + + + InputFile=$(MSBuildThisFileDirectory)Mixins\DependencyPropertyMixins.tt;OutputPath=$(MSBuildThisFileDirectory)Mixins;Configuration=$(Configuration);Platform=$(Platform) + + + InputFile=$(MSBuildThisFileDirectory)Mixins\iOS\FrameworkElementMixins.tt;OutputPath=$(MSBuildThisFileDirectory)Mixins\iOS;Configuration=$(Configuration);Platform=$(Platform) + + + InputFile=$(MSBuildThisFileDirectory)Mixins\iOS\VisualStatesMixins.tt;OutputPath=$(MSBuildThisFileDirectory)Mixins\iOS;Configuration=$(Configuration);Platform=$(Platform) + + + InputFile=$(MSBuildThisFileDirectory)Mixins\macOS\FrameworkElementMixins.tt;OutputPath=$(MSBuildThisFileDirectory)Mixins\macOS;Configuration=$(Configuration);Platform=$(Platform) + + + InputFile=$(MSBuildThisFileDirectory)Mixins\macOS\VisualStatesMixins.tt;OutputPath=$(MSBuildThisFileDirectory)Mixins\macOS;Configuration=$(Configuration);Platform=$(Platform) + + + InputFile=$(MSBuildThisFileDirectory)Mixins\Wasm\VisualStatesMixins.tt;OutputPath=$(MSBuildThisFileDirectory)Mixins\Wasm;Configuration=$(Configuration);Platform=$(Platform) + + + InputFile=$(MSBuildThisFileDirectory)Mixins\net461\VisualStatesMixins.tt;OutputPath=$(MSBuildThisFileDirectory)Mixins\net461;Configuration=$(Configuration);Platform=$(Platform) + + + + + + + + + + + + + + + + + + <_T4AOTFiles Include="$(T4Path)/*.dll" Exclude="$(T4Path)/System.Text.Encoding.CodePages.dll" /> + + + + + + + + + + diff --git a/src/Uno.UI/Mixins/Wasm/VisualStatesMixins.tt b/src/Uno.UI/Mixins/Wasm/VisualStatesMixins.tt index 23954f2bb68c..2b229906e184 100644 --- a/src/Uno.UI/Mixins/Wasm/VisualStatesMixins.tt +++ b/src/Uno.UI/Mixins/Wasm/VisualStatesMixins.tt @@ -1,6 +1,6 @@ <#@template language="C#"#> <#@output extension="g.cs" #> -#if __WASM__ +#if NETSTANDARD2_0 <# AddClass("Windows.UI.Xaml.Controls", "TextBox", hasCommonStates: true, hasCommonOverState: true, hasCommonFocusedState: true); AddClass("Windows.UI.Xaml.Controls", "Button", hasCommonStates: true, hasCommonOverState: true, hasCommonPressedState: true); diff --git a/src/Uno.UI/Mock/ArbitraryShapeBase.netstdref.cs b/src/Uno.UI/Mock/ArbitraryShapeBase.netstdref.cs new file mode 100644 index 000000000000..6f4997418cfa --- /dev/null +++ b/src/Uno.UI/Mock/ArbitraryShapeBase.netstdref.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using Uno.Disposables; +using System.Text; + +namespace Windows.UI.Xaml.Shapes +{ + public abstract partial class ArbitraryShapeBase : Shape + { + private IDisposable BuildDrawableLayer() => null; + + private Windows.Foundation.Size GetActualSize() => default; + } +} diff --git a/src/Uno.UI/Mock/Border.netstdref.cs b/src/Uno.UI/Mock/Border.netstdref.cs new file mode 100644 index 000000000000..653a90e7ee44 --- /dev/null +++ b/src/Uno.UI/Mock/Border.netstdref.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Windows.UI.Xaml.Controls +{ + public partial class Border + { + partial void OnChildChangedPartial(UIElement previousValue, UIElement newValue) + { + } + + bool ICustomClippingElement.AllowClippingToLayoutSlot => !(Child is UIElement ue) || ue.RenderTransform == null; + bool ICustomClippingElement.ForceClippingToLayoutSlot => CornerRadius != CornerRadius.None; + } +} diff --git a/src/Uno.UI/Mock/Brush.netstdref.cs b/src/Uno.UI/Mock/Brush.netstdref.cs new file mode 100644 index 000000000000..d98dc65316a1 --- /dev/null +++ b/src/Uno.UI/Mock/Brush.netstdref.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Uno.Extensions; +using Uno.Disposables; +using System.Drawing; + +namespace Windows.UI.Xaml.Media +{ + //Android partial for Brush + public abstract partial class Brush + { + internal static IDisposable AssignAndObserveBrush(Brush b, Action colorSetter, Action imageBrushCallback = null) + { + return null; + } + + } +} diff --git a/src/Uno.UI/Mock/Color.netstdref.cs b/src/Uno.UI/Mock/Color.netstdref.cs new file mode 100644 index 000000000000..31313a5e0cdb --- /dev/null +++ b/src/Uno.UI/Mock/Color.netstdref.cs @@ -0,0 +1,14 @@ +using Uno; +using Uno.Extensions; +using System; +using System.Collections.Generic; +using System.Linq; +using Uno.Disposables; +using System.Text; +using System.Threading.Tasks; + + +namespace Windows.UI.Xaml +{ + +} diff --git a/src/Uno.UI/Mock/ContentControl.netstdref.cs b/src/Uno.UI/Mock/ContentControl.netstdref.cs new file mode 100644 index 000000000000..ccb356d45655 --- /dev/null +++ b/src/Uno.UI/Mock/ContentControl.netstdref.cs @@ -0,0 +1,14 @@ +#pragma warning disable 108 // new keyword hiding +#pragma warning disable 114 // new keyword hiding +namespace Windows.UI.Xaml.Controls +{ + public partial class ContentControl + { + private void SetUpdateControlTemplate() { } + private bool HasParent() => true; + + partial void RegisterContentTemplateRoot() + { + } + } +} diff --git a/src/Uno.UI/Mock/Control.netstdref.cs b/src/Uno.UI/Mock/Control.netstdref.cs new file mode 100644 index 000000000000..e88ada2f3bd2 --- /dev/null +++ b/src/Uno.UI/Mock/Control.netstdref.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Windows.UI.Xaml.Controls +{ + public partial class Control : FrameworkElement + { + + } +} diff --git a/src/Uno.UI/Mock/DispatcherTimer.netstdref.cs b/src/Uno.UI/Mock/DispatcherTimer.netstdref.cs new file mode 100644 index 000000000000..af5d3abffb76 --- /dev/null +++ b/src/Uno.UI/Mock/DispatcherTimer.netstdref.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Windows.UI.Xaml +{ + partial class DispatcherTimer + { + private void StartNative(TimeSpan interval) + { + throw new NotSupportedException(); + } + + private void StartNative(TimeSpan dueTime, TimeSpan interval) + { + throw new NotSupportedException(); + } + + private void StopNative() + { + throw new NotSupportedException(); + } + } +} diff --git a/src/Uno.UI/Mock/Grid.netstdref.cs b/src/Uno.UI/Mock/Grid.netstdref.cs new file mode 100644 index 000000000000..9e864bf2db2f --- /dev/null +++ b/src/Uno.UI/Mock/Grid.netstdref.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; + +namespace Windows.UI.Xaml.Controls +{ + public partial class Grid + { + } +} diff --git a/src/Uno.UI/Mock/Image.netstdref.cs b/src/Uno.UI/Mock/Image.netstdref.cs new file mode 100644 index 000000000000..c1ce278d5215 --- /dev/null +++ b/src/Uno.UI/Mock/Image.netstdref.cs @@ -0,0 +1,9 @@ +using Windows.UI; + +namespace Windows.UI.Xaml.Controls +{ + public partial class Image : FrameworkElement + { + internal Color? MonochromeColor { get; set; } + } +} diff --git a/src/Uno.UI/Mock/ImageSource.netstdref.cs b/src/Uno.UI/Mock/ImageSource.netstdref.cs new file mode 100644 index 000000000000..2c7f7fda752e --- /dev/null +++ b/src/Uno.UI/Mock/ImageSource.netstdref.cs @@ -0,0 +1,22 @@ +using Uno.Extensions; +using Uno.Logging; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Net.Http; +using System.ComponentModel; + +namespace Windows.UI.Xaml.Media +{ + public partial class ImageSource + { + public ImageSource() + { + } + + internal void UnloadImageData() { } + } +} diff --git a/src/Uno.UI/Mock/ListView.netstdref.cs b/src/Uno.UI/Mock/ListView.netstdref.cs new file mode 100644 index 000000000000..ce5a071db9fa --- /dev/null +++ b/src/Uno.UI/Mock/ListView.netstdref.cs @@ -0,0 +1,8 @@ +#pragma warning disable 108 // new keyword hiding +#pragma warning disable 114 // new keyword hiding +namespace Windows.UI.Xaml.Controls +{ + public partial class ListView : ListViewBase + { + } +} diff --git a/src/Uno.UI/Mock/ListViewBase.netstdref.cs b/src/Uno.UI/Mock/ListViewBase.netstdref.cs new file mode 100644 index 000000000000..5e29bb81c30f --- /dev/null +++ b/src/Uno.UI/Mock/ListViewBase.netstdref.cs @@ -0,0 +1,11 @@ +#pragma warning disable 108 // new keyword hiding +#pragma warning disable 114 // new keyword hiding +using Windows.UI.Xaml.Controls.Primitives; + +namespace Windows.UI.Xaml.Controls +{ + public partial class ListViewBase : Selector + { + + } +} diff --git a/src/Uno.UI/Mock/Panel.netstdref.cs b/src/Uno.UI/Mock/Panel.netstdref.cs new file mode 100644 index 000000000000..9e20056b726e --- /dev/null +++ b/src/Uno.UI/Mock/Panel.netstdref.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Uno.Disposables; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Media.Animation; +using System.Drawing; +using View = Windows.UI.Xaml.UIElement; + + +namespace Windows.UI.Xaml.Controls +{ + public partial class Panel : FrameworkElement + { + + public Panel() + { + Initialize(); + } + + partial void Initialize(); + + protected virtual void OnChildrenChanged() + { + } + + bool ICustomClippingElement.AllowClippingToLayoutSlot => false; + bool ICustomClippingElement.ForceClippingToLayoutSlot => CornerRadius != CornerRadius.None; + } +} diff --git a/src/Uno.UI/Mock/Popup.netstdref.cs b/src/Uno.UI/Mock/Popup.netstdref.cs new file mode 100644 index 000000000000..7d291cd926c4 --- /dev/null +++ b/src/Uno.UI/Mock/Popup.netstdref.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Windows.UI.Xaml.Controls +{ + public partial class Popup + { + partial void InitializePartial() + { + } + + protected override void OnIsOpenChanged(bool oldIsOpen, bool newIsOpen) + { + base.OnIsOpenChanged(oldIsOpen, newIsOpen); + } + + partial void OnPopupPanelChangedPartial(PopupPanel previousPanel, PopupPanel newPanel) + { + } + } +} diff --git a/src/Uno.UI/Mock/ScrollContentPresenter.netstdref.cs b/src/Uno.UI/Mock/ScrollContentPresenter.netstdref.cs new file mode 100644 index 000000000000..9ecc33dec560 --- /dev/null +++ b/src/Uno.UI/Mock/ScrollContentPresenter.netstdref.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Windows.UI.Xaml.Controls +{ + public partial class ScrollContentPresenter + { + internal void OnMinZoomFactorChanged(float newValue) + { + throw new NotImplementedException(); + } + + internal void OnMaxZoomFactorChanged(float newValue) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Uno.UI/Mock/ScrollViewer.netstdref.cs b/src/Uno.UI/Mock/ScrollViewer.netstdref.cs new file mode 100644 index 000000000000..fe9b047c5802 --- /dev/null +++ b/src/Uno.UI/Mock/ScrollViewer.netstdref.cs @@ -0,0 +1,19 @@ +using Windows.UI.Xaml.Controls; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Media.Animation; +using Windows.UI; + +namespace Windows.UI.Xaml.Controls +{ + public partial class ScrollViewer + { + private void UpdateZoomedContentAlignment() { } + + } +} diff --git a/src/Uno.UI/Mock/Shape.netstdref.cs b/src/Uno.UI/Mock/Shape.netstdref.cs new file mode 100644 index 000000000000..7f1abdc88a73 --- /dev/null +++ b/src/Uno.UI/Mock/Shape.netstdref.cs @@ -0,0 +1,15 @@ +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Media.Animation; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Text; + +namespace Windows.UI.Xaml.Shapes +{ + public partial class Shape + { + + } +} diff --git a/src/Uno.UI/Mock/StackPanel.netstdref.cs b/src/Uno.UI/Mock/StackPanel.netstdref.cs new file mode 100644 index 000000000000..10a15b668f17 --- /dev/null +++ b/src/Uno.UI/Mock/StackPanel.netstdref.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; + +namespace Windows.UI.Xaml.Controls +{ + public partial class StackPanel + { + + } +} diff --git a/src/Uno.UI/Mock/TextBlock.netstdref.cs b/src/Uno.UI/Mock/TextBlock.netstdref.cs new file mode 100644 index 000000000000..c241ddbe3254 --- /dev/null +++ b/src/Uno.UI/Mock/TextBlock.netstdref.cs @@ -0,0 +1,14 @@ +#pragma warning disable 108 // new keyword hiding +#pragma warning disable 114 // new keyword hiding +using Windows.Foundation; +using Windows.UI.Text; + +namespace Windows.UI.Xaml.Controls +{ + public partial class TextBlock : FrameworkElement + { + private void InitializePartial() { } + + private int GetCharacterIndexAtPoint(Point point) => -1; + } +} diff --git a/src/Uno.UI/Mock/UserControl.netstdref.cs b/src/Uno.UI/Mock/UserControl.netstdref.cs new file mode 100644 index 000000000000..f3ba82855170 --- /dev/null +++ b/src/Uno.UI/Mock/UserControl.netstdref.cs @@ -0,0 +1,8 @@ +#pragma warning disable 108 // new keyword hiding +#pragma warning disable 114 // new keyword hiding +namespace Windows.UI.Xaml.Controls +{ + public partial class UserControl : ContentControl + { + } +} diff --git a/src/Uno.UI/Mock/ViewExtensions.netstdref.cs b/src/Uno.UI/Mock/ViewExtensions.netstdref.cs new file mode 100644 index 000000000000..bea33f1208d8 --- /dev/null +++ b/src/Uno.UI/Mock/ViewExtensions.netstdref.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Uno.Disposables; +using System.Text; +using Windows.UI.Xaml; + +namespace Uno.UI +{ + public static partial class ViewExtensions + { + /// + /// Gets an enumerator containing all the children of a View group + /// + /// + /// + internal static IEnumerable GetChildren(this UIElement group) => throw new NotImplementedException(); + + internal static FrameworkElement GetTopLevelParent(this UIElement view) => throw new NotImplementedException(); + + internal static T FindFirstChild(this FrameworkElement root) where T : FrameworkElement + { + return root.GetDescendants().OfType().FirstOrDefault(); + } + + private static IEnumerable GetDescendants(this FrameworkElement root) + { + throw new NotImplementedException(); + } + + + /// + /// Displays the visual tree in the vicinity of for diagnostic purposes. + /// + /// The view to display tree for. + /// How many levels above should be included in the displayed subtree. + /// A formatted string representing the visual tree around . + internal static string ShowLocalVisualTree(this UIElement element, int fromHeight = 1000) + { + throw new NotImplementedException(); + } + + /// + /// Displays all the visual descendants of for diagnostic purposes. + /// + internal static string ShowDescendants(this UIElement element, StringBuilder sb = null, string spacing = "", UIElement viewOfInterest = null) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Uno.UI/Mock/ViewExtensions.skia.cs b/src/Uno.UI/Mock/ViewExtensions.skia.cs new file mode 100644 index 000000000000..a484641905ca --- /dev/null +++ b/src/Uno.UI/Mock/ViewExtensions.skia.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Uno.Disposables; +using System.Text; +using Windows.UI.Xaml; + +namespace Uno.UI +{ + public static partial class ViewExtensions + { + /// + /// (Mock) Gets an enumerator containing all the children of a View group + /// + /// + /// + public static IEnumerable GetChildren(this object group) + { + return new object[0]; + } + + public static FrameworkElement GetTopLevelParent(this UIElement view) => throw new NotImplementedException(); + + public static T FindFirstChild(this FrameworkElement root) where T : FrameworkElement + { + return root.GetDescendants().OfType().FirstOrDefault(); + } + + private static IEnumerable GetDescendants(this FrameworkElement root) + { + foreach (var child in root._children) + { + yield return child as FrameworkElement; + + foreach (var descendant in (child as FrameworkElement).GetDescendants()) + { + yield return descendant; + } + } + } + } +} diff --git a/src/Uno.UI/System/DispatcherQueueTimer.netstdref.cs b/src/Uno.UI/System/DispatcherQueueTimer.netstdref.cs new file mode 100644 index 000000000000..d38b419fdcc9 --- /dev/null +++ b/src/Uno.UI/System/DispatcherQueueTimer.netstdref.cs @@ -0,0 +1,29 @@ +#if HAS_UNO_WINUI +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Windows.System.Threading; + +namespace Microsoft.System +{ + partial class DispatcherQueueTimer + { + private void StartNative(TimeSpan interval) + { + throw new NotImplementedException("DispatcherQueueTimer not supported on .net"); + } + + private void StartNative(TimeSpan dueTime, TimeSpan interval) + { + throw new NotImplementedException("DispatcherQueueTimer not supported on .net"); + } + + private void StopNative() + { + throw new NotImplementedException("DispatcherQueueTimer not supported on .net"); + } + } +} +#endif diff --git a/src/Uno.UI/System/DispatcherQueueTimer.skia.cs b/src/Uno.UI/System/DispatcherQueueTimer.skia.cs new file mode 100644 index 000000000000..d38b419fdcc9 --- /dev/null +++ b/src/Uno.UI/System/DispatcherQueueTimer.skia.cs @@ -0,0 +1,29 @@ +#if HAS_UNO_WINUI +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Windows.System.Threading; + +namespace Microsoft.System +{ + partial class DispatcherQueueTimer + { + private void StartNative(TimeSpan interval) + { + throw new NotImplementedException("DispatcherQueueTimer not supported on .net"); + } + + private void StartNative(TimeSpan dueTime, TimeSpan interval) + { + throw new NotImplementedException("DispatcherQueueTimer not supported on .net"); + } + + private void StopNative() + { + throw new NotImplementedException("DispatcherQueueTimer not supported on .net"); + } + } +} +#endif diff --git a/src/Uno.UI/UI/Xaml/Application.Skia.cs b/src/Uno.UI/UI/Xaml/Application.Skia.cs new file mode 100644 index 000000000000..77b4c402d8e2 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Application.Skia.cs @@ -0,0 +1,62 @@ +#if __SKIA__ +using System; +using Windows.ApplicationModel.Activation; +using Windows.Foundation; +using Windows.Foundation.Metadata; +using Windows.UI.Xaml.Controls.Primitives; +using Windows.ApplicationModel; +using Windows.Graphics.Display; +using Windows.UI.Core; +using Uno.Extensions; +using Uno.Logging; +using System.Threading; +using Uno.UI; +using Uno.UI.Xaml; + +namespace Windows.UI.Xaml +{ + public partial class Application + { + private static bool _startInvoked = false; + + public Application() + { + if (!_startInvoked) + { + throw new InvalidOperationException("The application must be started using Application.Start first, e.g. Windows.UI.Xaml.Application.Start(_ => new App());"); + } + + CoreDispatcher.Main.RunAsync(CoreDispatcherPriority.Normal, Initialize); + } + + static partial void StartPartial(ApplicationInitializationCallback callback) + { + _startInvoked = true; + + SynchronizationContext.SetSynchronizationContext( + new CoreDispatcherSynchronizationContext(CoreDispatcher.Main, CoreDispatcherPriority.Normal) + ); + + callback(new ApplicationInitializationCallbackParams()); + } + + private void Initialize() + { + using (WritePhaseEventTrace(TraceProvider.LauchedStart, TraceProvider.LauchedStop)) + { + // Force init + Window.Current.ToString(); + + Current = this; + + OnLaunched(new LaunchActivatedEventArgs(ActivationKind.Launch, "")); + } + } + + private ApplicationTheme GetDefaultSystemTheme() => ApplicationTheme.Light; + + internal void ForceSetRequestedTheme(ApplicationTheme theme) => _requestedTheme = theme; + + } +} +#endif diff --git a/src/Uno.UI/UI/Xaml/Application.netstdref.cs b/src/Uno.UI/UI/Xaml/Application.netstdref.cs new file mode 100644 index 000000000000..ea10d5d9d480 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Application.netstdref.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Windows.UI.Xaml +{ + public partial class Application + { + public Application() + { + Current = this; + } + + private ApplicationTheme GetDefaultSystemTheme() => ApplicationTheme.Light; + } +} diff --git a/src/Uno.UI/UI/Xaml/Controls/Border/Border.Skia.cs b/src/Uno.UI/UI/Xaml/Controls/Border/Border.Skia.cs new file mode 100644 index 000000000000..e3ed0a4f8754 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Controls/Border/Border.Skia.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Uno.Extensions; +using System.Linq; +using System.Drawing; +using Uno.Disposables; +using Windows.UI.Xaml.Media; +using Uno.UI; + +using View = Windows.UI.Xaml.UIElement; +using Color = System.Drawing.Color; +using Windows.UI.Composition; +using System.Numerics; +using Windows.Foundation; +using Windows.UI.Xaml.Shapes; + +namespace Windows.UI.Xaml.Controls +{ + public partial class Border + { + private SerialDisposable _brushChanged = new SerialDisposable(); + private BorderLayerRenderer _borderRenderer = new BorderLayerRenderer(); + + public Border() + { + Loaded += (s, e) => UpdateBorder(); + Unloaded += (s, e) => _borderRenderer.Clear(); + LayoutUpdated += (s, e) => UpdateBorder(); + } + + partial void OnChildChangedPartial(View previousValue, View newValue) + { + if (previousValue != null) + { + RemoveChild(previousValue); + } + + AddChild(newValue); + } + + private void UpdateBorder() + { + if (Visual != null) + { + _borderRenderer.UpdateLayer( + this, + Background, + BorderThickness, + BorderBrush, + CornerRadius, + null + ); + } + } + + internal override void OnArrangeVisual(Rect rect, Rect? clip) + { + base.OnArrangeVisual(rect, clip); + + UpdateBorder(); + } + + private protected override void OnLoaded() + { + base.OnLoaded(); + UpdateBorder(); + } + + partial void OnBorderBrushChangedPartial() + { + UpdateBorder(); + } + + partial void OnBorderThicknessChangedPartial(Thickness oldValue, Thickness newValue) + { + UpdateBorder(); + } + + partial void OnPaddingChangedPartial(Thickness oldValue, Thickness newValue) + { + UpdateBorder(); + } + + partial void OnCornerRadiusUpdatedPartial(CornerRadius oldValue, CornerRadius newValue) + { + UpdateBorder(); + } + + protected override void OnBackgroundChanged(DependencyPropertyChangedEventArgs e) + { + base.OnBackgroundChanged(e); + UpdateBorder(); + // UpdateHitTest(); + } + + internal override bool IsViewHit() + => Background != null || base.IsViewHit(); + bool ICustomClippingElement.AllowClippingToLayoutSlot => !(Child is UIElement ue) || ue.RenderTransform == null; + bool ICustomClippingElement.ForceClippingToLayoutSlot => CornerRadius != CornerRadius.None; + } +} diff --git a/src/Uno.UI/UI/Xaml/Controls/Border/Border.cs b/src/Uno.UI/UI/Xaml/Controls/Border/Border.cs index eb66c74d93a8..de1777adf936 100644 --- a/src/Uno.UI/UI/Xaml/Controls/Border/Border.cs +++ b/src/Uno.UI/UI/Xaml/Controls/Border/Border.cs @@ -57,6 +57,9 @@ void Add(View view) protected override bool IsSimpleLayout => true; + private protected override Thickness GetBorderThickness() => BorderThickness; + + #region Child DependencyProperty public virtual UIElement Child diff --git a/src/Uno.UI/UI/Xaml/Controls/Border/Border.wasm.cs b/src/Uno.UI/UI/Xaml/Controls/Border/Border.wasm.cs index 4c73e25a2552..f1a2f69ef349 100644 --- a/src/Uno.UI/UI/Xaml/Controls/Border/Border.wasm.cs +++ b/src/Uno.UI/UI/Xaml/Controls/Border/Border.wasm.cs @@ -73,7 +73,5 @@ internal override bool IsViewHit() bool ICustomClippingElement.AllowClippingToLayoutSlot => !(Child is UIElement ue) || ue.RenderTransform == null; bool ICustomClippingElement.ForceClippingToLayoutSlot => CornerRadius != CornerRadius.None; - - private protected override Thickness GetBorderThickness() => BorderThickness; } } diff --git a/src/Uno.UI/UI/Xaml/Controls/Border/BorderLayerRenderer.skia.cs b/src/Uno.UI/UI/Xaml/Controls/Border/BorderLayerRenderer.skia.cs new file mode 100644 index 000000000000..a92426e64ca3 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Controls/Border/BorderLayerRenderer.skia.cs @@ -0,0 +1,223 @@ +using System; +using System.Collections.Generic; +using Uno.Disposables; +using System.Text; +using Uno; +using Uno.Extensions; +using Windows.UI.Xaml.Media; +using Uno.UI.Extensions; +using Windows.Foundation; +using Windows.UI; +using Windows.UI.Composition; +using System.Numerics; + +namespace Windows.UI.Xaml.Shapes +{ + internal class BorderLayerRenderer + { + private LayoutState _currentState; + + private SerialDisposable _layerDisposable = new SerialDisposable(); + + /// + /// Updates or creates a sublayer to render a border-like shape. + /// + /// The parent layer to apply the shape + /// The rendering area + /// The background brush + /// The border thickness + /// The border brush + /// The corner radius + /// The background image in case of a ImageBrush background + public void UpdateLayer( + FrameworkElement owner, + Brush background, + Thickness borderThickness, + Brush borderBrush, + CornerRadius cornerRadius, + object backgroundImage + ) + { + // Bounds is captured to avoid calling twice calls below. + var area = new Rect(0, 0, owner.ActualWidth, owner.ActualHeight); + + var newState = new LayoutState(area, background, borderThickness, borderBrush, cornerRadius, backgroundImage); + var previousLayoutState = _currentState; + + if (!newState.Equals(previousLayoutState)) + { + if ( + background != null || + (borderThickness != Thickness.Empty && borderBrush != null) + ) + { + + _layerDisposable.Disposable = null; + _layerDisposable.Disposable = InnerCreateLayer(owner.Visual, area, background, borderThickness, borderBrush, cornerRadius); + } + else + { + _layerDisposable.Disposable = null; + } + + _currentState = newState; + } + } + + /// + /// Removes the added layers during a call to . + /// + internal void Clear() + { + _layerDisposable.Disposable = null; + _currentState = null; + } + + private static IDisposable InnerCreateLayer( + ContainerVisual parent, + Rect area, + Brush background, + Thickness borderThickness, + Brush borderBrush, + CornerRadius cornerRadius) + { + var disposables = new CompositeDisposable(); + var subVisuals = new List(); + + var adjustedLineWidth = borderThickness.Top; + var adjustedLineWidthOffset = adjustedLineWidth / 2; + + var adjustedArea = area; + adjustedArea.Inflate(-adjustedLineWidthOffset, -adjustedLineWidthOffset); + + var compositor = parent.Compositor; + + var shapeVisual = compositor.CreateShapeVisual(); + parent.Children.InsertAtBottom(shapeVisual); + + var spriteShape = compositor.CreateSpriteShape(); + + SkiaGeometrySource2D BuildGeometry() + { + var maxRadius = Math.Max(0, Math.Min((float)area.Width / 2 - adjustedLineWidthOffset, (float)area.Height / 2 - adjustedLineWidthOffset)); + cornerRadius = new CornerRadius( + Math.Min(cornerRadius.TopLeft, maxRadius), + Math.Min(cornerRadius.TopRight, maxRadius), + Math.Min(cornerRadius.BottomRight, maxRadius), + Math.Min(cornerRadius.BottomLeft, maxRadius)); + + var geometry = new SkiaGeometrySource2D(); + + Brush.AssignAndObserveBrush(borderBrush, color => spriteShape.StrokeBrush = compositor.CreateColorBrush(color)) + .DisposeWith(disposables); + + geometry.Geometry.MoveTo((float)adjustedArea.GetMidX(), (float)adjustedArea.Y); + geometry.Geometry.ArcTo((float)adjustedArea.Right, (float)adjustedArea.Top, (float)adjustedArea.Right, (float)adjustedArea.GetMidY(), (float)cornerRadius.TopRight); + geometry.Geometry.ArcTo((float)adjustedArea.Right, (float)adjustedArea.Bottom, (float)adjustedArea.GetMidX(), (float)adjustedArea.Bottom, (float)cornerRadius.BottomRight); + geometry.Geometry.ArcTo((float)adjustedArea.Left, (float)adjustedArea.Bottom, (float)adjustedArea.Left, (float)adjustedArea.GetMidY(), (float)cornerRadius.BottomLeft); + geometry.Geometry.ArcTo((float)adjustedArea.Left, (float)adjustedArea.Top, (float)adjustedArea.GetMidX(), (float)adjustedArea.Top, (float)cornerRadius.TopLeft); + + geometry.Geometry.Close(); + + if (background is LinearGradientBrush lgbBackground) + { + //var fillMask = new CAShapeLayer() + //{ + // Path = path, + // Frame = area, + // // We only use the fill color to create the mask area + // FillColor = _Color.White.CGColor, + //}; + + //// We reduce the adjustedArea again so that the gradient is inside the border (like in Windows) + //adjustedArea = adjustedArea.Shrink((nfloat)adjustedLineWidthOffset); + + //CreateLinearGradientBrushLayers(area, adjustedArea, parent, sublayers, ref insertionIndex, lgbBackground, fillMask); + } + else if (background is SolidColorBrush scbBackground) + { + Brush.AssignAndObserveBrush(scbBackground, color => spriteShape.FillBrush = compositor.CreateColorBrush(color)) + .DisposeWith(disposables); + } + else if (background is ImageBrush imgBackground) + { + //var uiImage = imgBackground.ImageSource?.ImageData; + //if (uiImage != null && uiImage.Size != CGSize.Empty) + //{ + // var fillMask = new CAShapeLayer() + // { + // Path = path, + // Frame = area, + // // We only use the fill color to create the mask area + // FillColor = _Color.White.CGColor, + // }; + + // // We reduce the adjustedArea again so that the image is inside the border (like in Windows) + // adjustedArea = adjustedArea.Shrink((nfloat)adjustedLineWidthOffset); + + // CreateImageBrushLayers(area, adjustedArea, parent, sublayers, ref insertionIndex, imgBackground, fillMask); + //} + } + else + { + spriteShape.FillBrush = null; + } + + return geometry; + } + + spriteShape.Geometry = compositor.CreatePathGeometry(new CompositionPath(BuildGeometry())); + + shapeVisual.Size = new Vector2((float)area.Width, (float)area.Height); + shapeVisual.Offset = new Vector3(0, 0, 0); + + shapeVisual.Shapes.Add(spriteShape); + + subVisuals.Add(shapeVisual); + + disposables.Add(() => + { + foreach (var sv in subVisuals) + { + parent.Children.Remove(sv); + sv.Dispose(); + } + }); + + Window.Current.QueueInvalidateRender(); + + return disposables; + } + + private class LayoutState : IEquatable + { + public readonly Rect Area; + public readonly Brush Background; + public readonly Brush BorderBrush; + public readonly Thickness BorderThickness; + public readonly CornerRadius CornerRadius; + public readonly object BackgroundImage; + + public LayoutState(Rect area, Brush background, Thickness borderThickness, Brush borderBrush, CornerRadius cornerRadius, object backgroundImage) + { + Area = area; + Background = background; + BorderBrush = borderBrush; + CornerRadius = cornerRadius; + BorderThickness = borderThickness; + BackgroundImage = backgroundImage; + } + + public bool Equals(LayoutState other) + { + return other != null + && other.Area == Area + && other.Background == Background + && other.BorderBrush == BorderBrush + && other.BorderThickness == BorderThickness + && other.CornerRadius == CornerRadius + && other.BackgroundImage == BackgroundImage; + } + } + } +} diff --git a/src/Uno.UI/UI/Xaml/Controls/Button/RadioButton.Android.cs b/src/Uno.UI/UI/Xaml/Controls/Button/RadioButton.Android.cs index 0290633acadf..62cf45466bb1 100644 --- a/src/Uno.UI/UI/Xaml/Controls/Button/RadioButton.Android.cs +++ b/src/Uno.UI/UI/Xaml/Controls/Button/RadioButton.Android.cs @@ -11,13 +11,5 @@ namespace Windows.UI.Xaml.Controls { public partial class RadioButton : ToggleButton { - private IEnumerable GetOtherHierarchicalGroupMembers() - { - return (Parent as ViewGroup)? - .GetChildren() - .OfType() - .Where(rb => rb != this) - ?? Enumerable.Empty(); - } } } diff --git a/src/Uno.UI/UI/Xaml/Controls/Button/RadioButton.cs b/src/Uno.UI/UI/Xaml/Controls/Button/RadioButton.cs index 93733f40067f..b12cae0baa2c 100644 --- a/src/Uno.UI/UI/Xaml/Controls/Button/RadioButton.cs +++ b/src/Uno.UI/UI/Xaml/Controls/Button/RadioButton.cs @@ -5,9 +5,16 @@ using System.Linq; using Uno.Disposables; using Uno.Logging; +using Uno.UI; using Windows.UI.Xaml.Controls.Primitives; using Windows.UI.Xaml.Automation.Peers; +#if __MACOS__ +using AppKit; +#elif __IOS__ +using UIKit; +#endif + namespace Windows.UI.Xaml.Controls { public partial class RadioButton : ToggleButton @@ -67,6 +74,15 @@ private IEnumerable GetOtherNamedGroupMembers() .Where(rb => rb != this); } + private IEnumerable GetOtherHierarchicalGroupMembers() + { + return (Parent as FrameworkElement)? + .GetChildren() + .OfType() + .Where(rb => rb != this) + ?? Enumerable.Empty(); + } + public string GroupName { get { return (string)GetValue(GroupNameProperty); } diff --git a/src/Uno.UI/UI/Xaml/Controls/Button/RadioButton.iOSmacOS.cs b/src/Uno.UI/UI/Xaml/Controls/Button/RadioButton.iOSmacOS.cs index 520d8c7df957..536f87cda2dd 100644 --- a/src/Uno.UI/UI/Xaml/Controls/Button/RadioButton.iOSmacOS.cs +++ b/src/Uno.UI/UI/Xaml/Controls/Button/RadioButton.iOSmacOS.cs @@ -12,14 +12,6 @@ namespace Windows.UI.Xaml.Controls { public partial class RadioButton : ToggleButton { - private IEnumerable GetOtherHierarchicalGroupMembers() - { - return Superview? - .Subviews - .OfType() - .Where(rb => rb != this) - ?? Enumerable.Empty(); - } } } diff --git a/src/Uno.UI/UI/Xaml/Controls/Button/RadioButton.net.cs b/src/Uno.UI/UI/Xaml/Controls/Button/RadioButton.net.cs index 334b0653aa6c..69761406d7a4 100644 --- a/src/Uno.UI/UI/Xaml/Controls/Button/RadioButton.net.cs +++ b/src/Uno.UI/UI/Xaml/Controls/Button/RadioButton.net.cs @@ -10,9 +10,5 @@ namespace Windows.UI.Xaml.Controls { public partial class RadioButton : ToggleButton { - private IEnumerable GetOtherHierarchicalGroupMembers() - { - return null; // throw new NotImplementedException(); - } } } diff --git a/src/Uno.UI/UI/Xaml/Controls/Button/RadioButton.netstdref.cs b/src/Uno.UI/UI/Xaml/Controls/Button/RadioButton.netstdref.cs new file mode 100644 index 000000000000..69761406d7a4 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Controls/Button/RadioButton.netstdref.cs @@ -0,0 +1,14 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using System.Text; +using Uno.Extensions; +using Uno.UI; +using Windows.UI.Xaml.Controls.Primitives; + +namespace Windows.UI.Xaml.Controls +{ + public partial class RadioButton : ToggleButton + { + } +} diff --git a/src/Uno.UI/UI/Xaml/Controls/Button/RadioButton.wasm.cs b/src/Uno.UI/UI/Xaml/Controls/Button/RadioButton.wasm.cs index b95a2ed25a2c..69761406d7a4 100644 --- a/src/Uno.UI/UI/Xaml/Controls/Button/RadioButton.wasm.cs +++ b/src/Uno.UI/UI/Xaml/Controls/Button/RadioButton.wasm.cs @@ -10,13 +10,5 @@ namespace Windows.UI.Xaml.Controls { public partial class RadioButton : ToggleButton { - private IEnumerable GetOtherHierarchicalGroupMembers() - { - return (Parent as FrameworkElement)? - .GetChildren() - .OfType() - .Where(rb => rb != this) - ?? Enumerable.Empty(); - } } } diff --git a/src/Uno.UI/UI/Xaml/Controls/Canvas/Canvas.Layout.cs b/src/Uno.UI/UI/Xaml/Controls/Canvas/Canvas.Layout.cs index c25e3b6939f3..7a19e1b0841c 100644 --- a/src/Uno.UI/UI/Xaml/Controls/Canvas/Canvas.Layout.cs +++ b/src/Uno.UI/UI/Xaml/Controls/Canvas/Canvas.Layout.cs @@ -13,7 +13,7 @@ using _View = UIKit.UIView; #elif __MACOS__ using _View = AppKit.NSView; -#elif __WASM__ || NET461 +#elif NETSTANDARD2_0 || NET461 using _View = Windows.UI.Xaml.UIElement; #endif diff --git a/src/Uno.UI/UI/Xaml/Controls/ContentControl/ContentControl.Skia.cs b/src/Uno.UI/UI/Xaml/Controls/ContentControl/ContentControl.Skia.cs new file mode 100644 index 000000000000..a724491bba3c --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Controls/ContentControl/ContentControl.Skia.cs @@ -0,0 +1,27 @@ +using Uno.Extensions; +using Uno.Logging; +using Uno.UI.DataBinding; +using Uno.UI.Controls; +using Windows.UI.Xaml.Data; +using System; +using System.Collections.Generic; +using Uno.Disposables; +using System.Runtime.CompilerServices; +using System.Text; +using Uno.UI; + +namespace Windows.UI.Xaml.Controls +{ + public partial class ContentControl + { + partial void RegisterContentTemplateRoot() + { + AddChild(ContentTemplateRoot); + } + + partial void UnregisterContentTemplateRoot() + { + RemoveChild(ContentTemplateRoot); + } + } +} diff --git a/src/Uno.UI/UI/Xaml/Controls/ContentPresenter/ContentPresenter.Skia.cs b/src/Uno.UI/UI/Xaml/Controls/ContentPresenter/ContentPresenter.Skia.cs new file mode 100644 index 000000000000..d575b67c98c1 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Controls/ContentPresenter/ContentPresenter.Skia.cs @@ -0,0 +1,70 @@ +using System; +using System.Drawing; +using Uno.Extensions; +using Uno.UI; +using Uno.UI.DataBinding; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Shapes; + +namespace Windows.UI.Xaml.Controls +{ + /// + /// Declares a Content presenter + /// + /// + /// The content presenter is used for compatibility with WPF concepts, + /// but the ContentSource property is not available, because there are ControlTemplates for now. + /// + public partial class ContentPresenter : FrameworkElement + { + private BorderLayerRenderer _borderRenderer = new BorderLayerRenderer(); + + public ContentPresenter() + { + InitializeContentPresenter(); + + Loaded += (s, e) => UpdateBorder(); + Unloaded += (s, e) => _borderRenderer.Clear(); + LayoutUpdated += (s, e) => UpdateBorder(); + } + + private void SetUpdateTemplate() + { + UpdateContentTemplateRoot(); + } + + partial void RegisterContentTemplateRoot() + { + AddChild(ContentTemplateRoot); + } + + partial void UnregisterContentTemplateRoot() + { + RemoveChild(ContentTemplateRoot); + } + + private void UpdateBorder() + { + if (IsLoaded) + { + _borderRenderer.UpdateLayer( + this, + Background, + BorderThickness, + BorderBrush, + CornerRadius, + null + ); + } + } + + partial void OnPaddingChangedPartial(Thickness oldValue, Thickness newValue) + { + UpdateBorder(); + } + + bool ICustomClippingElement.AllowClippingToLayoutSlot => true; + + bool ICustomClippingElement.ForceClippingToLayoutSlot => CornerRadius != CornerRadius.None; + } +} diff --git a/src/Uno.UI/UI/Xaml/Controls/ContentPresenter/ContentPresenter.cs b/src/Uno.UI/UI/Xaml/Controls/ContentPresenter/ContentPresenter.cs index 4eb54171d219..8cc01fa0398c 100644 --- a/src/Uno.UI/UI/Xaml/Controls/ContentPresenter/ContentPresenter.cs +++ b/src/Uno.UI/UI/Xaml/Controls/ContentPresenter/ContentPresenter.cs @@ -31,7 +31,7 @@ using ViewGroup = AppKit.NSView; using Color = AppKit.NSColor; using Font = AppKit.NSFont; -#elif __WASM__ || NET461 +#elif NETSTANDARD2_0 || NET461 using View = Windows.UI.Xaml.UIElement; using ViewGroup = Windows.UI.Xaml.UIElement; #endif @@ -1030,5 +1030,7 @@ protected override Size MeasureOverride(Size size) measuredSize.Height + padding.Top + padding.Bottom + borderThickness.Top + borderThickness.Bottom ); } + + private protected override Thickness GetBorderThickness() => BorderThickness; } } diff --git a/src/Uno.UI/UI/Xaml/Controls/ContentPresenter/ContentPresenter.netstdref.cs b/src/Uno.UI/UI/Xaml/Controls/ContentPresenter/ContentPresenter.netstdref.cs new file mode 100644 index 000000000000..87d4ab672e91 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Controls/ContentPresenter/ContentPresenter.netstdref.cs @@ -0,0 +1,53 @@ +using System; +using System.Drawing; +using Uno.Extensions; +using Uno.UI; +using Uno.UI.DataBinding; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Shapes; + +namespace Windows.UI.Xaml.Controls +{ + /// + /// Declares a Content presenter + /// + /// + /// The content presenter is used for compatibility with WPF concepts, + /// but the ContentSource property is not available, because there are ControlTemplates for now. + /// + public partial class ContentPresenter : FrameworkElement + { + public ContentPresenter() + { + InitializeContentPresenter(); + } + + private void SetUpdateTemplate() + { + UpdateContentTemplateRoot(); + } + + partial void RegisterContentTemplateRoot() + { + AddChild(ContentTemplateRoot); + } + + partial void UnregisterContentTemplateRoot() + { + RemoveChild(ContentTemplateRoot); + } + + private void UpdateBorder() + { + } + + partial void OnPaddingChangedPartial(Thickness oldValue, Thickness newValue) + { + UpdateBorder(); + } + + bool ICustomClippingElement.AllowClippingToLayoutSlot => true; + + bool ICustomClippingElement.ForceClippingToLayoutSlot => CornerRadius != CornerRadius.None; + } +} diff --git a/src/Uno.UI/UI/Xaml/Controls/ContentPresenter/ContentPresenter.wasm.cs b/src/Uno.UI/UI/Xaml/Controls/ContentPresenter/ContentPresenter.wasm.cs index 150e45c46907..bc3d0417bc87 100644 --- a/src/Uno.UI/UI/Xaml/Controls/ContentPresenter/ContentPresenter.wasm.cs +++ b/src/Uno.UI/UI/Xaml/Controls/ContentPresenter/ContentPresenter.wasm.cs @@ -51,7 +51,5 @@ partial void OnPaddingChangedPartial(Thickness oldValue, Thickness newValue) bool ICustomClippingElement.AllowClippingToLayoutSlot => true; bool ICustomClippingElement.ForceClippingToLayoutSlot => CornerRadius != CornerRadius.None; - - private protected override Thickness GetBorderThickness() => BorderThickness; } } diff --git a/src/Uno.UI/UI/Xaml/Controls/Control/Control.Skia.cs b/src/Uno.UI/UI/Xaml/Controls/Control/Control.Skia.cs new file mode 100644 index 000000000000..729f5641babe --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Controls/Control/Control.Skia.cs @@ -0,0 +1,45 @@ +using Uno.UI.Controls; +using Uno.Extensions; +using System; +using System.Collections.Generic; +using System.Text; +using Windows.UI.Xaml.Media; +using Uno.Logging; +using System.Drawing; +using System.Linq; +using Uno.Disposables; +using Uno.UI; +using View = Windows.UI.Xaml.UIElement; + +namespace Windows.UI.Xaml.Controls +{ + public partial class Control + { + public Control() + { + InitializeControl(); + } + + partial void UnregisterSubView() + { + var child = this.GetChildren()?.FirstOrDefault(); + if (child != null) + { + RemoveChild(child); + } + } + + partial void RegisterSubView(View child) + { + AddChild(child); + } + + /// + /// Gets the first sub-view of this control or null if there is none + /// + internal IFrameworkElement GetTemplateRoot() + { + return this.GetChildren()?.FirstOrDefault() as IFrameworkElement; + } + } +} diff --git a/src/Uno.UI/UI/Xaml/Controls/Control/Control.cs b/src/Uno.UI/UI/Xaml/Controls/Control/Control.cs index 8e1b13b65ae4..efa897e856af 100644 --- a/src/Uno.UI/UI/Xaml/Controls/Control/Control.cs +++ b/src/Uno.UI/UI/Xaml/Controls/Control/Control.cs @@ -31,7 +31,7 @@ using Color = AppKit.NSColor; using Font = AppKit.NSFont; using AppKit; -#elif __WASM__ || NET461 +#elif NETSTANDARD2_0 || NET461 using View = Windows.UI.Xaml.UIElement; #endif diff --git a/src/Uno.UI/UI/Xaml/Controls/Control/Control.netstdref.cs b/src/Uno.UI/UI/Xaml/Controls/Control/Control.netstdref.cs new file mode 100644 index 000000000000..3a1a93900c05 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Controls/Control/Control.netstdref.cs @@ -0,0 +1,39 @@ +using Uno.UI.Controls; +using Uno.Extensions; +using System; +using System.Collections.Generic; +using System.Text; +using Windows.UI.Xaml.Media; +using Uno.Logging; +using System.Drawing; +using System.Linq; +using Uno.Disposables; +using Uno.UI; +using View = Windows.UI.Xaml.UIElement; + +namespace Windows.UI.Xaml.Controls +{ + public partial class Control + { + public Control() + { + InitializeControl(); + } + + partial void UnregisterSubView() + { + } + + partial void RegisterSubView(View child) + { + } + + /// + /// Gets the first sub-view of this control or null if there is none + /// + internal IFrameworkElement GetTemplateRoot() + { + return this.GetChildren()?.FirstOrDefault() as IFrameworkElement; + } + } +} diff --git a/src/Uno.UI/UI/Xaml/Controls/Control/Control.wasm.cs b/src/Uno.UI/UI/Xaml/Controls/Control/Control.wasm.cs index 8a1dea5a9331..c72fa0b75861 100644 --- a/src/Uno.UI/UI/Xaml/Controls/Control/Control.wasm.cs +++ b/src/Uno.UI/UI/Xaml/Controls/Control/Control.wasm.cs @@ -19,7 +19,9 @@ public partial class Control /// This binary compatibility workaround that can be removed public new static DependencyProperty IsEnabledProperty => FrameworkElement.IsEnabledProperty; - public Control(string htmlTag = "div") : base(htmlTag) + public Control() : this("div") { } + + public Control(string htmlTag) : base(htmlTag) { InitializeControl(); } diff --git a/src/Uno.UI/UI/Xaml/Controls/DatePicker/DatePickerFlyout.wasm.cs b/src/Uno.UI/UI/Xaml/Controls/DatePicker/DatePickerFlyout.netstd.cs similarity index 100% rename from src/Uno.UI/UI/Xaml/Controls/DatePicker/DatePickerFlyout.wasm.cs rename to src/Uno.UI/UI/Xaml/Controls/DatePicker/DatePickerFlyout.netstd.cs diff --git a/src/Uno.UI/UI/Xaml/Controls/Image/Image.Skia.cs b/src/Uno.UI/UI/Xaml/Controls/Image/Image.Skia.cs new file mode 100644 index 000000000000..9b73354429bb --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Controls/Image/Image.Skia.cs @@ -0,0 +1,27 @@ +using System; +using System.Globalization; +using Windows.Foundation; +using Windows.UI.Xaml.Media; +using Uno.Diagnostics.Eventing; +using Uno.Extensions; +using Uno.Logging; +using Windows.UI.Xaml.Media.Imaging; +using Uno.Disposables; +using Windows.Storage.Streams; +using System.Runtime.InteropServices; +using Microsoft.Extensions.Logging; +using Windows.UI; + +namespace Windows.UI.Xaml.Controls +{ + partial class Image : FrameworkElement + { + public event RoutedEventHandler ImageOpened; + public event ExceptionRoutedEventHandler ImageFailed; + + /// + /// When set, the resulting image is tentatively converted to Monochrome. + /// + internal Color? MonochromeColor { get; set; } + } +} diff --git a/src/Uno.UI/UI/Xaml/Controls/Image/Image.cs b/src/Uno.UI/UI/Xaml/Controls/Image/Image.cs index abb61006916d..cce8b3c1fd48 100644 --- a/src/Uno.UI/UI/Xaml/Controls/Image/Image.cs +++ b/src/Uno.UI/UI/Xaml/Controls/Image/Image.cs @@ -1,4 +1,4 @@ -#if !NET461 && !__WASM__ +#if !NET461 && !NETSTANDARD2_0 using Uno.Extensions; using Uno.Diagnostics.Eventing; using Windows.UI.Xaml.Automation.Peers; @@ -88,7 +88,7 @@ protected virtual void OnImageOpened(ImageSource imageSource) _successfullyOpenedImage = imageSource; } - #region Stretch +#region Stretch public Stretch Stretch { get { return (Stretch)this.GetValue(StretchProperty); } @@ -101,9 +101,9 @@ public Stretch Stretch ((Image)s).OnStretchChanged((Stretch)e.NewValue, (Stretch)e.OldValue))); partial void OnStretchChanged(Stretch newValue, Stretch oldValue); - #endregion +#endregion - #region Source +#region Source public ImageSource Source { get { return (ImageSource)this.GetValue(SourceProperty); } @@ -152,7 +152,7 @@ void OnInvalidated(object sdn, EventArgs args) TryOpenImage(); } - #endregion +#endregion internal override bool IsViewHit() => Source?.HasSource() ?? false; diff --git a/src/Uno.UI/UI/Xaml/Controls/Image/Image.netstdref.cs b/src/Uno.UI/UI/Xaml/Controls/Image/Image.netstdref.cs new file mode 100644 index 000000000000..32d07de0239f --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Controls/Image/Image.netstdref.cs @@ -0,0 +1,24 @@ +using System; +using System.IO; +using Windows.Foundation; +using Windows.UI.Xaml.Media; +using Uno.Extensions; +using Uno.Foundation; +using Uno.Logging; +using Windows.UI.Xaml.Media.Imaging; +using Uno.Disposables; +using Windows.Storage.Streams; +using System.Runtime.InteropServices; +using Microsoft.Extensions.Logging; +using Windows.UI; + +namespace Windows.UI.Xaml.Controls +{ + partial class Image : FrameworkElement + { +#pragma warning disable 67 + public event RoutedEventHandler ImageOpened; + public event ExceptionRoutedEventHandler ImageFailed; +#pragma warning restore 67 + } +} diff --git a/src/Uno.UI/UI/Xaml/Controls/Image/Image.wasm.cs b/src/Uno.UI/UI/Xaml/Controls/Image/Image.wasm.cs index ddb79bd66705..f9bebc1be2b8 100644 --- a/src/Uno.UI/UI/Xaml/Controls/Image/Image.wasm.cs +++ b/src/Uno.UI/UI/Xaml/Controls/Image/Image.wasm.cs @@ -76,9 +76,12 @@ public event RoutedEventHandler ImageOpened remove => _htmlImage.UnregisterEventHandler("load", value); } - public event RoutedEventHandler ImageFailed + private ExceptionRoutedEventArgs ImageFailedConverter(object sender, string e) + => new ExceptionRoutedEventArgs(sender, e); + + public event ExceptionRoutedEventHandler ImageFailed { - add => _htmlImage.RegisterEventHandler("error", value); + add => _htmlImage.RegisterEventHandler("error", value, payloadConverter: ImageFailedConverter); remove => _htmlImage.UnregisterEventHandler("error", value); } @@ -201,7 +204,7 @@ protected override Size ArrangeOverride(Size finalSize) // Calculate the position of the image to follow stretch and alignment requirements var finalPosition = this.ArrangeSource(finalSize, containerSize); - _htmlImage.ArrangeElementNative(finalPosition, false, clipRect: null); + _htmlImage.ArrangeVisual(finalPosition, false, clipRect: null); if (this.Log().IsEnabled(LogLevel.Debug)) { diff --git a/src/Uno.UI/UI/Xaml/Controls/ItemsControl/ItemsControl.Skia.cs b/src/Uno.UI/UI/Xaml/Controls/ItemsControl/ItemsControl.Skia.cs new file mode 100644 index 000000000000..d30b78156af8 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Controls/ItemsControl/ItemsControl.Skia.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Uno.Extensions; +using Uno.UI; +using System.Linq; +using Uno.Extensions.Specialized; +using Windows.UI.Xaml.Data; +using Windows.Foundation; + +namespace Windows.UI.Xaml.Controls +{ + public partial class ItemsControl : Control + { + partial void RequestLayoutPartial() + { + InvalidateMeasure(); + } + + protected override Size MeasureOverride(Size availableSize) + { + UpdateItemsIfNeeded(); + return base.MeasureOverride(availableSize); + } + } +} diff --git a/src/Uno.UI/UI/Xaml/Controls/ItemsControl/ItemsPresenter.cs b/src/Uno.UI/UI/Xaml/Controls/ItemsControl/ItemsPresenter.cs index 70269a89e004..5803be8f5d91 100644 --- a/src/Uno.UI/UI/Xaml/Controls/ItemsControl/ItemsPresenter.cs +++ b/src/Uno.UI/UI/Xaml/Controls/ItemsControl/ItemsPresenter.cs @@ -128,7 +128,7 @@ internal void SetItemsPanel(View panel) this.AddSubview(_itemsPanel); #elif XAMARIN_ANDROID this.AddView(_itemsPanel); -#elif __WASM__ || NET461 +#elif NETSTANDARD || NET461 AddChild(_itemsPanel); #endif @@ -147,7 +147,7 @@ private void RemoveChildViews() } #elif XAMARIN_ANDROID this.RemoveAllViews(); -#elif __WASM__ +#elif NETSTANDARD ClearChildren(); #endif } diff --git a/src/Uno.UI/UI/Xaml/Controls/ItemsStackPanel/ItemsStackPanel.NotImplemented.cs b/src/Uno.UI/UI/Xaml/Controls/ItemsStackPanel/ItemsStackPanel.NotImplemented.cs index 000b3f4511b4..ebcf248edd52 100644 --- a/src/Uno.UI/UI/Xaml/Controls/ItemsStackPanel/ItemsStackPanel.NotImplemented.cs +++ b/src/Uno.UI/UI/Xaml/Controls/ItemsStackPanel/ItemsStackPanel.NotImplemented.cs @@ -1,4 +1,4 @@ -#if !XAMARIN_IOS && !XAMARIN_ANDROID && !__WASM__ && !__MACOS__ +#if !XAMARIN_IOS && !XAMARIN_ANDROID && !NETSTANDARD2_0 && !__MACOS__ #pragma warning disable 108 // new keyword hiding #pragma warning disable 114 // new keyword hiding namespace Windows.UI.Xaml.Controls diff --git a/src/Uno.UI/UI/Xaml/Controls/ItemsStackPanel/ItemsStackPanel.cs b/src/Uno.UI/UI/Xaml/Controls/ItemsStackPanel/ItemsStackPanel.cs index 12b9fd3574b7..b68e23662081 100644 --- a/src/Uno.UI/UI/Xaml/Controls/ItemsStackPanel/ItemsStackPanel.cs +++ b/src/Uno.UI/UI/Xaml/Controls/ItemsStackPanel/ItemsStackPanel.cs @@ -11,11 +11,11 @@ public partial class ItemsStackPanel : Panel, IVirtualizingPanel { VirtualizingPanelLayout _layout; -#if __WASM__ +#if NETSTANDARD [NotImplemented] #endif public int FirstVisibleIndex => _layout?.FirstVisibleIndex ?? -1; -#if __WASM__ +#if NETSTANDARD [NotImplemented] #endif public int LastVisibleIndex => _layout?.LastVisibleIndex ?? -1; @@ -32,7 +32,7 @@ public ItemsStackPanel() CacheLength = FeatureConfiguration.ListViewBase.DefaultCacheLength.Value; } -#if __WASM__ || __MACOS__ +#if NETSTANDARD || __MACOS__ CreateLayoutIfNeeded(); _layout.Initialize(this); #endif diff --git a/src/Uno.UI/UI/Xaml/Controls/ItemsWrapGrid/ItemsWrapGrid.cs b/src/Uno.UI/UI/Xaml/Controls/ItemsWrapGrid/ItemsWrapGrid.cs index 89034f0eba46..4b41fa12938e 100644 --- a/src/Uno.UI/UI/Xaml/Controls/ItemsWrapGrid/ItemsWrapGrid.cs +++ b/src/Uno.UI/UI/Xaml/Controls/ItemsWrapGrid/ItemsWrapGrid.cs @@ -1,4 +1,4 @@ -#if !NET461 && !__WASM__ && !__MACOS__ +#if !NET461 && !NETSTANDARD2_0 && !__MACOS__ using System; using System.Collections.Generic; using System.Text; diff --git a/src/Uno.UI/UI/Xaml/Controls/ItemsWrapGrid/ItemsWrapGridLayout.cs b/src/Uno.UI/UI/Xaml/Controls/ItemsWrapGrid/ItemsWrapGridLayout.cs index 63e9bc365c09..e3c095ff605b 100644 --- a/src/Uno.UI/UI/Xaml/Controls/ItemsWrapGrid/ItemsWrapGridLayout.cs +++ b/src/Uno.UI/UI/Xaml/Controls/ItemsWrapGrid/ItemsWrapGridLayout.cs @@ -1,4 +1,4 @@ -#if !NET461 && !__WASM__ && !__MACOS__ +#if !NET461 && !NETSTANDARD2_0 && !__MACOS__ using System; using System.Collections.Generic; using System.Text; diff --git a/src/Uno.UI/UI/Xaml/Controls/Layouter/Layouter.cs b/src/Uno.UI/UI/Xaml/Controls/Layouter/Layouter.cs index 044f1f3bb7f0..48de258e8612 100644 --- a/src/Uno.UI/UI/Xaml/Controls/Layouter/Layouter.cs +++ b/src/Uno.UI/UI/Xaml/Controls/Layouter/Layouter.cs @@ -1,6 +1,6 @@ // #define LOG_LAYOUT -#if !__WASM__ +#if !NETSTANDARD2_0 using System; using System.Collections.Generic; using System.Linq; diff --git a/src/Uno.UI/UI/Xaml/Controls/ListViewBase/ListViewBase.Skia.cs b/src/Uno.UI/UI/Xaml/Controls/ListViewBase/ListViewBase.Skia.cs new file mode 100644 index 000000000000..61b9a1617e8d --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Controls/ListViewBase/ListViewBase.Skia.cs @@ -0,0 +1,53 @@ +#pragma warning disable 108 // new keyword hiding +#pragma warning disable 114 // new keyword hiding +using System; +using System.Collections.Generic; +using Windows.UI.Xaml.Controls.Primitives; +using Windows.UI.Xaml.Data; + +namespace Windows.UI.Xaml.Controls +{ + public partial class ListViewBase + { + //private int PageSize => throw new NotImplementedException(); + + //private protected override bool ShouldItemsControlManageChildren => true; + + //private void Refresh() + //{ + + //} + + //private void AddItems(int firstItem, int count, int section) + //{ + // Refresh(); + //} + + //private void RemoveItems(int firstItem, int count, int section) + //{ + // Refresh(); + //} + + //private void AddGroup(int groupIndexInView) + //{ + // Refresh(); + //} + + //private void RemoveGroup(int groupIndexInView) + //{ + // Refresh(); + //} + + //private void ReplaceGroup(int groupIndexInView) + //{ + // Refresh(); + //} + + //private ContentControl ContainerFromGroupIndex(int groupIndex) => throw new NotImplementedException(); + + //private void TryLoadMoreItems() + //{ + // //TODO: ISupportIncrementalLoading + //} + } +} diff --git a/src/Uno.UI/UI/Xaml/Controls/ListViewBase/ListViewBase.managed.cs b/src/Uno.UI/UI/Xaml/Controls/ListViewBase/ListViewBase.managed.cs index ba270a5dceca..ac4c7d3880e3 100644 --- a/src/Uno.UI/UI/Xaml/Controls/ListViewBase/ListViewBase.managed.cs +++ b/src/Uno.UI/UI/Xaml/Controls/ListViewBase/ListViewBase.managed.cs @@ -1,4 +1,4 @@ -#if __WASM__ || __MACOS__ +#if NETSTANDARD || __MACOS__ #pragma warning disable 108 // new keyword hiding #pragma warning disable 114 // new keyword hiding using System; diff --git a/src/Uno.UI/UI/Xaml/Controls/ListViewBase/ListViewBase.netstdref.cs b/src/Uno.UI/UI/Xaml/Controls/ListViewBase/ListViewBase.netstdref.cs new file mode 100644 index 000000000000..005642440a71 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Controls/ListViewBase/ListViewBase.netstdref.cs @@ -0,0 +1,13 @@ +#pragma warning disable 108 // new keyword hiding +#pragma warning disable 114 // new keyword hiding +using System; +using System.Collections.Generic; +using Windows.UI.Xaml.Controls.Primitives; +using Windows.UI.Xaml.Data; + +namespace Windows.UI.Xaml.Controls +{ + public partial class ListViewBase + { + } +} diff --git a/src/Uno.UI/UI/Xaml/Controls/ListViewBase/ListViewBaseScrollContentPresenter.cs b/src/Uno.UI/UI/Xaml/Controls/ListViewBase/ListViewBaseScrollContentPresenter.cs index 65b9c1fa8b31..b9bf452816b3 100644 --- a/src/Uno.UI/UI/Xaml/Controls/ListViewBase/ListViewBaseScrollContentPresenter.cs +++ b/src/Uno.UI/UI/Xaml/Controls/ListViewBase/ListViewBaseScrollContentPresenter.cs @@ -1,4 +1,4 @@ -#if !NET461 && !__WASM__ && !__MACOS__ +#if !NET461 && !NETSTANDARD2_0 && !__MACOS__ using System; using System.Collections.Generic; using System.Text; diff --git a/src/Uno.UI/UI/Xaml/Controls/ListViewBase/NativeListViewBase.cs b/src/Uno.UI/UI/Xaml/Controls/ListViewBase/NativeListViewBase.cs index 66f5d481b1b3..b272b3c66c5f 100644 --- a/src/Uno.UI/UI/Xaml/Controls/ListViewBase/NativeListViewBase.cs +++ b/src/Uno.UI/UI/Xaml/Controls/ListViewBase/NativeListViewBase.cs @@ -1,4 +1,4 @@ -#if !NET461 && !__WASM__ && !__MACOS__ +#if !NET461 && !NETSTANDARD2_0 && !__MACOS__ using System; using System.Collections.Generic; using System.ComponentModel; diff --git a/src/Uno.UI/UI/Xaml/Controls/ListViewBase/VirtualizingPanelLayout.cs b/src/Uno.UI/UI/Xaml/Controls/ListViewBase/VirtualizingPanelLayout.cs index 506d06f276a3..6de426f807cb 100644 --- a/src/Uno.UI/UI/Xaml/Controls/ListViewBase/VirtualizingPanelLayout.cs +++ b/src/Uno.UI/UI/Xaml/Controls/ListViewBase/VirtualizingPanelLayout.cs @@ -28,7 +28,7 @@ protected enum RelativeHeaderPlacement { Inline, Adjacent } /// /// For layouting this is identical to but for it is the opposite of . public abstract Orientation ScrollOrientation { get; } -#if !__WASM__ +#if !NETSTANDARD2_0 private protected readonly ILayouter _layouter = new VirtualizingPanelLayouter(); internal ILayouter Layouter => _layouter; #endif @@ -250,7 +250,7 @@ public static (TSource Item, TComparable Value) MinWithSelector child.RelativePosition; +#elif __NETSTD_REFERENCE__ + private static Point GetRelativePosition(FrameworkElement child) => throw new NotSupportedException(); #elif __MACOS__ || __IOS__ private static Point GetRelativePosition(FrameworkElement child) => child.Frame.Location; #elif __ANDROID__ diff --git a/src/Uno.UI/UI/Xaml/Controls/Panel/Panel.Skia.cs b/src/Uno.UI/UI/Xaml/Controls/Panel/Panel.Skia.cs new file mode 100644 index 000000000000..10351d1594eb --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Controls/Panel/Panel.Skia.cs @@ -0,0 +1,108 @@ +using Uno.Extensions; +using Uno.Logging; +using Uno.UI.Controls; +using System; +using System.Linq; +using System.Collections.Generic; +using System.Text; +using System.Collections; +using Uno.UI.DataBinding; +using Uno.Disposables; +using Windows.UI.Xaml.Data; +using System.Runtime.CompilerServices; +using System.Drawing; +using Uno.UI; +using Windows.UI.Xaml.Media; + +using View = Windows.UI.Xaml.UIElement; +using Windows.UI.Xaml.Shapes; + +namespace Windows.UI.Xaml.Controls +{ + public partial class Panel : IEnumerable + { + private SerialDisposable _brushChanged = new SerialDisposable(); + private readonly BorderLayerRenderer _borderRenderer = new BorderLayerRenderer(); + + public Panel() + { + Initialize(); + + Loaded += (s, e) => UpdateBorder(); + Unloaded += (s, e) => _borderRenderer.Clear(); + LayoutUpdated += (s, e) => UpdateBorder(); + } + + partial void Initialize(); + + public void UpdateBorder() + { + // Checking for Window avoids re-creating the layer until it is actually used. + if (IsLoaded) + { + _borderRenderer.UpdateLayer( + this, + Background, + BorderThickness, + BorderBrush, + CornerRadius, + null + ); + } + } + + protected virtual void OnChildrenChanged() + { + UpdateBorder(); + } + + partial void OnPaddingChangedPartial(Thickness oldValue, Thickness newValue) + { + UpdateBorder(); + } + + partial void OnBorderBrushChangedPartial(Brush oldValue, Brush newValue) + { + UpdateBorder(); + } + + partial void OnBorderThicknessChangedPartial(Thickness oldValue, Thickness newValue) + { + UpdateBorder(); + } + + partial void OnCornerRadiusChangedPartial(CornerRadius oldValue, CornerRadius newValue) + { + UpdateBorder(); + } + + /// + /// Support for the C# collection initializer style. + /// Allows items to be added like this + /// new Panel + /// { + /// new Border() + /// } + /// + /// + public void Add(View view) + { + Children.Add(view); + } + + public new IEnumerator GetEnumerator() + { + return this.GetChildren().GetEnumerator(); + } + + protected override void OnBackgroundChanged(DependencyPropertyChangedEventArgs e) + { + base.OnBackgroundChanged(e); + UpdateBorder(); + UpdateHitTest(); + } + + bool ICustomClippingElement.AllowClippingToLayoutSlot => true; + bool ICustomClippingElement.ForceClippingToLayoutSlot => CornerRadius != CornerRadius.None; + } +} diff --git a/src/Uno.UI/UI/Xaml/Controls/Panel/Panel.cs b/src/Uno.UI/UI/Xaml/Controls/Panel/Panel.cs index 3ef5c3e99cd6..7ca21213be3d 100644 --- a/src/Uno.UI/UI/Xaml/Controls/Panel/Panel.cs +++ b/src/Uno.UI/UI/Xaml/Controls/Panel/Panel.cs @@ -23,7 +23,7 @@ namespace Windows.UI.Xaml.Controls [Markup.ContentProperty(Name = "Children")] public partial class Panel : FrameworkElement, ICustomClippingElement { -#if NET461 || __WASM__ +#if NET461 || NETSTANDARD2_0 private new UIElementCollection _children; #else private UIElementCollection _children; @@ -272,5 +272,7 @@ protected virtual void OnBorderBrushChanged(Brush oldValue, Brush newValue) OnBorderBrushChangedPartial(oldValue, newValue); } partial void OnBorderBrushChangedPartial(Brush oldValue, Brush newValue); + + private protected override Thickness GetBorderThickness() => BorderThickness; } } diff --git a/src/Uno.UI/UI/Xaml/Controls/Panel/Panel.wasm.cs b/src/Uno.UI/UI/Xaml/Controls/Panel/Panel.wasm.cs index 03ffdc704ce6..2b682b07c209 100644 --- a/src/Uno.UI/UI/Xaml/Controls/Panel/Panel.wasm.cs +++ b/src/Uno.UI/UI/Xaml/Controls/Panel/Panel.wasm.cs @@ -87,7 +87,5 @@ protected override void OnBackgroundChanged(DependencyPropertyChangedEventArgs e bool ICustomClippingElement.AllowClippingToLayoutSlot => true; bool ICustomClippingElement.ForceClippingToLayoutSlot => CornerRadius != CornerRadius.None; - - private protected override Thickness GetBorderThickness() => BorderThickness; } } diff --git a/src/Uno.UI/UI/Xaml/Controls/Primitives/CarouselPanel.cs b/src/Uno.UI/UI/Xaml/Controls/Primitives/CarouselPanel.cs index e28d65d4059b..21c5d7efe827 100644 --- a/src/Uno.UI/UI/Xaml/Controls/Primitives/CarouselPanel.cs +++ b/src/Uno.UI/UI/Xaml/Controls/Primitives/CarouselPanel.cs @@ -1,4 +1,4 @@ -#if !__WASM__ +#if !NETSTANDARD using System; using System.Collections.Generic; using System.Text; diff --git a/src/Uno.UI/UI/Xaml/Controls/Primitives/CarouselPanel.wasm.cs b/src/Uno.UI/UI/Xaml/Controls/Primitives/CarouselPanel.netstd.cs similarity index 100% rename from src/Uno.UI/UI/Xaml/Controls/Primitives/CarouselPanel.wasm.cs rename to src/Uno.UI/UI/Xaml/Controls/Primitives/CarouselPanel.netstd.cs diff --git a/src/Uno.UI/UI/Xaml/Controls/ProgressRing/ProgressRing.cs b/src/Uno.UI/UI/Xaml/Controls/ProgressRing/ProgressRing.cs index 859ec7767665..040f55224305 100644 --- a/src/Uno.UI/UI/Xaml/Controls/ProgressRing/ProgressRing.cs +++ b/src/Uno.UI/UI/Xaml/Controls/ProgressRing/ProgressRing.cs @@ -1,3 +1,4 @@ +#if XAMARIN || NETSTANDARD using System; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls.Primitives; @@ -14,7 +15,6 @@ public ProgressRing() DefaultStyleKey = typeof(ProgressRing); } - #region IsActive /// /// Gets or sets a value that indicates whether the is showing progress. @@ -25,10 +25,8 @@ public bool IsActive set { SetValue(IsActiveProperty, value); } } - public static readonly DependencyProperty IsActiveProperty = - DependencyProperty.Register("IsActive", typeof(bool), typeof(ProgressRing), new FrameworkPropertyMetadata(false, OnIsActiveChanged)); - - #endregion + public static DependencyProperty IsActiveProperty { get; } = + DependencyProperty.Register("IsActive", typeof(bool), typeof(ProgressRing), new PropertyMetadata(defaultValue: false, propertyChangedCallback: OnIsActiveChanged)); private static void OnIsActiveChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args) { @@ -47,6 +45,8 @@ private static void OnIsActiveChanged(DependencyObject dependencyObject, Depende partial void OnIsActiveChangedPartial(bool newValue); +#if !NETSTANDARD && !__MACOS__ && !__NETSTD_REFERENCE__ + private protected override void OnLoaded() { base.OnLoaded(); @@ -81,5 +81,7 @@ public ProgressRingTemplateSettings TemplateSettings return result; } } +#endif } } +#endif diff --git a/src/Uno.UI/UI/Xaml/Controls/ProgressRing/ProgressRing.netstdref.cs b/src/Uno.UI/UI/Xaml/Controls/ProgressRing/ProgressRing.netstdref.cs new file mode 100644 index 000000000000..8327e04c655b --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Controls/ProgressRing/ProgressRing.netstdref.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Windows.UI.Xaml; + +using Microsoft/*Intentional space for WinUI upgrade tooling*/.UI.Xaml.Controls; + +namespace Windows.UI.Xaml.Controls +{ + public partial class ProgressRing : Control + { + private static void OnIsActiveChanged(DependencyObject dependencyObject, object newValue) => throw new NotSupportedException(); + } +} diff --git a/src/Uno.UI/UI/Xaml/Controls/ProgressRing/ProgressRing.skia.cs b/src/Uno.UI/UI/Xaml/Controls/ProgressRing/ProgressRing.skia.cs new file mode 100644 index 000000000000..8327e04c655b --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Controls/ProgressRing/ProgressRing.skia.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Windows.UI.Xaml; + +using Microsoft/*Intentional space for WinUI upgrade tooling*/.UI.Xaml.Controls; + +namespace Windows.UI.Xaml.Controls +{ + public partial class ProgressRing : Control + { + private static void OnIsActiveChanged(DependencyObject dependencyObject, object newValue) => throw new NotSupportedException(); + } +} diff --git a/src/Uno.UI/UI/Xaml/Controls/ScrollContentPresenter/ScrollContentPresenter.Skia.cs b/src/Uno.UI/UI/Xaml/Controls/ScrollContentPresenter/ScrollContentPresenter.Skia.cs new file mode 100644 index 000000000000..c6c186785c7f --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Controls/ScrollContentPresenter/ScrollContentPresenter.Skia.cs @@ -0,0 +1,128 @@ +using Uno.Extensions; +using Uno.Logging; +using Uno.UI.DataBinding; +using Windows.UI.Xaml.Data; +using System; +using System.Collections; +using System.Collections.Generic; +using Uno.Disposables; +using System.Runtime.CompilerServices; +using System.Text; +using Windows.Foundation; +using Windows.UI.Xaml.Media; + +namespace Windows.UI.Xaml.Controls +{ + public partial class ScrollContentPresenter : ContentPresenter + { + // Default physical amount to scroll with Up/Down/Left/Right key + const double ScrollViewerLineDelta = 16.0; + + // This value comes from WHEEL_DELTA defined in WinUser.h. It represents the universal default mouse wheel delta. + const int ScrollViewerDefaultMouseWheelDelta = 120; + + // These macros compute how many integral pixels need to be scrolled based on the viewport size and mouse wheel delta. + // - First the maximum between 48 and 15% of the viewport size is picked. + // - Then that number is multiplied by (mouse wheel delta/120), 120 being the universal default value. + // - Finally if the resulting number is larger than the viewport size, then that viewport size is picked instead. + private static double GetVerticalScrollWheelDelta(Size size, double delta) + => Math.Min(Math.Floor(size.Height), Math.Round(delta * Math.Max(48.0, Math.Round(size.Height * 0.15, 0)) / ScrollViewerDefaultMouseWheelDelta, 0)); + private static double GetHorizontalScrollWheelDelta(Size size, double delta) + => Math.Min(Math.Floor(size.Width), Math.Round(delta * Math.Max(48.0, Math.Round(size.Width * 0.15, 0)) / ScrollViewerDefaultMouseWheelDelta, 0)); + + // Minimum value of MinZoomFactor, ZoomFactor and MaxZoomFactor + // ZoomFactor can be manipulated to a slightly smaller value, but + // will jump back to 0.1 when the manipulation completes. + const double ScrollViewerMinimumZoomFactor = 0.1f; + + // Tolerated rounding delta in pixels between requested scroll offset and + // effective value. Used to handle non-DM-driven scrolls. + const double ScrollViewerScrollRoundingTolerance = 0.05f; + + // Tolerated rounding delta in pixels between requested scroll offset and + // effective value for cases where IScrollInfo is implemented by a + // IManipulationDataProvider provider. Used to handle non-DM-driven scrolls. + const double ScrollViewerScrollRoundingToleranceForProvider = 1.0f; + + // Delta required between the current scroll offsets and target scroll offsets + // in order to warrant a call to BringIntoViewport instead of + // SetOffsetsWithExtents, SetHorizontalOffset, SetVerticalOffset. + const double ScrollViewerScrollRoundingToleranceForBringIntoViewport = 0.001f; + + // Tolerated rounding delta in between requested zoom factor and + // effective value. Used to handle non-DM-driven zooms. + const double ScrollViewerZoomExtentRoundingTolerance = 0.001f; + + // Tolerated rounding delta in between old and new zoom factor + // in DM delta handling. + const double ScrollViewerZoomRoundingTolerance = 0.000001f; + + // Delta required between the current zoom factor and target zoom factor + // in order to warrant a call to BringIntoViewport instead of ZoomToFactor. + const double ScrollViewerZoomRoundingToleranceForBringIntoViewport = 0.00001f; + + // When a snap point is within this tolerance of the scrollviewer's extent + // minus its viewport we nudge the snap point back into place. + const double ScrollViewerSnapPointLocationTolerance = 0.0001f; + + // If a ScrollViewer is going to reflow around docked CoreInputView occlussions + // by shrinking its viewport, we want to at least guarantee that it will keep + // an appropriate size. + const double ScrollViewerMinHeightToReflowAroundOcclusions = 32.0f; + + + + public ScrollMode HorizontalScrollMode { get; set; } + + public ScrollMode VerticalScrollMode { get; set; } + + public float MinimumZoomScale { get; set; } + + public float MaximumZoomScale { get; set; } + + public ScrollBarVisibility VerticalScrollBarVisibility { get; set; } + + public ScrollBarVisibility HorizontalScrollBarVisibility { get; set; } + + public double HorizontalOffset { get; internal set; } + + public double VerticalOffset { get; internal set; } + + internal Size ScrollBarSize + { + get + { + return new Size(0, 0); + } + } + + public ScrollContentPresenter() + { + PointerWheelChanged += ScrollContentPresenter_PointerWheelChanged; + } + + private void ScrollContentPresenter_PointerWheelChanged(object sender, Input.PointerRoutedEventArgs e) + { + var properties = e.GetCurrentPoint(null).Properties; + + if (Content is UIElement c) + { + if (properties.IsHorizontalMouseWheel) + { + HorizontalOffset += GetHorizontalScrollWheelDelta(c.RenderSize, properties.MouseWheelDelta); + } + else + { + VerticalOffset += GetVerticalScrollWheelDelta(c.RenderSize, properties.MouseWheelDelta); + } + + c.RenderTransform = new TranslateTransform() { X = -HorizontalOffset, Y = -VerticalOffset }; + + Window.Current.QueueInvalidateRender(); + } + + + (TemplatedParent as ScrollViewer)?.OnScrollInternal(HorizontalOffset, VerticalOffset, false); + } + } +} diff --git a/src/Uno.UI/UI/Xaml/Controls/ScrollContentPresenter/ScrollContentPresenter.netstd.cs b/src/Uno.UI/UI/Xaml/Controls/ScrollContentPresenter/ScrollContentPresenter.netstd.cs new file mode 100644 index 000000000000..9ba7cf3b7ae0 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Controls/ScrollContentPresenter/ScrollContentPresenter.netstd.cs @@ -0,0 +1,85 @@ +using Uno.Extensions; +using Uno.Logging; +using Uno.UI.DataBinding; +using Windows.UI.Xaml.Data; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using Uno.Disposables; +using System.Runtime.CompilerServices; +using System.Text; +using Windows.Foundation; +using Uno.UI.Xaml; +using Microsoft.Extensions.Logging; + +namespace Windows.UI.Xaml.Controls +{ + public partial class ScrollContentPresenter : ContentPresenter, IScrollContentPresenter + { + protected override Size MeasureOverride(Size size) + { + var child = Content as UIElement; + if (child != null) + { + var slotSize = size; + if (VerticalScrollBarVisibility != ScrollBarVisibility.Disabled) + { + slotSize.Height = double.PositiveInfinity; + } + if (HorizontalScrollBarVisibility != ScrollBarVisibility.Disabled) + { + slotSize.Width = double.PositiveInfinity; + } + + child.Measure(slotSize); + + return new Size( + Math.Min(size.Width, child.DesiredSize.Width), + Math.Min(size.Height, child.DesiredSize.Height) + ); + } + + return new Size(0, 0); + } + + protected override Size ArrangeOverride(Size finalSize) + { + var child = Content as UIElement; + if (child != null) + { + var slotSize = finalSize; + + var desiredChildSize = child.DesiredSize; + + if (VerticalScrollBarVisibility != ScrollBarVisibility.Disabled) + { + slotSize.Height = Math.Max(desiredChildSize.Height, finalSize.Height); + } + if (HorizontalScrollBarVisibility != ScrollBarVisibility.Disabled) + { + slotSize.Width = Math.Max(desiredChildSize.Width, finalSize.Width); + } + + child.Arrange(new Rect(new Point(0, 0), slotSize)); + } + + return finalSize; + } + + internal override bool IsViewHit() + { + return true; + } + + void IScrollContentPresenter.OnMinZoomFactorChanged(float newValue) + { + MinimumZoomScale = newValue; + } + + void IScrollContentPresenter.OnMaxZoomFactorChanged(float newValue) + { + MaximumZoomScale = newValue; + } + } +} diff --git a/src/Uno.UI/UI/Xaml/Controls/ScrollContentPresenter/ScrollContentPresenter.netstdref.cs b/src/Uno.UI/UI/Xaml/Controls/ScrollContentPresenter/ScrollContentPresenter.netstdref.cs new file mode 100644 index 000000000000..cb224aa0c7ff --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Controls/ScrollContentPresenter/ScrollContentPresenter.netstdref.cs @@ -0,0 +1,29 @@ +using Uno.Extensions; +using Uno.Logging; +using Uno.UI.DataBinding; +using Windows.UI.Xaml.Data; +using System; +using System.Collections; +using System.Collections.Generic; +using Uno.Disposables; +using System.Runtime.CompilerServices; +using System.Text; +using System.Drawing; + +namespace Windows.UI.Xaml.Controls +{ + public partial class ScrollContentPresenter : ContentPresenter + { + public ScrollMode HorizontalScrollMode { get; set; } + + public ScrollMode VerticalScrollMode { get; set; } + + public float MinimumZoomScale { get; set; } + + public float MaximumZoomScale { get; set; } + + public ScrollBarVisibility VerticalScrollBarVisibility { get; set; } + + public ScrollBarVisibility HorizontalScrollBarVisibility { get; set; } + } +} \ No newline at end of file diff --git a/src/Uno.UI/UI/Xaml/Controls/ScrollContentPresenter/ScrollContentPresenter.wasm.cs b/src/Uno.UI/UI/Xaml/Controls/ScrollContentPresenter/ScrollContentPresenter.wasm.cs index 2e92fb183e51..54e9965123e5 100644 --- a/src/Uno.UI/UI/Xaml/Controls/ScrollContentPresenter/ScrollContentPresenter.wasm.cs +++ b/src/Uno.UI/UI/Xaml/Controls/ScrollContentPresenter/ScrollContentPresenter.wasm.cs @@ -15,7 +15,7 @@ namespace Windows.UI.Xaml.Controls { - public partial class ScrollContentPresenter : ContentPresenter, IScrollContentPresenter + public partial class ScrollContentPresenter : ContentPresenter { private ScrollBarVisibility _verticalScrollBarVisibility; private ScrollBarVisibility _horizotalScrollBarVisibility; @@ -146,56 +146,6 @@ public ScrollBarVisibility HorizontalScrollBarVisibility } } - protected override Size MeasureOverride(Size size) - { - var child = Content as UIElement; - if (child != null) - { - var slotSize = size; - if (VerticalScrollBarVisibility != ScrollBarVisibility.Disabled) - { - slotSize.Height = double.PositiveInfinity; - } - if (HorizontalScrollBarVisibility != ScrollBarVisibility.Disabled) - { - slotSize.Width = double.PositiveInfinity; - } - - child.Measure(slotSize); - - return new Size( - Math.Min(size.Width, child.DesiredSize.Width), - Math.Min(size.Height, child.DesiredSize.Height) - ); - } - - return new Size(0, 0); - } - - protected override Size ArrangeOverride(Size finalSize) - { - var child = Content as UIElement; - if (child != null) - { - var slotSize = finalSize; - - var desiredChildSize = child.DesiredSize; - - if (VerticalScrollBarVisibility != ScrollBarVisibility.Disabled) - { - slotSize.Height = Math.Max(desiredChildSize.Height, finalSize.Height); - } - if (HorizontalScrollBarVisibility != ScrollBarVisibility.Disabled) - { - slotSize.Width = Math.Max(desiredChildSize.Width, finalSize.Width); - } - - child.Arrange(new Rect(new Point(0, 0), slotSize)); - } - - return finalSize; - } - private protected override void OnLoaded() { base.OnLoaded(); @@ -242,21 +192,5 @@ private void OnScroll(object sender, EventArgs args) isIntermediate ); } - - - void IScrollContentPresenter.OnMinZoomFactorChanged(float newValue) - { - MinimumZoomScale = newValue; - } - - void IScrollContentPresenter.OnMaxZoomFactorChanged(float newValue) - { - MaximumZoomScale = newValue; - } - - internal override bool IsViewHit() - { - return true; - } } } diff --git a/src/Uno.UI/UI/Xaml/Controls/ScrollViewer/ScrollViewer.Skia.cs b/src/Uno.UI/UI/Xaml/Controls/ScrollViewer/ScrollViewer.Skia.cs new file mode 100644 index 000000000000..17246e6dac59 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Controls/ScrollViewer/ScrollViewer.Skia.cs @@ -0,0 +1,34 @@ +using Windows.UI.Xaml.Controls; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Media.Animation; +using Windows.Foundation; +using Windows.UI; + +namespace Windows.UI.Xaml.Controls +{ + public partial class ScrollViewer + { + internal Size ScrollBarSize => (_sv as ScrollContentPresenter)?.ScrollBarSize ?? default; + + public Color BackgroundColor + { + get + { + throw new NotImplementedException(); + } + set + { + throw new NotImplementedException(); + } + } + + private void UpdateZoomedContentAlignment() { } + + } +} diff --git a/src/Uno.UI/UI/Xaml/Controls/ScrollViewer/ScrollViewer.cs b/src/Uno.UI/UI/Xaml/Controls/ScrollViewer/ScrollViewer.cs index edb32f408e48..f687a6c910d4 100644 --- a/src/Uno.UI/UI/Xaml/Controls/ScrollViewer/ScrollViewer.cs +++ b/src/Uno.UI/UI/Xaml/Controls/ScrollViewer/ScrollViewer.cs @@ -617,7 +617,7 @@ private void UpdateDimensionProperties() /// /// Used in the context of member initialization public -#if !__WASM__ && !__MACOS__ && !NET461 +#if !NETSTANDARD2_0 && !__MACOS__ && !NET461 new #endif void Add(View view) diff --git a/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextBlock.Skia.cs b/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextBlock.Skia.cs new file mode 100644 index 000000000000..b63dc0f298a6 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextBlock.Skia.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using Windows.Foundation; +using Windows.UI.Xaml.Documents; +using Uno.Extensions; +using System.Linq; +using Windows.UI.Xaml.Hosting; +using SkiaSharp; +using Windows.UI.Composition; +using System.Numerics; +using Windows.UI.Composition.Interactions; +using Uno.Disposables; +using Windows.UI.Xaml.Media; +using Uno.UI; + +namespace Windows.UI.Xaml.Controls +{ + partial class TextBlock : FrameworkElement + { + private readonly TextVisual _textVisual; + private readonly SerialDisposable _foregroundColorChanged = new SerialDisposable(); + private readonly SerialDisposable _foregroundOpacityChanged = new SerialDisposable(); + + public Size _lastMeasure; + private Size _lastDesiredSize; + + public TextBlock() + { + _textVisual = new TextVisual(Visual.Compositor, this); + + Visual.Children.InsertAtBottom(_textVisual); + } + + private int GetCharacterIndexAtPoint(Point point) + { + throw new NotSupportedException(); + } + + partial void OnForegroundChangedPartial() + { + var colorBrush = Foreground as SolidColorBrush; + + if (colorBrush != null) + { + _foregroundColorChanged.Disposable = colorBrush.RegisterDisposablePropertyChangedCallback( + SolidColorBrush.ColorProperty, + (s, colorArg) => _textVisual.UpdateForeground() + ); + _foregroundOpacityChanged.Disposable = colorBrush.RegisterDisposablePropertyChangedCallback( + SolidColorBrush.OpacityProperty, + (s, _) => _textVisual.UpdateForeground() + ); + } + else + { + _foregroundColorChanged.Disposable = null; + _foregroundOpacityChanged.Disposable = null; + } + + _textVisual.UpdateForeground(); + } + + protected override Size MeasureOverride(Size availableSize) + { + _lastMeasure = availableSize; + var padding = Padding; + + // available size considering padding + var availableSizeWithoutPadding = availableSize.Subtract(Padding); + + var desiredSize = _textVisual.Measure(availableSizeWithoutPadding); + + _lastDesiredSize = desiredSize.Add(padding); + + return new Size(_lastDesiredSize.Width, _lastDesiredSize.Height); + } + + protected override Size ArrangeOverride(Size finalSize) + { + if (_lastDesiredSize != finalSize) + { + _lastMeasure = finalSize; + _lastDesiredSize = _textVisual.Measure(finalSize); + } + + _textVisual.Size = new Vector2((float)_lastDesiredSize.Width, (float)_lastDesiredSize.Height); + + return base.ArrangeOverride(finalSize); + } + } +} diff --git a/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextBlock.cs b/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextBlock.cs index f9fa152a4575..f66a56290a53 100644 --- a/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextBlock.cs +++ b/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextBlock.cs @@ -35,7 +35,7 @@ public partial class TextBlock : DependencyObject private readonly SerialDisposable _foregroundChanged = new SerialDisposable(); -#if !__WASM__ +#if !NETSTANDARD public TextBlock() { IFrameworkElementHelper.Initialize(this); diff --git a/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextVisual.Skia.cs b/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextVisual.Skia.cs new file mode 100644 index 000000000000..0738b82bc0be --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Controls/TextBlock/TextVisual.Skia.cs @@ -0,0 +1,83 @@ +using SkiaSharp; +using System; +using System.Collections.Generic; +using System.Text; +using Uno; +using Windows.Foundation; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Media; + +namespace Windows.UI.Composition +{ + internal class TextVisual : Visual + { + private SKPaint _paint; + private static Func _getTypeFace = Funcs.CreateMemoized(FromFamilyName); + + private readonly TextBlock _owner; + + private static SKTypeface FromFamilyName(string name) + { + return SKTypeface.FromFamilyName(name); + } + + public TextVisual(Compositor compositor, TextBlock owner) : base(compositor) + { + _owner = owner; + + _paint = new SKPaint(); + _paint.TextEncoding = SKTextEncoding.Utf16; + _paint.IsStroke = false; + _paint.IsAntialias = true; + _paint.LcdRenderText = true; + _paint.SubpixelText = true; + } + + internal Size Measure(Size availableSize) + { + _paint.Typeface = _getTypeFace(_owner.FontFamily.Source); + _paint.TextSize = (float)_owner.FontSize; + + var metrics = _paint.FontMetrics; + var descent = metrics.Descent; + var ascent = metrics.Ascent; + + var lineHeight = descent - ascent; + + UpdateForeground(); + + var bounds = new SKRect(0, 0, (float)availableSize.Width, (float)availableSize.Height); + _paint.MeasureText(string.IsNullOrEmpty(_owner.Text) ? " " : _owner.Text, ref bounds); + + var size = bounds.Size; + + size.Height = lineHeight; + + return new Size(size.Width, size.Height); + } + + public void UpdateForeground() + { + switch (_owner.Foreground) + { + case SolidColorBrush scb: + _paint.Color = new SKColor(red: scb.Color.R, green: scb.Color.G, blue: scb.Color.B, alpha: scb.Color.A); + break; + } + } + + internal override void Render(SKSurface surface, SKImageInfo info) + { + if (!string.IsNullOrEmpty(_owner.Text)) + { + var metrics = _paint.FontMetrics; + var descent = metrics.Descent; + var ascent = metrics.Ascent; + + var lineHeight = descent - ascent; + + surface.Canvas.DrawText(_owner.Text, 0, Size.Y-descent, _paint); + } + } + } +} diff --git a/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.Skia.cs b/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.Skia.cs new file mode 100644 index 000000000000..7b056b166fe4 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.Skia.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Windows.UI.Xaml.Controls +{ + public partial class TextBox + { + private TextBoxView _textBoxView; + + private void UpdateTextBoxView() { } + } +} diff --git a/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.cs b/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.cs index bfec234c3707..77ccef586610 100644 --- a/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.cs +++ b/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.cs @@ -1,4 +1,4 @@ -#if NET461 || __WASM__ || __MACOS__ +#if NET461 || NETSTANDARD2_0 || __MACOS__ #pragma warning disable CS0067, CS649 #endif diff --git a/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.netstdref.cs b/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.netstdref.cs new file mode 100644 index 000000000000..7b056b166fe4 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBox.netstdref.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Windows.UI.Xaml.Controls +{ + public partial class TextBox + { + private TextBoxView _textBoxView; + + private void UpdateTextBoxView() { } + } +} diff --git a/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBoxView.Android.cs b/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBoxView.Android.cs index fff531d5385b..653d3a4c1d16 100644 --- a/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBoxView.Android.cs +++ b/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBoxView.Android.cs @@ -23,7 +23,7 @@ namespace Windows.UI.Xaml.Controls { - public partial class TextBoxView : EditText, DependencyObject + internal partial class TextBoxView : EditText, DependencyObject { private bool _isRunningTextChanged; private bool _isInitialized = false; diff --git a/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBoxView.macOS.cs b/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBoxView.macOS.cs index 4ee6bd1425a0..94537c5cee14 100644 --- a/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBoxView.macOS.cs +++ b/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBoxView.macOS.cs @@ -12,7 +12,7 @@ namespace Windows.UI.Xaml.Controls { - public partial class TextBoxView : _TextField, ITextBoxView, DependencyObject, IFontScalable + internal partial class TextBoxView : _TextField, ITextBoxView, DependencyObject, IFontScalable { private TextBoxViewDelegate _delegate; private readonly WeakReference _textBox; diff --git a/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBoxView.stub.cs b/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBoxView.stub.cs index 0e5059f696d9..26a0aedc87a6 100644 --- a/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBoxView.stub.cs +++ b/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBoxView.stub.cs @@ -1,11 +1,11 @@ -#if NET461 +#if NET461 || __SKIA__ || __NETSTD_REFERENCE__ using System; using System.Collections.Generic; using System.Text; namespace Windows.UI.Xaml.Controls { - public partial class TextBoxView : FrameworkElement + internal partial class TextBoxView : FrameworkElement { internal void SetTextNative(string text) diff --git a/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBoxView.wasm.cs b/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBoxView.wasm.cs index bb645467cfa1..96e3d7581529 100644 --- a/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBoxView.wasm.cs +++ b/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBoxView.wasm.cs @@ -11,7 +11,7 @@ namespace Windows.UI.Xaml.Controls { - public partial class TextBoxView : FrameworkElement + internal partial class TextBoxView : FrameworkElement { private readonly TextBox _textBox; diff --git a/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBoxViewDelegate.macOS.cs b/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBoxViewDelegate.macOS.cs index 3ebe4cc7b5c1..964654e930b1 100644 --- a/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBoxViewDelegate.macOS.cs +++ b/src/Uno.UI/UI/Xaml/Controls/TextBox/TextBoxViewDelegate.macOS.cs @@ -10,7 +10,7 @@ namespace Windows.UI.Xaml.Controls { - public class TextBoxViewDelegate : NSTextFieldDelegate + internal class TextBoxViewDelegate : NSTextFieldDelegate { private readonly WeakReference _textBox; private readonly WeakReference _textBoxView; diff --git a/src/Uno.UI/UI/Xaml/Controls/TimePicker/TimePicker.cs b/src/Uno.UI/UI/Xaml/Controls/TimePicker/TimePicker.cs index 8d834ea2fc88..315abf1b79f5 100644 --- a/src/Uno.UI/UI/Xaml/Controls/TimePicker/TimePicker.cs +++ b/src/Uno.UI/UI/Xaml/Controls/TimePicker/TimePicker.cs @@ -1,4 +1,4 @@ -#if !__WASM__ +#if !NETSTANDARD using System; using System.Collections.Generic; using System.Globalization; diff --git a/src/Uno.UI/UI/Xaml/Controls/TimePicker/TimePickerFlyout.wasm.cs b/src/Uno.UI/UI/Xaml/Controls/TimePicker/TimePickerFlyout.netstd.cs similarity index 100% rename from src/Uno.UI/UI/Xaml/Controls/TimePicker/TimePickerFlyout.wasm.cs rename to src/Uno.UI/UI/Xaml/Controls/TimePicker/TimePickerFlyout.netstd.cs diff --git a/src/Uno.UI/UI/Xaml/Controls/ViewBox/Viewbox.skia.cs b/src/Uno.UI/UI/Xaml/Controls/ViewBox/Viewbox.skia.cs new file mode 100644 index 000000000000..6812997428eb --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Controls/ViewBox/Viewbox.skia.cs @@ -0,0 +1,17 @@ +using Windows.UI.Xaml.Markup; + +namespace Windows.UI.Xaml.Controls +{ + public partial class Viewbox : global::Windows.UI.Xaml.FrameworkElement + { + partial void OnChildChangedPartial(UIElement previousValue, UIElement newValue) + { + if (previousValue != null) + { + RemoveChild(previousValue); + } + + AddChild(newValue); + } + } +} diff --git a/src/Uno.UI/UI/Xaml/Controls/WebView/WebView.cs b/src/Uno.UI/UI/Xaml/Controls/WebView/WebView.cs index db058a9c69e1..5cb4debc5639 100644 --- a/src/Uno.UI/UI/Xaml/Controls/WebView/WebView.cs +++ b/src/Uno.UI/UI/Xaml/Controls/WebView/WebView.cs @@ -2,7 +2,7 @@ #pragma warning disable CS0067, CS0414 #endif -#if XAMARIN || __WASM__ +#if XAMARIN || __WASM__ || __SKIA__ using Windows.Foundation; using Windows.UI.Xaml.Controls; using System; @@ -98,10 +98,12 @@ public bool IsScrollEnabled partial void OnScrollEnabledChangedPartial(bool scrollingEnabled); #endregion +#pragma warning disable 67 public event TypedEventHandler NavigationStarting; public event TypedEventHandler NavigationCompleted; public event TypedEventHandler NewWindowRequested; public event TypedEventHandler UnsupportedUriSchemeIdentified; +#pragma warning restore 67 //Remove pragma when implemented for Android #pragma warning disable 0067 diff --git a/src/Uno.UI/UI/Xaml/Controls/WebView/WebView.netstdref.cs b/src/Uno.UI/UI/Xaml/Controls/WebView/WebView.netstdref.cs new file mode 100644 index 000000000000..eb748e907b1c --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Controls/WebView/WebView.netstdref.cs @@ -0,0 +1,23 @@ + +using Windows.Foundation; +using Windows.UI.Xaml.Controls; +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Uno.Extensions; + +namespace Windows.UI.Xaml.Controls +{ + public partial class WebView : Control + { + public WebView() + { + + } + } +} diff --git a/src/Uno.UI/UI/Xaml/Controls/WebView/WebView.skia.cs b/src/Uno.UI/UI/Xaml/Controls/WebView/WebView.skia.cs new file mode 100644 index 000000000000..ab0bf0acc4f7 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Controls/WebView/WebView.skia.cs @@ -0,0 +1,34 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using System.Text; +using Uno.UI; +using Uno.Extensions; +using Uno.UI.Extensions; +using Windows.UI.Xaml; +using Uno.UI.Web; +using System.Globalization; +using System.Net.Http; +using System.Threading.Tasks; +using System.Threading; +using Windows.UI.Core; +using Uno.Logging; + +namespace Windows.UI.Xaml.Controls +{ + public partial class WebView + { + //This should be IAsyncOperation instead of Task but we use an extension method to enable the same signature in Win. + //IAsyncOperation is not available in Xamarin. + public async Task InvokeScriptAsync(CancellationToken ct, string script, string[] arguments) + { + throw new NotSupportedException(); + } + + public async Task InvokeScriptAsync(string script, string[] arguments) + { + throw new NotSupportedException(); + } + } +} + diff --git a/src/Uno.UI/UI/Xaml/DependencyPropertiesImplementation.cs b/src/Uno.UI/UI/Xaml/DependencyPropertiesImplementation.cs index 370768f0604f..268d7b4df00b 100644 --- a/src/Uno.UI/UI/Xaml/DependencyPropertiesImplementation.cs +++ b/src/Uno.UI/UI/Xaml/DependencyPropertiesImplementation.cs @@ -21,10 +21,13 @@ #if XAMARIN_IOS using Color = UIKit.UIColor; using View = UIKit.UIView; +#elif __MACOS__ +using Color = AppKit.NSColor; +using View = AppKit.NSView; #elif XAMARIN_ANDROID using Color = Android.Resource.Color; using View = Android.Views.View; -#elif NET461 +#elif NET461 || NETSTANDARD2_0 using Color = System.Object; using View = Windows.UI.Xaml.FrameworkElement; #endif diff --git a/src/Uno.UI/UI/Xaml/DependencyPropertiesImplementation.tt b/src/Uno.UI/UI/Xaml/DependencyPropertiesImplementation.tt index 3824a0b48987..7e81398d8243 100644 --- a/src/Uno.UI/UI/Xaml/DependencyPropertiesImplementation.tt +++ b/src/Uno.UI/UI/Xaml/DependencyPropertiesImplementation.tt @@ -32,7 +32,7 @@ using View = AppKit.NSView; #elif XAMARIN_ANDROID using Color = Android.Resource.Color; using View = Android.Views.View; -#elif NET461 || __WASM__ +#elif NET461 || NETSTANDARD2_0 using Color = System.Object; using View = Windows.UI.Xaml.FrameworkElement; #endif diff --git a/src/Uno.UI/UI/Xaml/DispatcherTimer.Skia.cs b/src/Uno.UI/UI/Xaml/DispatcherTimer.Skia.cs new file mode 100644 index 000000000000..ffa06195434f --- /dev/null +++ b/src/Uno.UI/UI/Xaml/DispatcherTimer.Skia.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Windows.UI.Core; + +namespace Windows.UI.Xaml +{ + partial class DispatcherTimer + { + Timer _timer; + + private void StartNative(TimeSpan interval) + { + if (_timer == null) + { + _timer = new Timer(_ => DispatchRaiseTick()); + } + + _timer.Change(interval, interval); + } + + private void DispatchRaiseTick() + { + CoreDispatcher.Main.RunAsync(CoreDispatcherPriority.Normal, _ => RaiseTick()); + } + + private void StartNative(TimeSpan dueTime, TimeSpan interval) + { + if (_timer == null) + { + _timer = new Timer(_ => DispatchRaiseTick()); + } + + _timer.Change(dueTime, interval); + } + + private void StopNative() + { + _timer.Dispose(); + _timer = null; + } + } +} diff --git a/src/Uno.UI/UI/Xaml/Documents/Hyperlink.wasm.cs b/src/Uno.UI/UI/Xaml/Documents/Hyperlink.wasm.cs index 008575f5f64a..f07966895207 100644 --- a/src/Uno.UI/UI/Xaml/Documents/Hyperlink.wasm.cs +++ b/src/Uno.UI/UI/Xaml/Documents/Hyperlink.wasm.cs @@ -67,6 +67,40 @@ private void UpdateNavigationProperties(Uri navigateUri, NavigationTarget target internal override bool IsViewHit() => NavigateUri != null || base.IsViewHit(); + + public new event global::Windows.UI.Xaml.RoutedEventHandler GotFocus + { + add => base.GotFocus += value; + remove => base.GotFocus -= value; + } + + public new event global::Windows.UI.Xaml.RoutedEventHandler LostFocus + { + add => base.LostFocus += value; + remove => base.LostFocus -= value; + } + +#if HAS_UNO_WINUI + // The properties below have moved to UIElement in WinUI, but Hyperlink does not inherit from UIElement and does in Wasm. + // This makes the properties move down incorrectly. + // This section places those properties at the same location as the reference implementation. + + public new bool IsTabStop + { + get => base.IsTabStop; + set => base.IsTabStop = value; + } + + public static new DependencyProperty IsTabStopProperty { get; } = UIElement.IsTabStopProperty; + + public new FocusState FocusState + { + get => base.FocusState; + set => base.FocusState = value; + } + + public static new DependencyProperty FocusStateProperty { get; } = UIElement.FocusStateProperty; +#endif } public enum NavigationTarget diff --git a/src/Uno.UI/UI/Xaml/Documents/Inline.cs b/src/Uno.UI/UI/Xaml/Documents/Inline.cs index 4be703e139a6..cbfb3ec3d994 100644 --- a/src/Uno.UI/UI/Xaml/Documents/Inline.cs +++ b/src/Uno.UI/UI/Xaml/Documents/Inline.cs @@ -6,7 +6,7 @@ namespace Windows.UI.Xaml.Documents { - public partial class Inline : TextElement + public abstract partial class Inline : TextElement { internal void InvalidateInlines() { diff --git a/src/Uno.UI/UI/Xaml/Documents/InlineCollection.cs b/src/Uno.UI/UI/Xaml/Documents/InlineCollection.cs index 2f9c3badfe1a..f598b132d267 100644 --- a/src/Uno.UI/UI/Xaml/Documents/InlineCollection.cs +++ b/src/Uno.UI/UI/Xaml/Documents/InlineCollection.cs @@ -8,17 +8,20 @@ namespace Windows.UI.Xaml.Documents { - public partial class InlineCollection : DependencyObjectCollection, IList, IEnumerable + public partial class InlineCollection : IList, IEnumerable { + private readonly DependencyObjectCollection _collection = new DependencyObjectCollection(); + internal InlineCollection(DependencyObject parent) { - this.SetParent(parent); + _collection.SetParent(parent); + _collection.VectorChanged += (s, e) => OnCollectionChanged(); } - private protected override void OnCollectionChanged() + private void OnCollectionChanged() { #if !NET461 - switch (this.GetParent()) + switch (_collection.GetParent()) { case TextBlock textBlock: textBlock.InvalidateInlines(); @@ -31,6 +34,47 @@ private protected override void OnCollectionChanged() } #endif } + + public IEnumerator GetEnumerator() => _collection.OfType().GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + /// + public void Add(Inline item) => _collection.Add(item); + + /// + public void Clear() => _collection.Clear(); + + /// + public bool Contains(Inline item) => _collection.Contains(item); + + /// + public void CopyTo(Inline[] array, int arrayIndex) => throw new NotSupportedException(); + + /// + public bool Remove(Inline item) => _collection.Remove(item); + + /// + public int Count => _collection.Count; + + /// + public bool IsReadOnly => false; + + /// + public int IndexOf(Inline item) => _collection.IndexOf(item); + + /// + public void Insert(int index, Inline item) => _collection.Insert(index, item); + + /// + public void RemoveAt(int index) => _collection.RemoveAt(index); + + /// + public Inline this[int index] + { + get => (Inline)_collection[index]; + set => _collection[index] = value; + } } } -#endif \ No newline at end of file +#endif diff --git a/src/Uno.UI/UI/Xaml/Documents/InlineCollection.wasm.cs b/src/Uno.UI/UI/Xaml/Documents/InlineCollection.wasm.cs index 20030bdb9609..2f21cef0fabc 100644 --- a/src/Uno.UI/UI/Xaml/Documents/InlineCollection.wasm.cs +++ b/src/Uno.UI/UI/Xaml/Documents/InlineCollection.wasm.cs @@ -6,11 +6,11 @@ namespace Windows.UI.Xaml.Documents { - partial class InlineCollection + partial class InlineCollection : IList, IEnumerable { private readonly UIElementCollection _collection; - public InlineCollection(UIElement containerElement) + internal InlineCollection(UIElement containerElement) { _collection = new UIElementCollection(containerElement); } diff --git a/src/Uno.UI/UI/Xaml/ElementStub.wasm.cs b/src/Uno.UI/UI/Xaml/ElementStub.netstd.cs similarity index 100% rename from src/Uno.UI/UI/Xaml/ElementStub.wasm.cs rename to src/Uno.UI/UI/Xaml/ElementStub.netstd.cs diff --git a/src/Uno.UI/UI/Xaml/FrameworkElement.Interface.Skia.cs b/src/Uno.UI/UI/Xaml/FrameworkElement.Interface.Skia.cs new file mode 100644 index 000000000000..217c7a9a5bc1 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/FrameworkElement.Interface.Skia.cs @@ -0,0 +1,118 @@ +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Media.Animation; +using System; +using System.Collections.Generic; +using Windows.Foundation; +using System.Runtime.CompilerServices; +using System.Text; +using Uno.UI.Xaml; + +namespace Windows.UI.Xaml +{ + public partial class FrameworkElement : UIElement, IFrameworkElement + { + public T FindFirstParent() where T : class + { + var view = this.Parent; + while (view != null) + { + var typed = view as T; + if (typed != null) + { + return typed; + } + view = view.GetParent() as DependencyObject; + } + return null; + } + + private protected virtual void OnLoaded() + { + + } + + private protected virtual void OnUnloaded() + { + + } + + public TransitionCollection Transitions { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + + public object FindName(string name) + => IFrameworkElementHelper.FindName(this, GetChildren(), name); + + + public void Dispose() + { + throw new NotImplementedException(); + } + + public Size AdjustArrange(Size finalSize) + { + return finalSize; + } + + + #region IsEnabled DependencyProperty + + public event DependencyPropertyChangedEventHandler IsEnabledChanged; + + [GeneratedDependencyProperty(DefaultValue = true, ChangedCallback = true, CoerceCallback = true, Options = FrameworkPropertyMetadataOptions.Inherits)] + public static DependencyProperty IsEnabledProperty { get; } = CreateIsEnabledProperty(); + + public bool IsEnabled + { + get => GetIsEnabledValue(); + set => SetIsEnabledValue(value); + } + + protected virtual void OnIsEnabledChanged(DependencyPropertyChangedEventArgs args) + { + OnIsEnabledChanged((bool)args.OldValue, (bool)args.NewValue); + IsEnabledChanged?.Invoke(this, args); + } + + protected virtual void OnIsEnabledChanged(bool oldValue, bool newValue) + { + } + + #endregion + + public int? RenderPhase + { + get => throw new NotImplementedException(); + set => throw new NotImplementedException(); + } + + private static readonly Uri DefaultBaseUri = new Uri("ms-appx://local"); + public global::System.Uri BaseUri + { + get; + internal set; + } = DefaultBaseUri; + + public void ApplyBindingPhase(int phase) => throw new NotImplementedException(); + + #region Background DependencyProperty + + public Brush Background + { + get => (Brush)GetValue(BackgroundProperty); + set => SetValue(BackgroundProperty, value); + } + + // Using a DependencyProperty as the backing store for Background. This enables animation, styling, binding, etc... + public static DependencyProperty BackgroundProperty { get; } = + DependencyProperty.Register("Background", typeof(Brush), typeof(FrameworkElement), new PropertyMetadata(null, (s, e) => ((FrameworkElement)s)?.OnBackgroundChanged(e))); + + + protected virtual void OnBackgroundChanged(DependencyPropertyChangedEventArgs e) + { + + } + + #endregion + } +} diff --git a/src/Uno.UI/UI/Xaml/FrameworkElement.Interface.netstdref.cs b/src/Uno.UI/UI/Xaml/FrameworkElement.Interface.netstdref.cs new file mode 100644 index 000000000000..a889ea833001 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/FrameworkElement.Interface.netstdref.cs @@ -0,0 +1,130 @@ +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Media.Animation; +using System; +using System.Collections.Generic; +using Windows.Foundation; +using System.Runtime.CompilerServices; +using System.Text; +using Uno.UI.Xaml; + +namespace Windows.UI.Xaml +{ + public partial class FrameworkElement : UIElement, IFrameworkElement + { + public T FindFirstParent() where T : class + { + var view = this.Parent; + while (view != null) + { + var typed = view as T; + if (typed != null) + { + return typed; + } + view = view.GetParent() as DependencyObject; + } + return null; + } + + partial void Initialize(); + + public FrameworkElement() + { + Initialize(); + } + + private protected virtual void OnLoading() + { + OnLoadingPartial(); + } + + private protected virtual void OnLoaded() + { + } + + private protected virtual void OnUnloaded() + { + } + + public TransitionCollection Transitions { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + + public void Dispose() + { + throw new NotImplementedException(); + } + + public Size AdjustArrange(Size finalSize) + { + return finalSize; + } + + public object FindName(string name) + => IFrameworkElementHelper.FindName(this, GetChildren(), name); + + #region IsEnabled DependencyProperty + +#pragma warning disable 67 + public event DependencyPropertyChangedEventHandler IsEnabledChanged; +#pragma warning restore 67 + + public bool IsEnabled + { + get { return (bool)GetValue(IsEnabledProperty); } + set { SetValue(IsEnabledProperty, value); } + } + + // Using a DependencyProperty as the backing store for Enabled. This enables animation, styling, binding, etc... + public static DependencyProperty IsEnabledProperty { get; } = + DependencyProperty.Register( + "IsEnabled", + typeof(bool), + typeof(FrameworkElement), + new PropertyMetadata( + defaultValue: true, + propertyChangedCallback: (s, e) => ((FrameworkElement)s)?.OnIsEnabledChanged((bool)e.OldValue, (bool)e.NewValue), + coerceValueCallback: (s, v) => (s as FrameworkElement)?.CoerceIsEnabled(v) + ) + ); + + protected virtual void OnIsEnabledChanged(bool oldValue, bool newValue) + { + } + + #endregion + + #region Background DependencyProperty + + public Brush Background + { + get => (Brush)GetValue(BackgroundProperty); + set => SetValue(BackgroundProperty, value); + } + + // Using a DependencyProperty as the backing store for Background. This enables animation, styling, binding, etc... + public static DependencyProperty BackgroundProperty { get; } = + DependencyProperty.Register("Background", typeof(Brush), typeof(FrameworkElement), new PropertyMetadata(null, (s, e) => ((FrameworkElement)s)?.OnBackgroundChanged(e))); + + protected virtual void OnBackgroundChanged(DependencyPropertyChangedEventArgs e) + { + + } + + #endregion + + public int? RenderPhase + { + get => throw new NotImplementedException(); + set => throw new NotImplementedException(); + } + + public void ApplyBindingPhase(int phase) => throw new NotImplementedException(); + + private void OnGenericPropertyUpdated(DependencyPropertyChangedEventArgs args) + { + OnGenericPropertyUpdatedPartial(args); + this.InvalidateMeasure(); + } + } +} diff --git a/src/Uno.UI/UI/Xaml/FrameworkElement.Interface.wasm.cs b/src/Uno.UI/UI/Xaml/FrameworkElement.Interface.wasm.cs index 279a62e416d9..016d6f7e5ea3 100644 --- a/src/Uno.UI/UI/Xaml/FrameworkElement.Interface.wasm.cs +++ b/src/Uno.UI/UI/Xaml/FrameworkElement.Interface.wasm.cs @@ -36,7 +36,15 @@ public T FindFirstParent() where T : class partial void Initialize(); - public FrameworkElement(string htmlTag = "div", bool isSvg = false) : base(htmlTag, isSvg) + public FrameworkElement() : this(DefaultHtmlTag, false) + { + } + + public FrameworkElement(string htmlTag) : this(htmlTag, false) + { + } + + public FrameworkElement(string htmlTag, bool isSvg) : base(htmlTag, isSvg) { Initialize(); diff --git a/src/Uno.UI/UI/Xaml/FrameworkElement.Layout.Skia.cs b/src/Uno.UI/UI/Xaml/FrameworkElement.Layout.Skia.cs new file mode 100644 index 000000000000..e13ac84f1429 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/FrameworkElement.Layout.Skia.cs @@ -0,0 +1,19 @@ +using System; +using System.Globalization; +using Uno.Diagnostics.Eventing; +using Uno.Extensions; +using Uno.Logging; +using Windows.Foundation; +using Microsoft.Extensions.Logging; +using Uno.UI; +using static System.Math; +using static Uno.UI.LayoutHelper; +using Windows.UI.Xaml.Media; +using Uno.UI.Extensions; + +namespace Windows.UI.Xaml +{ + public partial class FrameworkElement + { + } +} diff --git a/src/Uno.UI/UI/Xaml/FrameworkElement.Layout.netstd.cs b/src/Uno.UI/UI/Xaml/FrameworkElement.Layout.netstd.cs new file mode 100644 index 000000000000..dd6aef210113 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/FrameworkElement.Layout.netstd.cs @@ -0,0 +1,323 @@ +#if !__NETSTD_REFERENCE__ +using System; +using System.Globalization; +using System.Linq; +using Uno.Diagnostics.Eventing; +using Uno.Extensions; +using Uno.Logging; +using Windows.Foundation; +using Microsoft.Extensions.Logging; +using Uno.UI; +using static System.Math; +using static Uno.UI.LayoutHelper; + +namespace Windows.UI.Xaml +{ + public partial class FrameworkElement + { + /// + /// DesiredSize from MeasureOverride, after clamping to min size but before being clipped by max size (from GetMinMax()) + /// + private Size _unclippedDesiredSize; + private Point _visualOffset; + + private const double SIZE_EPSILON = 0.05d; + private readonly Size MaxSize = new Size(double.PositiveInfinity, double.PositiveInfinity); + + /// + /// The origin of the view's bounds relative to its parent. + /// + internal Point RelativePosition => _visualOffset; + + private protected string DepthIndentation + { + get + { + if (Depth is int d) + { + return (Parent as FrameworkElement)?.DepthIndentation + $"-{d}>"; + } + else + { + return "-?>"; + } + } + } + + internal sealed override void MeasureCore(Size availableSize) + { + if (_trace.IsEnabled) + { + var traceActivity = _trace.WriteEventActivity( + TraceProvider.FrameworkElement_MeasureStart, + TraceProvider.FrameworkElement_MeasureStop, + new object[] { GetType().Name, this.GetDependencyObjectId(), Name, availableSize.ToString() } + ); + + using (traceActivity) + { + InnerMeasureCore(availableSize); + } + } + else + { + // This method is split in two functions to avoid the dynCalls + // invocations generation for mono-wasm AOT inside of try/catch/finally blocks. + InnerMeasureCore(availableSize); + } + } + + private void InnerMeasureCore(Size availableSize) + { + var (minSize, maxSize) = this.GetMinMax(); + var marginSize = this.GetMarginSize(); + + // NaN values are accepted as input here, particularly when coming from + // SizeThatFits in Image or Scrollviewer. Clamp the value here as it is reused + // below for the clipping value. + availableSize = availableSize + .NumberOrDefault(MaxSize); + + var frameworkAvailableSize = availableSize + .Subtract(marginSize) + .AtLeastZero() + .AtMost(maxSize); + + var desiredSize = MeasureOverride(frameworkAvailableSize); + + _logDebug?.LogTrace($"{DepthIndentation}{this}.MeasureOverride(availableSize={frameworkAvailableSize}): desiredSize={desiredSize} minSize={minSize} maxSize={maxSize} marginSize={marginSize}"); + + if ( + double.IsNaN(desiredSize.Width) + || double.IsNaN(desiredSize.Height) + || double.IsInfinity(desiredSize.Width) + || double.IsInfinity(desiredSize.Height) + ) + { + throw new InvalidOperationException($"{this}: Invalid measured size {desiredSize}. NaN or Infinity are invalid desired size."); + } + + desiredSize = desiredSize + .AtLeast(minSize) + .AtLeastZero(); + + _unclippedDesiredSize = desiredSize; + + var clippedDesiredSize = desiredSize + .AtMost(availableSize) + .Add(marginSize) + // Margin may be negative + .AtLeastZero(); + + // DesiredSize must include margins + SetDesiredSize(clippedDesiredSize); + + _logDebug?.Debug($"{DepthIndentation}[{this}] Measure({Name}/{availableSize}/{Margin}) = {clippedDesiredSize} _unclippedDesiredSize={_unclippedDesiredSize}"); + } + + internal sealed override void ArrangeCore(Rect finalRect) + { + if (_trace.IsEnabled) + { + var traceActivity = _trace.WriteEventActivity( + TraceProvider.FrameworkElement_ArrangeStart, + TraceProvider.FrameworkElement_ArrangeStop, + new object[] { GetType().Name, this.GetDependencyObjectId(), Name, finalRect.ToString() } + ); + + using (traceActivity) + { + InnerArrangeCore(finalRect); + } + } + else + { + // This method is split in two functions to avoid the dynCalls + // invocations generation for mono-wasm AOT inside of try/catch/finally blocks. + InnerArrangeCore(finalRect); + } + } + + private static bool IsLessThanAndNotCloseTo(double a, double b) => a < (b - SIZE_EPSILON); + + private void InnerArrangeCore(Rect finalRect) + { + _logDebug?.Debug($"{DepthIndentation}{this}: InnerArrangeCore({finalRect})"); + var arrangeSize = finalRect.Size; + + var (_, maxSize) = this.GetMinMax(); + var marginSize = this.GetMarginSize(); + + arrangeSize = arrangeSize + .Subtract(marginSize) + .AtLeastZero(); + + var customClippingElement = (this as ICustomClippingElement); + var allowClipToSlot = customClippingElement?.AllowClippingToLayoutSlot ?? true; // Some controls may control itself how clipping is applied + var needsClipToSlot = customClippingElement?.ForceClippingToLayoutSlot ?? false; + + _logDebug?.Debug($"{DepthIndentation}{this}: InnerArrangeCore({finalRect}) - allowClip={allowClipToSlot}, arrangeSize={arrangeSize}, _unclippedDesiredSize={_unclippedDesiredSize}, forcedClipping={needsClipToSlot}"); + + if (allowClipToSlot && !needsClipToSlot) + { + if (IsLessThanAndNotCloseTo(arrangeSize.Width, _unclippedDesiredSize.Width)) + { + _logDebug?.Debug($"{DepthIndentation}{this}: (arrangeSize.Width) {arrangeSize.Width} < {_unclippedDesiredSize.Width}: NEEDS CLIPPING."); + needsClipToSlot = true; + } + else if (IsLessThanAndNotCloseTo(arrangeSize.Height, _unclippedDesiredSize.Height)) + { + _logDebug?.Debug($"{DepthIndentation}{this}: (arrangeSize.Height) {arrangeSize.Height} < {_unclippedDesiredSize.Height}: NEEDS CLIPPING."); + needsClipToSlot = true; + } + } + + if (HorizontalAlignment != HorizontalAlignment.Stretch) + { + arrangeSize.Width = _unclippedDesiredSize.Width; + } + + if (VerticalAlignment != VerticalAlignment.Stretch) + { + arrangeSize.Height = _unclippedDesiredSize.Height; + } + + // We have to choose max between _unclippedDesiredSize and maxSize here, because + // otherwise setting of max property could cause arrange at less then _unclippedDesiredSize. + // Clipping by Max is needed to limit stretch here + var effectiveMaxSize = Max(_unclippedDesiredSize, maxSize); + + _logDebug?.Debug($"{DepthIndentation}{this}: InnerArrangeCore({finalRect}) - effectiveMaxSize={effectiveMaxSize}, maxSize={maxSize}, _unclippedDesiredSize={_unclippedDesiredSize}, forcedClipping={needsClipToSlot}"); + + if (allowClipToSlot) + { + if (IsLessThanAndNotCloseTo(effectiveMaxSize.Width, arrangeSize.Width)) + { + _logDebug?.Debug($"{DepthIndentation}{this}: (effectiveMaxSize.Width) {effectiveMaxSize.Width} < {arrangeSize.Width}: NEEDS CLIPPING."); + needsClipToSlot = true; + arrangeSize.Width = effectiveMaxSize.Width; + } + if (IsLessThanAndNotCloseTo(effectiveMaxSize.Height, arrangeSize.Height)) + { + _logDebug?.Debug($"{DepthIndentation}{this}: (effectiveMaxSize.Height) {effectiveMaxSize.Height} < {arrangeSize.Height}: NEEDS CLIPPING."); + needsClipToSlot = true; + arrangeSize.Height = effectiveMaxSize.Height; + } + } + + var oldRenderSize = RenderSize; + var innerInkSize = ArrangeOverride(arrangeSize); + + var clippedInkSize = innerInkSize.AtMost(maxSize); + + RenderSize = needsClipToSlot ? clippedInkSize : innerInkSize; + + _logDebug?.Debug($"{DepthIndentation}{this}: ArrangeOverride({arrangeSize})={innerInkSize}, clipped={clippedInkSize} (max={maxSize}) needsClipToSlot={needsClipToSlot}"); + + var clientSize = finalRect.Size + .Subtract(marginSize) + .AtLeastZero(); + + // Give opportunity to element to alter arranged size + clippedInkSize = AdjustArrange(clippedInkSize); + + var (offset, overflow) = this.GetAlignmentOffset(clientSize, clippedInkSize); + var margin = Margin; + + offset = new Point( + offset.X + finalRect.X + margin.Left, + offset.Y + finalRect.Y + margin.Top + ); + + if (overflow) + { + needsClipToSlot = true; + } + + _logDebug?.Debug( + $"{DepthIndentation}[{this}] ArrangeChild(offset={offset}, margin={margin}) [oldRenderSize={oldRenderSize}] [RenderSize={RenderSize}] [clippedInkSize={clippedInkSize}] [RequiresClipping={needsClipToSlot}]"); + + RequiresClipping = needsClipToSlot; + +#if __WASM__ + if (FeatureConfiguration.UIElement.AssignDOMXamlProperties) + { + UpdateDOMXamlProperty(nameof(RequiresClipping), RequiresClipping); + } +#endif + + if (needsClipToSlot) + { + var layoutFrame = new Rect(offset, clippedInkSize); + + // Calculate clipped frame. + var clippedFrameWithParentOrigin = + layoutFrame + .IntersectWith(finalRect.DeflateBy(margin)) + ?? Rect.Empty; + + // Rebase the origin of the clipped frame to layout + var clippedFrame = new Rect( + clippedFrameWithParentOrigin.X - layoutFrame.X, + clippedFrameWithParentOrigin.Y - layoutFrame.Y, + clippedFrameWithParentOrigin.Width, + clippedFrameWithParentOrigin.Height); + + ArrangeNative(offset, clippedFrame); + } + else + { + ArrangeNative(offset); + } + + OnLayoutUpdated(); + } + + /// + /// Calculates and applies native arrange properties. + /// + /// Offset of the view from its parent + /// Zone to clip, if clipping is required + private void ArrangeNative(Point offset, Rect clippedFrame = default) + { + _visualOffset = offset; + + var newRect = new Rect(offset, RenderSize); + + if ( + newRect.Width < 0 + || newRect.Height < 0 + || double.IsNaN(newRect.Width) + || double.IsNaN(newRect.Height) + || double.IsNaN(newRect.X) + || double.IsNaN(newRect.Y) + ) + { + throw new InvalidOperationException($"{this}: Invalid frame size {newRect}. No dimension should be NaN or negative value."); + } + + Rect? getClip() + { + // Clip transform not supported yet on Wasm + + if (RequiresClipping) // if control should be clipped by layout constrains + { + if (Clip != null) + { + return clippedFrame.IntersectWith(Clip.Rect); + } + return clippedFrame; + } + + return Clip?.Rect; + } + + var clipRect = getClip(); + + _logDebug?.Trace($"{DepthIndentation}{this}.ArrangeElementNative({newRect}, clip={clipRect} (RequiresClipping={RequiresClipping})"); + + ArrangeVisual(newRect, RequiresClipping, clipRect); + } + } +} +#endif diff --git a/src/Uno.UI/UI/Xaml/FrameworkElement.Layout.wasm.cs b/src/Uno.UI/UI/Xaml/FrameworkElement.Layout.wasm.cs index ba54ec323192..50f64388433d 100644 --- a/src/Uno.UI/UI/Xaml/FrameworkElement.Layout.wasm.cs +++ b/src/Uno.UI/UI/Xaml/FrameworkElement.Layout.wasm.cs @@ -14,308 +14,5 @@ namespace Windows.UI.Xaml { public partial class FrameworkElement { - /// - /// DesiredSize from MeasureOverride, after clamping to min size but before being clipped by max size (from GetMinMax()) - /// - private Size _unclippedDesiredSize; - private Point _visualOffset; - - private const double SIZE_EPSILON = 0.05d; - private readonly Size MaxSize = new Size(double.PositiveInfinity, double.PositiveInfinity); - - /// - /// The origin of the view's bounds relative to its parent. - /// - internal Point RelativePosition => _visualOffset; - - private protected string DepthIndentation - { - get - { - if (Depth is int d) - { - return (Parent as FrameworkElement)?.DepthIndentation + $"-{d}>"; - } - else - { - return "-?>"; - } - } - } - - internal sealed override void MeasureCore(Size availableSize) - { - if (_trace.IsEnabled) - { - var traceActivity = _trace.WriteEventActivity( - TraceProvider.FrameworkElement_MeasureStart, - TraceProvider.FrameworkElement_MeasureStop, - new object[] { GetType().Name, this.GetDependencyObjectId(), Name, availableSize.ToString() } - ); - - using (traceActivity) - { - InnerMeasureCore(availableSize); - } - } - else - { - // This method is split in two functions to avoid the dynCalls - // invocations generation for mono-wasm AOT inside of try/catch/finally blocks. - InnerMeasureCore(availableSize); - } - } - - private void InnerMeasureCore(Size availableSize) - { - var (minSize, maxSize) = this.GetMinMax(); - var marginSize = this.GetMarginSize(); - - // NaN values are accepted as input here, particularly when coming from - // SizeThatFits in Image or Scrollviewer. Clamp the value here as it is reused - // below for the clipping value. - availableSize = availableSize - .NumberOrDefault(MaxSize); - - var frameworkAvailableSize = availableSize - .Subtract(marginSize) - .AtLeastZero() - .AtMost(maxSize); - - var desiredSize = MeasureOverride(frameworkAvailableSize); - - _logDebug?.LogTrace($"{DepthIndentation}{this}.MeasureOverride(availableSize={frameworkAvailableSize}): desiredSize={desiredSize} minSize={minSize} maxSize={maxSize} marginSize={marginSize}"); - - if ( - double.IsNaN(desiredSize.Width) - || double.IsNaN(desiredSize.Height) - || double.IsInfinity(desiredSize.Width) - || double.IsInfinity(desiredSize.Height) - ) - { - throw new InvalidOperationException($"{this}: Invalid measured size {desiredSize}. NaN or Infinity are invalid desired size."); - } - - desiredSize = desiredSize - .AtLeast(minSize) - .AtLeastZero(); - - _unclippedDesiredSize = desiredSize; - - var clippedDesiredSize = desiredSize - .AtMost(availableSize) - .Add(marginSize) - // Margin may be negative - .AtLeastZero(); - - // DesiredSize must include margins - SetDesiredSize(clippedDesiredSize); - - _logDebug?.Debug($"{DepthIndentation}[{this}] Measure({Name}/{availableSize}/{Margin}) = {clippedDesiredSize} _unclippedDesiredSize={_unclippedDesiredSize}"); - } - - internal sealed override void ArrangeCore(Rect finalRect) - { - if (_trace.IsEnabled) - { - var traceActivity = _trace.WriteEventActivity( - TraceProvider.FrameworkElement_ArrangeStart, - TraceProvider.FrameworkElement_ArrangeStop, - new object[] { GetType().Name, this.GetDependencyObjectId(), Name, finalRect.ToString() } - ); - - using (traceActivity) - { - InnerArrangeCore(finalRect); - } - } - else - { - // This method is split in two functions to avoid the dynCalls - // invocations generation for mono-wasm AOT inside of try/catch/finally blocks. - InnerArrangeCore(finalRect); - } - } - - private static bool IsLessThanAndNotCloseTo(double a, double b) => a < (b - SIZE_EPSILON); - - private void InnerArrangeCore(Rect finalRect) - { - _logDebug?.Debug($"{DepthIndentation}{this}: InnerArrangeCore({finalRect})"); - var arrangeSize = finalRect.Size; - - var (_, maxSize) = this.GetMinMax(); - var marginSize = this.GetMarginSize(); - - arrangeSize = arrangeSize - .Subtract(marginSize) - .AtLeastZero(); - - var customClippingElement = (this as ICustomClippingElement); - var allowClipToSlot = customClippingElement?.AllowClippingToLayoutSlot ?? true; // Some controls may control itself how clipping is applied - var needsClipToSlot = customClippingElement?.ForceClippingToLayoutSlot ?? false; - - _logDebug?.Debug($"{DepthIndentation}{this}: InnerArrangeCore({finalRect}) - allowClip={allowClipToSlot}, arrangeSize={arrangeSize}, _unclippedDesiredSize={_unclippedDesiredSize}, forcedClipping={needsClipToSlot}"); - - if (allowClipToSlot && !needsClipToSlot) - { - if (IsLessThanAndNotCloseTo(arrangeSize.Width, _unclippedDesiredSize.Width)) - { - _logDebug?.Debug($"{DepthIndentation}{this}: (arrangeSize.Width) {arrangeSize.Width} < {_unclippedDesiredSize.Width}: NEEDS CLIPPING."); - needsClipToSlot = true; - } - else if (IsLessThanAndNotCloseTo(arrangeSize.Height, _unclippedDesiredSize.Height)) - { - _logDebug?.Debug($"{DepthIndentation}{this}: (arrangeSize.Height) {arrangeSize.Height} < {_unclippedDesiredSize.Height}: NEEDS CLIPPING."); - needsClipToSlot = true; - } - } - - if (HorizontalAlignment != HorizontalAlignment.Stretch) - { - arrangeSize.Width = _unclippedDesiredSize.Width; - } - - if (VerticalAlignment != VerticalAlignment.Stretch) - { - arrangeSize.Height = _unclippedDesiredSize.Height; - } - - // We have to choose max between _unclippedDesiredSize and maxSize here, because - // otherwise setting of max property could cause arrange at less then _unclippedDesiredSize. - // Clipping by Max is needed to limit stretch here - var effectiveMaxSize = Max(_unclippedDesiredSize, maxSize); - - _logDebug?.Debug($"{DepthIndentation}{this}: InnerArrangeCore({finalRect}) - effectiveMaxSize={effectiveMaxSize}, maxSize={maxSize}, _unclippedDesiredSize={_unclippedDesiredSize}, forcedClipping={needsClipToSlot}"); - - if (allowClipToSlot) - { - if (IsLessThanAndNotCloseTo(effectiveMaxSize.Width, arrangeSize.Width)) - { - _logDebug?.Debug($"{DepthIndentation}{this}: (effectiveMaxSize.Width) {effectiveMaxSize.Width} < {arrangeSize.Width}: NEEDS CLIPPING."); - needsClipToSlot = true; - arrangeSize.Width = effectiveMaxSize.Width; - } - if (IsLessThanAndNotCloseTo(effectiveMaxSize.Height, arrangeSize.Height)) - { - _logDebug?.Debug($"{DepthIndentation}{this}: (effectiveMaxSize.Height) {effectiveMaxSize.Height} < {arrangeSize.Height}: NEEDS CLIPPING."); - needsClipToSlot = true; - arrangeSize.Height = effectiveMaxSize.Height; - } - } - - var oldRenderSize = RenderSize; - var innerInkSize = ArrangeOverride(arrangeSize); - - var clippedInkSize = innerInkSize.AtMost(maxSize); - - RenderSize = needsClipToSlot ? clippedInkSize : innerInkSize; - - _logDebug?.Debug($"{DepthIndentation}{this}: ArrangeOverride({arrangeSize})={innerInkSize}, clipped={clippedInkSize} (max={maxSize}) needsClipToSlot={needsClipToSlot}"); - - var clientSize = finalRect.Size - .Subtract(marginSize) - .AtLeastZero(); - - // Give opportunity to element to alter arranged size - clippedInkSize = AdjustArrange(clippedInkSize); - - var (offset, overflow) = this.GetAlignmentOffset(clientSize, clippedInkSize); - var margin = Margin; - - offset = new Point( - offset.X + finalRect.X + margin.Left, - offset.Y + finalRect.Y + margin.Top - ); - - if (overflow) - { - needsClipToSlot = true; - } - - _logDebug?.Debug( - $"{DepthIndentation}[{this}] ArrangeChild(offset={offset}, margin={margin}) [oldRenderSize={oldRenderSize}] [RenderSize={RenderSize}] [clippedInkSize={clippedInkSize}] [RequiresClipping={needsClipToSlot}]"); - - RequiresClipping = needsClipToSlot; - - if (FeatureConfiguration.UIElement.AssignDOMXamlProperties) - { - UpdateDOMXamlProperty(nameof(RequiresClipping), RequiresClipping); - } - - if (needsClipToSlot) - { - var layoutFrame = new Rect(offset, clippedInkSize); - - // Calculate clipped frame. - var clippedFrameWithParentOrigin = - layoutFrame - .IntersectWith(finalRect.DeflateBy(margin)) - ?? Rect.Empty; - - // Rebase the origin of the clipped frame to layout - var clippedFrame = new Rect( - clippedFrameWithParentOrigin.X - layoutFrame.X, - clippedFrameWithParentOrigin.Y - layoutFrame.Y, - clippedFrameWithParentOrigin.Width, - clippedFrameWithParentOrigin.Height); - - ArrangeNative(offset, clippedFrame); - } - else - { - ArrangeNative(offset); - } - - OnLayoutUpdated(); - } - - private protected virtual Thickness GetBorderThickness() => Thickness.Empty; - - /// - /// Calculates and applies native arrange properties. - /// - /// Offset of the view from its parent - /// Zone to clip, if clipping is required - private void ArrangeNative(Point offset, Rect clippedFrame = default) - { - _visualOffset = offset; - - var newRect = new Rect(offset, RenderSize); - - if ( - newRect.Width < 0 - || newRect.Height < 0 - || double.IsNaN(newRect.Width) - || double.IsNaN(newRect.Height) - || double.IsNaN(newRect.X) - || double.IsNaN(newRect.Y) - ) - { - throw new InvalidOperationException($"{this}: Invalid frame size {newRect}. No dimension should be NaN or negative value."); - } - - Rect? getClip() - { - // Clip transform not supported yet on Wasm - - if (RequiresClipping) // if control should be clipped by layout constrains - { - if (Clip != null) - { - return clippedFrame.IntersectWith(Clip.Rect); - } - return clippedFrame; - } - - return Clip?.Rect; - } - - var clipRect = getClip(); - - _logDebug?.Trace($"{DepthIndentation}{this}.ArrangeElementNative({newRect}, clip={clipRect} (RequiresClipping={RequiresClipping})"); - - ArrangeElementNative(newRect, RequiresClipping, clipRect); - } } } diff --git a/src/Uno.UI/UI/Xaml/FrameworkElement.Skia.cs b/src/Uno.UI/UI/Xaml/FrameworkElement.Skia.cs new file mode 100644 index 000000000000..119ee0b07de0 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/FrameworkElement.Skia.cs @@ -0,0 +1,301 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Uno.Disposables; +using System.Text; +using System.Threading.Tasks; +using Uno.Extensions; +using Uno; +using Uno.Logging; +using Windows.UI.Xaml.Controls; +using Windows.Foundation; +using View = Windows.UI.Xaml.UIElement; +using System.Collections; +using Microsoft.Extensions.Logging; +using Uno.UI.Xaml; + +namespace Windows.UI.Xaml +{ + public partial class FrameworkElement : IEnumerable + { + private Size _actualSize; + + private readonly static Thickness _thicknessCache = Thickness.Empty; + + public FrameworkElement() + { + _log = this.Log(); + _logDebug = _log.IsEnabled(LogLevel.Debug) ? _log : null; + Initialize(); + } + + public new bool IsLoaded + { + get => base.IsLoaded; // The IsLoaded state is managed by the UIElement, FrameworkElement only makes it publicly visible + set => base.IsLoaded = value; + } + + bool IFrameworkElementInternal.HasLayouter => true; + + partial void Initialize(); + + protected internal readonly ILogger _log; + private protected readonly ILogger _logDebug; + + partial void OnLoadingPartial(); + private protected virtual void OnPostLoading() + { + } + public bool HasParent() + { + return Parent != null; + } + + internal void SetActualSize(Size size) => _actualSize = size; + + public double ActualWidth => GetActualWidth(); + public double ActualHeight => GetActualHeight(); + + private protected virtual double GetActualWidth() => _actualSize.Width; + private protected virtual double GetActualHeight() => _actualSize.Height; + + partial void OnMeasurePartial(Size slotSize) + { + } + + internal override void OnElementLoaded() + { + base.OnElementLoaded(); + OnLoadingPartial(); + _loading?.Invoke(this, new RoutedEventArgs()); + + OnLoaded(); + _loaded?.Invoke(this, new RoutedEventArgs()); + } + + internal void OnElementUnloaded() + { + OnUnloaded(); + _unloaded?.Invoke(this, new RoutedEventArgs()); + } + + public int InvalidateMeasureCallCount { get; private set; } + + private bool IsTopLevelXamlView() => false; + + internal void SuspendRendering() => throw new NotSupportedException(); + + internal void ResumeRendering() => throw new NotSupportedException(); + public IEnumerator GetEnumerator() => _children.GetEnumerator(); + + public event SizeChangedEventHandler SizeChanged; + + internal void RaiseSizeChanged(SizeChangedEventArgs args) + { + SizeChanged?.Invoke(this, args); + _renderTransform?.UpdateSize(args.NewSize); + } + + #region Margin Dependency Property + [GeneratedDependencyProperty( + Options = FrameworkPropertyMetadataOptions.AutoConvert | FrameworkPropertyMetadataOptions.AffectsMeasure +#if DEBUG + , ChangedCallbackName = nameof(OnGenericPropertyUpdated) +#endif + )] + public static DependencyProperty MarginProperty { get; } = CreateMarginProperty(); + + public virtual Thickness Margin + { + get => GetMarginValue(); + set => SetMarginValue(value); + } + private static Thickness GetMarginDefaultValue() => Thickness.Empty; + #endregion + + #region HorizontalAlignment Dependency Property + [GeneratedDependencyProperty( + DefaultValue = Xaml.HorizontalAlignment.Stretch, + Options = FrameworkPropertyMetadataOptions.AutoConvert | FrameworkPropertyMetadataOptions.AffectsMeasure +#if DEBUG + , ChangedCallbackName = nameof(OnGenericPropertyUpdated) +#endif + )] + public static DependencyProperty HorizontalAlignmentProperty { get; } = CreateHorizontalAlignmentProperty(); + + public HorizontalAlignment HorizontalAlignment + { + get => GetHorizontalAlignmentValue(); + set => SetHorizontalAlignmentValue(value); + } + #endregion + + #region HorizontalAlignment Dependency Property + [GeneratedDependencyProperty( + DefaultValue = Xaml.HorizontalAlignment.Stretch, + Options = FrameworkPropertyMetadataOptions.AutoConvert | FrameworkPropertyMetadataOptions.AffectsMeasure +#if DEBUG + , ChangedCallbackName = nameof(OnGenericPropertyUpdated) +#endif + )] + public static DependencyProperty VerticalAlignmentProperty { get; } = CreateVerticalAlignmentProperty(); + + public VerticalAlignment VerticalAlignment + { + get => GetVerticalAlignmentValue(); + set => SetVerticalAlignmentValue(value); + } + #endregion + + #region Width Dependency Property + [GeneratedDependencyProperty( + DefaultValue = double.NaN, + Options = FrameworkPropertyMetadataOptions.AutoConvert | FrameworkPropertyMetadataOptions.AffectsMeasure +#if DEBUG + , ChangedCallbackName = nameof(OnGenericPropertyUpdated) +#endif + )] + public static DependencyProperty WidthProperty { get; } = CreateWidthProperty(); + + public double Width + { + get => GetWidthValue(); + set => SetWidthValue(value); + } + #endregion + + #region Height Dependency Property + [GeneratedDependencyProperty( + DefaultValue = double.NaN, + Options = FrameworkPropertyMetadataOptions.AutoConvert | FrameworkPropertyMetadataOptions.AffectsMeasure +#if DEBUG + , ChangedCallbackName = nameof(OnGenericPropertyUpdated) +#endif + )] + public static DependencyProperty HeightProperty { get; } = CreateHeightProperty(); + + public double Height + { + get => GetHeightValue(); + set => SetHeightValue(value); + } + #endregion + + #region MinWidth Dependency Property + [GeneratedDependencyProperty( + DefaultValue = 0.0d, + Options = FrameworkPropertyMetadataOptions.AutoConvert | FrameworkPropertyMetadataOptions.AffectsMeasure +#if DEBUG + , ChangedCallbackName = nameof(OnGenericPropertyUpdated) +#endif + )] + public static DependencyProperty MinWidthProperty { get; } = CreateMinWidthProperty(); + + public double MinWidth + { + get => GetMinWidthValue(); + set => SetMinWidthValue(value); + } + #endregion + + #region MinHeight Dependency Property + + [GeneratedDependencyProperty( + DefaultValue = 0.0d, + Options = FrameworkPropertyMetadataOptions.AutoConvert | FrameworkPropertyMetadataOptions.AffectsMeasure +#if DEBUG + , ChangedCallbackName = nameof(OnGenericPropertyUpdated) +#endif + )] + public static DependencyProperty MinHeightProperty { get; } = CreateMinHeightProperty(); + + public double MinHeight + { + get => GetMinHeightValue(); + set => SetMinHeightValue(value); + } + #endregion + + #region MaxWidth Dependency Property + [GeneratedDependencyProperty( + DefaultValue = double.PositiveInfinity, + Options = FrameworkPropertyMetadataOptions.AutoConvert | FrameworkPropertyMetadataOptions.AffectsMeasure +#if DEBUG + , ChangedCallbackName = nameof(OnGenericPropertyUpdated) +#endif + )] + public static DependencyProperty MaxWidthProperty { get; } = CreateMaxWidthProperty(); + + public double MaxWidth + { + get => GetMaxWidthValue(); + set => SetMaxWidthValue(value); + } + #endregion + + #region MaxHeight Dependency Property + + [GeneratedDependencyProperty( + DefaultValue = double.PositiveInfinity, + Options = FrameworkPropertyMetadataOptions.AutoConvert | FrameworkPropertyMetadataOptions.AffectsMeasure +#if DEBUG + , ChangedCallbackName = nameof(OnGenericPropertyUpdated) +#endif + )] + public static DependencyProperty MaxHeightProperty { get; } = CreateMaxHeightProperty(); + + public double MaxHeight + { + get => GetMaxHeightValue(); + set => SetMaxHeightValue(value); + } + #endregion + + partial void OnGenericPropertyUpdatedPartial(DependencyPropertyChangedEventArgs args); + + private void OnGenericPropertyUpdated(DependencyPropertyChangedEventArgs args) + { + OnGenericPropertyUpdatedPartial(args); + } + + private event RoutedEventHandler _loading; + public event RoutedEventHandler Loading + { + add + { + _loading += value; + } + remove + { + + _loading -= value; + } + } + + private event RoutedEventHandler _loaded; + public event RoutedEventHandler Loaded + { + add + { + _loaded += value; + } + remove + { + _loaded -= value; + } + } + + private event RoutedEventHandler _unloaded; + public event RoutedEventHandler Unloaded + { + add + { + _unloaded += value; + } + remove + { + _unloaded -= value; + } + } + } +} diff --git a/src/Uno.UI/UI/Xaml/FrameworkElement.cs b/src/Uno.UI/UI/Xaml/FrameworkElement.cs index 50cb5d234168..2bd7505c1fef 100644 --- a/src/Uno.UI/UI/Xaml/FrameworkElement.cs +++ b/src/Uno.UI/UI/Xaml/FrameworkElement.cs @@ -46,7 +46,7 @@ static class TraceProvider public const int FrameworkElement_InvalidateMeasure = 5; } -#if !__WASM__ +#if !NETSTANDARD private FrameworkElementLayouter _layouter; #else private readonly static IEventProvider _trace = Tracing.Get(FrameworkElement.TraceProvider.Id); @@ -82,7 +82,7 @@ static class TraceProvider partial void Initialize() { -#if !__WASM__ +#if !NETSTANDARD2_0 _layouter = new FrameworkElementLayouter(this, MeasureOverride, ArrangeOverride); #endif Resources = new Windows.UI.Xaml.ResourceDictionary(); @@ -139,7 +139,7 @@ public bool IsParsing /// The size that this object determines it needs during layout, based on its calculations of the allocated sizes for child objects or based on other considerations such as a fixed container size. protected virtual Size MeasureOverride(Size availableSize) { -#if !__WASM__ +#if !NETSTANDARD2_0 LastAvailableSize = availableSize; #endif @@ -158,7 +158,7 @@ protected virtual Size ArrangeOverride(Size finalSize) if (child != null) { -#if __WASM__ +#if NETSTANDARD child.Arrange(new Rect(0, 0, finalSize.Width, finalSize.Height)); #else ArrangeElement(child, new Rect(0, 0, finalSize.Width, finalSize.Height)); @@ -171,7 +171,7 @@ protected virtual Size ArrangeOverride(Size finalSize) } } -#if !__WASM__ +#if !NETSTANDARD /// /// Updates the DesiredSize of a UIElement. Typically, objects that implement custom layout for their /// layout children call this method from their own MeasureOverride implementations to form a recursive layout update. @@ -223,7 +223,7 @@ public override void Arrange(Rect finalRect) /// The measured size - INCLUDES THE MARGIN protected Size MeasureElement(View view, Size availableSize) { -#if __WASM__ +#if NETSTANDARD view.Measure(availableSize); return view.DesiredSize; #else @@ -238,7 +238,7 @@ protected Size MeasureElement(View view, Size availableSize) /// The final size that the parent computes for the child in layout, provided as a value. protected void ArrangeElement(View view, Rect finalRect) { -#if __WASM__ +#if NETSTANDARD var adjust = GetBorderThickness(); // HTML moves the origin along with the border thickness. @@ -256,7 +256,7 @@ protected void ArrangeElement(View view, Rect finalRect) /// protected Size GetElementDesiredSize(View view) { -#if __WASM__ +#if NETSTANDARD return view.DesiredSize; #else return (_layouter as ILayouter).GetDesiredSize(view); @@ -509,6 +509,8 @@ internal virtual void OnLayoutUpdated() LayoutUpdated?.Invoke(this, new RoutedEventArgs(this)); } + private protected virtual Thickness GetBorderThickness() => Thickness.Empty; + #if XAMARIN private static FrameworkElement FindPhaseEnabledRoot(ContentControl content) { @@ -662,7 +664,7 @@ public AutomationPeer GetAutomationPeer() #endregion -#if !__WASM__ +#if !NETSTANDARD private class FrameworkElementLayouter : Layouter { private readonly MeasureOverrideHandler _measureOverrideHandler; diff --git a/src/Uno.UI/UI/Xaml/FrameworkElement.netstdref.cs b/src/Uno.UI/UI/Xaml/FrameworkElement.netstdref.cs new file mode 100644 index 000000000000..4f71008084a3 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/FrameworkElement.netstdref.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Windows.Foundation; +using View = Windows.UI.Xaml.UIElement; +using System.Collections; +using Uno.UI; + +namespace Windows.UI.Xaml +{ + public partial class FrameworkElement : IEnumerable + { + bool IFrameworkElementInternal.HasLayouter => true; + + internal List _children = new List(); + + partial void OnLoadingPartial(); + + private protected virtual void OnPostLoading() + { + } + + internal T AddChild(T child) where T : View + { + _children.Add(child); + OnAddChild(child); + + return child; + } + + internal T AddChild(T child, int index) where T : View + { + _children.Insert(index, child); + OnAddChild(child); + + return child; + } + + private void OnAddChild(View child) + { + } + + internal T RemoveChild(T child) where T : View + { + return child; + } + + internal View FindFirstChild() + { + return _children.FirstOrDefault(); + } + + internal virtual IEnumerable GetChildren() + { + return _children; + } + + internal bool HasParent() + { + return Parent != null; + } + + partial void OnMeasurePartial(Size slotSize) + { + + } + + internal void InternalArrange(Rect frame) + { + } + + partial void OnGenericPropertyUpdatedPartial(DependencyPropertyChangedEventArgs args); + + public bool IsLoaded { get; private set; } + + internal void ForceLoaded() + { + IsLoaded = true; + EnterTree(); + } + + private void EnterTree() + { + } + + internal int InvalidateMeasureCallCount { get; private set; } + + private bool IsTopLevelXamlView() => false; + + internal void SuspendRendering() => throw new NotSupportedException(); + + internal void ResumeRendering() => throw new NotSupportedException(); + public IEnumerator GetEnumerator() => _children.GetEnumerator(); + + public double ActualWidth => 0; + + public double ActualHeight => 0; + + internal Size UnclippedDesiredSize => new Size(); + + public global::System.Uri BaseUri { get; internal set; } + + private protected virtual double GetActualWidth() => ActualWidth; + private protected virtual double GetActualHeight() => ActualHeight; + +#pragma warning disable 67 + public event RoutedEventHandler Loading; + + public event RoutedEventHandler Loaded; + + public event RoutedEventHandler Unloaded; +#pragma warning restore 67 + } +} diff --git a/src/Uno.UI/UI/Xaml/Hosting/ElementCompositionPreview.cs b/src/Uno.UI/UI/Xaml/Hosting/ElementCompositionPreview.cs index 1fd1ff01da46..fca4789af980 100644 --- a/src/Uno.UI/UI/Xaml/Hosting/ElementCompositionPreview.cs +++ b/src/Uno.UI/UI/Xaml/Hosting/ElementCompositionPreview.cs @@ -1,23 +1,40 @@ -#pragma warning disable 108 // new keyword hiding -#pragma warning disable 114 // new keyword hiding +using System.Linq; + namespace Windows.UI.Xaml.Hosting { - public partial class ElementCompositionPreview - { - public static global::Windows.UI.Composition.Visual GetElementVisual(global::Windows.UI.Xaml.UIElement element) - { - return new Windows.UI.Composition.Visual() { NativeOwner = element }; - } + public partial class ElementCompositionPreview + { + private const string ChildVisualName = "childVisual"; + + public static global::Windows.UI.Composition.Visual GetElementVisual(global::Windows.UI.Xaml.UIElement element) + { +#if __SKIA__ + return element.Visual; +#else + return new Composition.Visual(null) { NativeOwner = element }; +#endif + } - public static void SetElementChildVisual(global::Windows.UI.Xaml.UIElement element, global::Windows.UI.Composition.Visual visual) - { + public static void SetElementChildVisual(global::Windows.UI.Xaml.UIElement element, global::Windows.UI.Composition.Visual visual) + { #if __IOS__ element.Layer.AddSublayer(visual.NativeLayer); visual.NativeOwner = element; element.ClipsToBounds = false; (element as FrameworkElement).SizeChanged += (s, e) => visual.NativeLayer.Frame = new CoreGraphics.CGRect(0, 0, element.Frame.Width, element.Frame.Height); +#elif __SKIA__ + + var container = new Composition.ContainerVisual(element.Visual.Compositor) { Comment = ChildVisualName }; + container.Children.InsertAtTop(visual); + + if (element.Visual.Children.FirstOrDefault(v => v.Comment == ChildVisualName) is Composition.ContainerVisual cv) + { + element.Visual.Children.Remove(cv); + } + + element.Visual.Children.InsertAtTop(container); #endif - } - } + } + } } diff --git a/src/Uno.UI/UI/Xaml/IFrameworkElementImplementation.Android.cs b/src/Uno.UI/UI/Xaml/IFrameworkElementImplementation.Android.cs index d951cf035d5e..95b61b5995bb 100644 --- a/src/Uno.UI/UI/Xaml/IFrameworkElementImplementation.Android.cs +++ b/src/Uno.UI/UI/Xaml/IFrameworkElementImplementation.Android.cs @@ -1,21 +1,31 @@  #pragma warning disable 108 +#pragma warning disable 109 // The member does not hide an accessible member. The new keyword is not required. -using System; -using Windows.Foundation; +using Android.Runtime; +using Android.Views; +using Android.Views.Accessibility; +using Uno.Diagnostics.Eventing; using Uno.Disposables; -using System.Runtime.CompilerServices; using Uno.Extensions; +using Uno.Logging; +using Uno.UI; using Uno.UI.DataBinding; +using Uno.UI.Extensions; +using Uno.UI.Media; +using System; +using System.ComponentModel; +using System.Runtime.CompilerServices; +using Windows.Foundation; using Windows.UI.Xaml; +using Windows.UI.Xaml.Automation; +using Windows.UI.Xaml.Automation.Peers; +using Windows.UI.Xaml.Automation.Provider; using Windows.UI.Xaml.Data; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media.Animation; -using Android.Views; -using Uno.UI.Extensions; using global::Windows.UI.Xaml.Input; using Point = Windows.Foundation.Point; -using Uno.UI; -using Uno.Diagnostics.Eventing; +using Uno.UI.Xaml; diff --git a/src/Uno.UI/UI/Xaml/IFrameworkElementImplementation.iOS.tt b/src/Uno.UI/UI/Xaml/IFrameworkElementImplementation.iOS.tt index cff7f5d1ad03..d67d73241838 100644 --- a/src/Uno.UI/UI/Xaml/IFrameworkElementImplementation.iOS.tt +++ b/src/Uno.UI/UI/Xaml/IFrameworkElementImplementation.iOS.tt @@ -32,7 +32,7 @@ using Uno.UI.Xaml; namespace <#= mixin.NamespaceName #> { - public partial class <#= mixin.ClassName #> : IFrameworkElement, IXUidProvider, IFrameworkElementInternal + partial class <#= mixin.ClassName #> : IFrameworkElement, IXUidProvider, IFrameworkElementInternal { string IXUidProvider.Uid { get; set; } diff --git a/src/Uno.UI/UI/Xaml/IFrameworkElementImplementation.macOS.tt b/src/Uno.UI/UI/Xaml/IFrameworkElementImplementation.macOS.tt index 0b73de087551..af1879a9425f 100644 --- a/src/Uno.UI/UI/Xaml/IFrameworkElementImplementation.macOS.tt +++ b/src/Uno.UI/UI/Xaml/IFrameworkElementImplementation.macOS.tt @@ -32,7 +32,7 @@ using Uno.UI.Xaml; namespace <#= mixin.NamespaceName #> { - public partial class <#= mixin.ClassName #> : IFrameworkElement, IXUidProvider, IFrameworkElementInternal + partial class <#= mixin.ClassName #> : IFrameworkElement, IXUidProvider, IFrameworkElementInternal { string IXUidProvider.Uid { get; set; } diff --git a/src/Uno.UI/UI/Xaml/Input/FocusManager.net.cs b/src/Uno.UI/UI/Xaml/Input/FocusManager.net.cs index 65691aff6658..671aad2701da 100644 --- a/src/Uno.UI/UI/Xaml/Input/FocusManager.net.cs +++ b/src/Uno.UI/UI/Xaml/Input/FocusManager.net.cs @@ -55,11 +55,6 @@ private static DependencyObject InnerFindLastFocusableElement(DependencyObject s throw new NotImplementedException(); } - public static void OnFocusChanged(View control, FocusState state) - { - throw new NotImplementedException(); - } - private static void FocusNative(object toFocus) { } } } diff --git a/src/Uno.UI/UI/Xaml/Input/FocusManager.netstdref.cs b/src/Uno.UI/UI/Xaml/Input/FocusManager.netstdref.cs new file mode 100644 index 000000000000..671aad2701da --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Input/FocusManager.netstdref.cs @@ -0,0 +1,60 @@ +using System; +using Uno.UI; +using System.Collections.Generic; +using System.Linq; +using Windows.UI.Xaml.Controls; + +using View = Windows.UI.Xaml.UIElement; + +namespace Windows.UI.Xaml.Input +{ + public partial class FocusManager + { + private static View InnerGetFocusedElement() + { + throw new NotImplementedException(); + } + + private static bool InnerTryMoveFocus(FocusNavigationDirection focusNavigationDirection) + { + throw new NotImplementedException(); + } + + /// + /// Enumerates focusable views ordered by "cousin level". + /// "Sister" views will be returned first, then first cousins, then second cousins, and so on. + /// + private static IEnumerable SearchOtherFocusableViews(View currentView) + { + throw new NotImplementedException(); + } + + + private static bool IsFocusableView(View view) + { + throw new NotImplementedException(); + } + + private static int[] GetAbsolutePosition(View v) + { + throw new NotImplementedException(); + } + + public static View InnerFindNextFocusableElement(FocusNavigationDirection focusNavigationDirection) + { + throw new NotImplementedException(); + } + + public static DependencyObject InnerFindFirstFocusableElement(DependencyObject searchScope) + { + throw new NotImplementedException(); + } + + private static DependencyObject InnerFindLastFocusableElement(DependencyObject searchScope) + { + throw new NotImplementedException(); + } + + private static void FocusNative(object toFocus) { } + } +} diff --git a/src/Uno.UI/UI/Xaml/Input/FocusManager.skia.cs b/src/Uno.UI/UI/Xaml/Input/FocusManager.skia.cs new file mode 100644 index 000000000000..671aad2701da --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Input/FocusManager.skia.cs @@ -0,0 +1,60 @@ +using System; +using Uno.UI; +using System.Collections.Generic; +using System.Linq; +using Windows.UI.Xaml.Controls; + +using View = Windows.UI.Xaml.UIElement; + +namespace Windows.UI.Xaml.Input +{ + public partial class FocusManager + { + private static View InnerGetFocusedElement() + { + throw new NotImplementedException(); + } + + private static bool InnerTryMoveFocus(FocusNavigationDirection focusNavigationDirection) + { + throw new NotImplementedException(); + } + + /// + /// Enumerates focusable views ordered by "cousin level". + /// "Sister" views will be returned first, then first cousins, then second cousins, and so on. + /// + private static IEnumerable SearchOtherFocusableViews(View currentView) + { + throw new NotImplementedException(); + } + + + private static bool IsFocusableView(View view) + { + throw new NotImplementedException(); + } + + private static int[] GetAbsolutePosition(View v) + { + throw new NotImplementedException(); + } + + public static View InnerFindNextFocusableElement(FocusNavigationDirection focusNavigationDirection) + { + throw new NotImplementedException(); + } + + public static DependencyObject InnerFindFirstFocusableElement(DependencyObject searchScope) + { + throw new NotImplementedException(); + } + + private static DependencyObject InnerFindLastFocusableElement(DependencyObject searchScope) + { + throw new NotImplementedException(); + } + + private static void FocusNative(object toFocus) { } + } +} diff --git a/src/Uno.UI/UI/Xaml/Input/PointerRoutedEventArgs.skia.cs b/src/Uno.UI/UI/Xaml/Input/PointerRoutedEventArgs.skia.cs new file mode 100644 index 000000000000..917f460fcf69 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Input/PointerRoutedEventArgs.skia.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using Windows.Devices.Input; +using Uno; +using Windows.Foundation; +using Windows.UI.Input; +using Windows.UI.Xaml.Media; +using Windows.UI.Core; + +namespace Windows.UI.Xaml.Input +{ + partial class PointerRoutedEventArgs + { + private readonly PointerEventArgs _pointerEventArgs; + private readonly Point _absolutePosition; + private static long _pseudoNextFrameId; + private readonly uint _pseudoFrameId = (uint)Interlocked.Increment(ref _pseudoNextFrameId); + private readonly ulong _pseudoTimestamp = (ulong)DateTime.UtcNow.Ticks; + + internal PointerRoutedEventArgs( + PointerEventArgs pointerEventArgs, + Pointer pointer, + UIElement source) : this() + { + _pointerEventArgs = pointerEventArgs; + _absolutePosition = pointerEventArgs.CurrentPoint.RawPosition; + + FrameId = _pseudoFrameId; + Pointer = pointer; + OriginalSource = source; + } + + public PointerPoint GetCurrentPoint(UIElement relativeTo) + { + var device = PointerDevice.For(PointerDeviceType.Mouse); + var position = relativeTo == null + ? _absolutePosition + : relativeTo.TransformToVisual(null).Inverse.TransformPoint(_absolutePosition); + + var properties = _pointerEventArgs.CurrentPoint.Properties; + + return new PointerPoint(FrameId, _pseudoTimestamp, device, 0, _absolutePosition, position, true, properties); + } + } +} diff --git a/src/Uno.UI/UI/Xaml/Media/Animation/Animators/AnimatorFactory.Skia.cs b/src/Uno.UI/UI/Xaml/Media/Animation/Animators/AnimatorFactory.Skia.cs new file mode 100644 index 000000000000..12f4944a0700 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Media/Animation/Animators/AnimatorFactory.Skia.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Uno.Extensions; +using Uno.Logging; +using Windows.UI; + +namespace Windows.UI.Xaml.Media.Animation +{ + internal static partial class AnimatorFactory + { + internal static IValueAnimator Create(Timeline timeline, double startingValue, double targetValue) + { + return new DispatcherFloatAnimator((float)startingValue, (float)targetValue); + } + + private static IValueAnimator CreateDouble(Timeline timeline, double startingValue, double targetValue) + { + return new NotSupportedAnimator(); + } + + private static IValueAnimator CreateColor(Timeline timeline, ColorOffset startingValue, ColorOffset targetValue) + { + return new NotSupportedAnimator(); + } + } +} diff --git a/src/Uno.UI/UI/Xaml/Media/Animation/Animators/AnimatorFactory.netstdref.cs b/src/Uno.UI/UI/Xaml/Media/Animation/Animators/AnimatorFactory.netstdref.cs new file mode 100644 index 000000000000..d7d807b84d0b --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Media/Animation/Animators/AnimatorFactory.netstdref.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Uno.Extensions; +using Uno.Logging; +using Windows.UI; + +namespace Windows.UI.Xaml.Media.Animation +{ + internal static partial class AnimatorFactory + { + /// + /// Creates the actual animator instance + /// + private static IValueAnimator CreateDouble(Timeline timeline, double startingValue, double targetValue) + { + return new NotSupportedAnimator(); + } + + private static IValueAnimator CreateColor(Timeline timeline, ColorOffset startingValue, ColorOffset targetValue) + { + return new NotSupportedAnimator(); + } + } +} diff --git a/src/Uno.UI/UI/Xaml/Media/Animation/ColorAnimationUsingKeyFrames.netstdref.cs b/src/Uno.UI/UI/Xaml/Media/Animation/ColorAnimationUsingKeyFrames.netstdref.cs new file mode 100644 index 000000000000..b987c858595e --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Media/Animation/ColorAnimationUsingKeyFrames.netstdref.cs @@ -0,0 +1,11 @@ +namespace Windows.UI.Xaml.Media.Animation +{ + partial class ColorAnimationUsingKeyFrames + { + private bool ReportEachFrame() => true; + + partial void OnFrame(IValueAnimator currentAnimator) + { + } + } +} diff --git a/src/Uno.UI/UI/Xaml/Media/Animation/ColorAnimationUsingKeyFrames.skia.cs b/src/Uno.UI/UI/Xaml/Media/Animation/ColorAnimationUsingKeyFrames.skia.cs new file mode 100644 index 000000000000..b987c858595e --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Media/Animation/ColorAnimationUsingKeyFrames.skia.cs @@ -0,0 +1,11 @@ +namespace Windows.UI.Xaml.Media.Animation +{ + partial class ColorAnimationUsingKeyFrames + { + private bool ReportEachFrame() => true; + + partial void OnFrame(IValueAnimator currentAnimator) + { + } + } +} diff --git a/src/Uno.UI/UI/Xaml/Media/Animation/DoubleAnimation.Skia.cs b/src/Uno.UI/UI/Xaml/Media/Animation/DoubleAnimation.Skia.cs new file mode 100644 index 000000000000..192297b76601 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Media/Animation/DoubleAnimation.Skia.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Windows.UI.Xaml.Media.Animation +{ + public partial class DoubleAnimation + { + } +} diff --git a/src/Uno.UI/UI/Xaml/Media/Animation/DoubleAnimationUsingKeyFrames.netstdref.cs b/src/Uno.UI/UI/Xaml/Media/Animation/DoubleAnimationUsingKeyFrames.netstdref.cs new file mode 100644 index 000000000000..c9ded862acd0 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Media/Animation/DoubleAnimationUsingKeyFrames.netstdref.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Windows.UI.Xaml.Media.Animation +{ + public partial class DoubleAnimationUsingKeyFrames + { + private bool ReportEachFrame() => true; + } +} diff --git a/src/Uno.UI/UI/Xaml/Media/Animation/DoubleAnimationUsingKeyFrames.skia.cs b/src/Uno.UI/UI/Xaml/Media/Animation/DoubleAnimationUsingKeyFrames.skia.cs new file mode 100644 index 000000000000..c9ded862acd0 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Media/Animation/DoubleAnimationUsingKeyFrames.skia.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Windows.UI.Xaml.Media.Animation +{ + public partial class DoubleAnimationUsingKeyFrames + { + private bool ReportEachFrame() => true; + } +} diff --git a/src/Uno.UI/UI/Xaml/Media/Animation/Timeline.animation.netstdref.cs b/src/Uno.UI/UI/Xaml/Media/Animation/Timeline.animation.netstdref.cs new file mode 100644 index 000000000000..85fce97936af --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Media/Animation/Timeline.animation.netstdref.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Windows.UI.Xaml.Media.Animation +{ + partial class Timeline + { + partial class AnimationImplementation + { + private bool ReportEachFrame() => true; + } + } +} diff --git a/src/Uno.UI/UI/Xaml/Media/Animation/Timeline.animation.skia.cs b/src/Uno.UI/UI/Xaml/Media/Animation/Timeline.animation.skia.cs new file mode 100644 index 000000000000..85fce97936af --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Media/Animation/Timeline.animation.skia.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Windows.UI.Xaml.Media.Animation +{ + partial class Timeline + { + partial class AnimationImplementation + { + private bool ReportEachFrame() => true; + } + } +} diff --git a/src/Uno.UI/UI/Xaml/Media/Brush.Skia.cs b/src/Uno.UI/UI/Xaml/Media/Brush.Skia.cs new file mode 100644 index 000000000000..eb8a5c12a1f9 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Media/Brush.Skia.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Uno.Extensions; +using Uno.Disposables; +using Windows.UI; + +namespace Windows.UI.Xaml.Media +{ + public abstract partial class Brush + { + internal static IDisposable AssignAndObserveBrush(Brush b, Action colorSetter, Action imageBrushCallback = null) + { + var disposables = new CompositeDisposable(); + + if (b != null) + { + var colorBrush = b as SolidColorBrush; + var imageBrush = b as ImageBrush; + + if (colorBrush != null) + { + colorSetter(colorBrush.ColorWithOpacity); + + colorBrush.RegisterDisposablePropertyChangedCallback( + SolidColorBrush.ColorProperty, + (s, colorArg) => colorSetter((s as SolidColorBrush).ColorWithOpacity) + ) + .DisposeWith(disposables); + + colorBrush.RegisterDisposablePropertyChangedCallback( + SolidColorBrush.OpacityProperty, + (s, colorArg) => colorSetter((s as SolidColorBrush).ColorWithOpacity) + ) + .DisposeWith(disposables); + } + //else if (imageBrush != null) + //{ + // Action<_Image> action = _ => colorSetter(SolidColorBrushHelper.Transparent.Color); + + // imageBrush.ImageChanged += action; + + // disposables.Add(() => imageBrush.ImageChanged -= action); + //} + else + { + colorSetter(SolidColorBrushHelper.Transparent.Color); + } + } + else + { + colorSetter(SolidColorBrushHelper.Transparent.Color); + } + + return disposables; + } + + } +} diff --git a/src/Uno.UI/UI/Xaml/Media/ImageSource.skia.cs b/src/Uno.UI/UI/Xaml/Media/ImageSource.skia.cs new file mode 100644 index 000000000000..4b65bab903d6 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Media/ImageSource.skia.cs @@ -0,0 +1,32 @@ +using Uno.Extensions; +using Uno.Logging; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Net.Http; +using System.ComponentModel; +using System.Runtime.CompilerServices; +using Uno; +using Uno.Diagnostics.Eventing; +using Windows.UI.Xaml.Media.Imaging; + +namespace Windows.UI.Xaml.Media +{ + partial class ImageSource + { + protected ImageSource() + { + + } + + partial void InitFromResource(Uri uri) + { + WebUri = uri; + } + + internal void UnloadImageData() { } + } +} diff --git a/src/Uno.UI/UI/Xaml/Media/SolidColorBrush.Skia.cs b/src/Uno.UI/UI/Xaml/Media/SolidColorBrush.Skia.cs new file mode 100644 index 000000000000..cb25da1ddd1e --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Media/SolidColorBrush.Skia.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Uno.Extensions; + +namespace Windows.UI.Xaml.Media +{ + public partial class SolidColorBrush : Brush + { + } +} diff --git a/src/Uno.UI/UI/Xaml/Shapes/ArbitraryShapeBase.Skia.cs b/src/Uno.UI/UI/Xaml/Shapes/ArbitraryShapeBase.Skia.cs new file mode 100644 index 000000000000..6c06f4efc2d3 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Shapes/ArbitraryShapeBase.Skia.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Uno.Disposables; +using System.Text; +using Windows.Foundation; + +namespace Windows.UI.Xaml.Shapes +{ + public abstract partial class ArbitraryShapeBase : Shape + { +#pragma warning disable 649 // unused member + private float _scaleX; + private float _scaleY; +#pragma warning restore 649 // unused member + + private IDisposable BuildDrawableLayer() { return null; } + + private Windows.Foundation.Size GetActualSize() { return Size.Empty; } + } +} diff --git a/src/Uno.UI/UI/Xaml/Shapes/ArbitraryShapeBase.cs b/src/Uno.UI/UI/Xaml/Shapes/ArbitraryShapeBase.cs index 1db37a781e6c..29fd4848c8b3 100644 --- a/src/Uno.UI/UI/Xaml/Shapes/ArbitraryShapeBase.cs +++ b/src/Uno.UI/UI/Xaml/Shapes/ArbitraryShapeBase.cs @@ -22,7 +22,7 @@ protected static double LimitWithUserSize(double availableSize, double userSize, var hasUserSize = userSize != 0 && !double.IsNaN(userSize) && !double.IsInfinity(userSize); var hasAvailableSize = !double.IsNaN(availableSize); -#if __WASM__ +#if NETSTANDARD // The measuring algorithms for shapes in Wasm and iOS/Android/macOS are not using the // infinity the same way. // Those implementation will need to be merged. @@ -43,7 +43,7 @@ protected static double LimitWithUserSize(double availableSize, double userSize, return naNFallbackValue; } -#if !__WASM__ +#if !NETSTANDARD protected internal override void OnInvalidateMeasure() { base.OnInvalidateMeasure(); diff --git a/src/Uno.UI/UI/Xaml/Shapes/ArbitraryShapeBase.netstdref.cs b/src/Uno.UI/UI/Xaml/Shapes/ArbitraryShapeBase.netstdref.cs new file mode 100644 index 000000000000..152fec136493 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Shapes/ArbitraryShapeBase.netstdref.cs @@ -0,0 +1,19 @@ +using System; +using System.Diagnostics; +using System.Globalization; +using Windows.Foundation; +using Windows.UI.Xaml.Media; +using Uno.Disposables; +using System.Numerics; +using Uno.UI; + +namespace Windows.UI.Xaml.Shapes +{ + partial class ArbitraryShapeBase + { +#pragma warning disable CS0067, CS0649 + private double _scaleX; + private double _scaleY; +#pragma warning restore CS0067, CS0649 + } +} diff --git a/src/Uno.UI/UI/Xaml/Shapes/Ellipse.Skia.cs b/src/Uno.UI/UI/Xaml/Shapes/Ellipse.Skia.cs new file mode 100644 index 000000000000..66f8672569cc --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Shapes/Ellipse.Skia.cs @@ -0,0 +1,27 @@ +using Windows.Foundation; +using Uno.Extensions; +using Windows.UI.Composition; +using System.Numerics; +using SkiaSharp; + +namespace Windows.UI.Xaml.Shapes +{ + partial class Ellipse + { + private ShapeVisual _rectangleVisual; + + public Ellipse() + { + _rectangleVisual = Visual.Compositor.CreateShapeVisual(); + Visual.Children.InsertAtBottom(_rectangleVisual); + } + + internal override SkiaGeometrySource2D GetGeometry(Size finalSize) + { + var geometry = new SkiaGeometrySource2D(); + geometry.Geometry.AddOval(new SKRect(0, 0, (float)finalSize.Width, (float)finalSize.Height)); + + return geometry; + } + } +} diff --git a/src/Uno.UI/UI/Xaml/Shapes/Path.Skia.cs b/src/Uno.UI/UI/Xaml/Shapes/Path.Skia.cs new file mode 100644 index 000000000000..36ce8a066eb5 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Shapes/Path.Skia.cs @@ -0,0 +1,74 @@ +using System; +using Uno.Disposables; +using Uno.Media; +using Windows.Foundation; +using Windows.Graphics; +using Windows.UI.Composition; +using Windows.UI.Xaml.Media; + +namespace Windows.UI.Xaml.Shapes +{ + partial class Path + { + internal override SkiaGeometrySource2D GetGeometry(Size finalSize) + { + switch (Data) + { + case PathGeometry pg: + return ToGeometrySource2D(pg); + case StreamGeometry sg: + return sg.GetGeometrySource2D(); + } + + throw new NotSupportedException($"Geometry {Data} is not supported"); + } + + private SkiaGeometrySource2D ToGeometrySource2D(PathGeometry geometry) + { + var skiaGeometry = new SkiaGeometrySource2D(); + + foreach (PathFigure figure in geometry.Figures) + { + skiaGeometry.Geometry.MoveTo((float)figure.StartPoint.X, (float)figure.StartPoint.Y); + + foreach (PathSegment segment in figure.Segments) + { + if (segment is LineSegment lineSegment) + { + skiaGeometry.Geometry.LineTo((float)lineSegment.Point.X, (float)lineSegment.Point.Y); + } + else if (segment is BezierSegment bezierSegment) + { + skiaGeometry.Geometry.CubicTo( + (float)bezierSegment.Point1.X, (float)bezierSegment.Point1.Y, + (float)bezierSegment.Point2.X, (float)bezierSegment.Point2.Y, + (float)bezierSegment.Point3.X, (float)bezierSegment.Point3.Y); + } + else if (segment is QuadraticBezierSegment quadraticBezierSegment) + { + skiaGeometry.Geometry.QuadTo( + (float)quadraticBezierSegment.Point1.X, (float)quadraticBezierSegment.Point1.Y, + (float)quadraticBezierSegment.Point2.X, (float)quadraticBezierSegment.Point2.Y); + } + else if (segment is ArcSegment arcSegment) + { + skiaGeometry.Geometry.ArcTo( + (float)arcSegment.Size.Width, (float)arcSegment.Size.Height, + (float)arcSegment.RotationAngle, + arcSegment.IsLargeArc ? SkiaSharp.SKPathArcSize.Large : SkiaSharp.SKPathArcSize.Small, + (arcSegment.SweepDirection == SweepDirection.Clockwise ? SkiaSharp.SKPathDirection.Clockwise : SkiaSharp.SKPathDirection.CounterClockwise), + (float)arcSegment.Point.X, (float)arcSegment.Point.Y); + } + } + + if (figure.IsClosed) + { + skiaGeometry.Geometry.Close(); + } + } + + return skiaGeometry; + } + + } +} diff --git a/src/Uno.UI/UI/Xaml/Shapes/Rectangle.Skia.cs b/src/Uno.UI/UI/Xaml/Shapes/Rectangle.Skia.cs new file mode 100644 index 000000000000..f9e46e4c756f --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Shapes/Rectangle.Skia.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Windows.UI.Xaml.Media; +using Uno.Extensions; +using System.Linq; +using Uno.Disposables; +using Uno.UI.Extensions; +using Uno.UI; +using Windows.UI.Composition; +using Windows.Foundation; +using Windows.Graphics; + +namespace Windows.UI.Xaml.Shapes +{ + public partial class Rectangle + { + + public Rectangle() + { + } + + internal override SkiaGeometrySource2D GetGeometry(Size finalSize) + { + var area = new Rect(0, 0, finalSize.Width, finalSize.Height); + + switch (Stretch) + { + default: + case Stretch.None: + break; + case Stretch.Fill: + area = new Rect(0, 0, finalSize.Width, finalSize.Height); + break; + case Stretch.Uniform: + area = (area.Height > area.Width) + ? (new Rect((float)area.X, (float)area.Y, (float)area.Width, (float)area.Width)) + : (new Rect((float)area.X, (float)area.Y, (float)area.Height, (float)area.Height)); + break; + case Stretch.UniformToFill: + area = (area.Height > area.Width) + ? (new Rect((float)area.X, (float)area.Y, (float)area.Height, (float)area.Height)) + : (new Rect((float)area.X, (float)area.Y, (float)area.Width, (float)area.Width)); + break; + } + + var shrinkValue = -ActualStrokeThickness / 2; + if (area != Rect.Empty) + { + area.Inflate(shrinkValue, shrinkValue); + } + + var geometry = new SkiaGeometrySource2D(); + + if (Math.Max(RadiusX, RadiusY) > 0) + { + geometry.Geometry.AddRoundRect(area.ToSKRect(), (float)RadiusX, (float)RadiusY); + } + else + { + geometry.Geometry.AddRect(area.ToSKRect()); + } + + return geometry; + } + + + partial void OnRadiusXChangedPartial() + { + InvalidateMeasure(); + } + + partial void OnRadiusYChangedPartial() + { + InvalidateMeasure(); + } + + } +} diff --git a/src/Uno.UI/UI/Xaml/Shapes/Shape.Skia.cs b/src/Uno.UI/UI/Xaml/Shapes/Shape.Skia.cs new file mode 100644 index 000000000000..da1e05945fb0 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Shapes/Shape.Skia.cs @@ -0,0 +1,174 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Collections.Specialized; +using System.Globalization; +using System.Linq; +using System.Threading; +using Windows.Foundation; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Media; +using Uno.Extensions; +using Windows.UI.Composition; +using Uno.Disposables; +using System.IO.Compression; + +namespace Windows.UI.Xaml.Shapes +{ + [Markup.ContentProperty(Name = "SvgChildren")] + partial class Shape + { + private ShapeVisual _rectangleVisual; + private SerialDisposable _fillSubscription = new SerialDisposable(); + private SerialDisposable _strokeSubscription = new SerialDisposable(); + private CompositionSpriteShape _pathSpriteShape; + + public Shape() + { + _rectangleVisual = Visual.Compositor.CreateShapeVisual(); + Visual.Children.InsertAtBottom(_rectangleVisual); + + InitCommonShapeProperties(); + } + + internal virtual SkiaGeometrySource2D GetGeometry(Size finalSize) + { + throw new NotSupportedException($"Path.GetGeometry must be implemented"); + } + + private void InitCommonShapeProperties() { } + + protected override Size MeasureOverride(Size availableSize) + { + var geometrySource = GetGeometry(availableSize); + + return new Size(geometrySource.Geometry.Bounds.Width, geometrySource.Geometry.Bounds.Height); + } + + protected override Size ArrangeOverride(Size finalSize) + { + var area = new Rect(0, 0, finalSize.Width, finalSize.Height); + + switch (Stretch) + { + default: + case Stretch.None: + break; + case Stretch.Fill: + area = new Rect(0, 0, finalSize.Width, finalSize.Height); + break; + case Stretch.Uniform: + area = (area.Height > area.Width) + ? (new Rect((float)area.X, (float)area.Y, (float)area.Width, (float)area.Width)) + : (new Rect((float)area.X, (float)area.Y, (float)area.Height, (float)area.Height)); + break; + case Stretch.UniformToFill: + area = (area.Height > area.Width) + ? (new Rect((float)area.X, (float)area.Y, (float)area.Height, (float)area.Height)) + : (new Rect((float)area.X, (float)area.Y, (float)area.Width, (float)area.Width)); + break; + } + + var shrinkValue = -ActualStrokeThickness / 2; + if (area != Rect.Empty) + { + area.Inflate(shrinkValue, shrinkValue); + } + + var geometrySource = GetGeometry(finalSize); + var compositionPath = new CompositionPath(geometrySource); + var pathGeometry = Visual.Compositor.CreatePathGeometry(); + pathGeometry.Path = compositionPath; + + _pathSpriteShape = Visual.Compositor.CreateSpriteShape(pathGeometry); + + _rectangleVisual.Shapes.Clear(); + _rectangleVisual.Shapes.Add(_pathSpriteShape); + + UpdateFill(); + UpdateStroke(); + UpdateStrokeThickness(); + return finalSize; // geometrySource.Geometry.Bounds.Size.ToSize(); + } + + partial void OnStrokeUpdatedPartial() + { + UpdateStroke(); + + InvalidateMeasure(); + } + + + partial void OnFillUpdatedPartial() + { + UpdateFill(); + + InvalidateMeasure(); + } + + partial void OnStrokeThicknessUpdatedPartial() + { + if (StrokeThickness > 0 && StrokeThickness < 1) + { + StrokeThickness = 1; + return; + } + + UpdateStrokeThickness(); + + InvalidateMeasure(); + } + + partial void OnStrokeDashArrayUpdatedPartial() + { + // _rectangleLayer.LineDashPattern = newValue.Safe().Select(d => new NSNumber(d)).ToArray(); + + InvalidateMeasure(); + } + + partial void OnStretchUpdatedPartial() + { + InvalidateMeasure(); + } + + private void UpdateFill() + { + if (_pathSpriteShape != null) + { + _fillSubscription.Disposable = null; + + _pathSpriteShape.FillBrush = null; + + var scbFill = Fill as SolidColorBrush; + var lgbFill = Fill as LinearGradientBrush; + if (scbFill != null) + { + _fillSubscription.Disposable = + Brush.AssignAndObserveBrush(scbFill, c => _pathSpriteShape.FillBrush = Visual.Compositor.CreateColorBrush(scbFill.Color)); + } + else if (lgbFill != null) + { + } + } + } + + private void UpdateStrokeThickness() + { + if (_pathSpriteShape != null) + { + _pathSpriteShape.StrokeThickness = (float)StrokeThickness; + } + } + + private void UpdateStroke() + { + var brush = Stroke as SolidColorBrush ?? SolidColorBrushHelper.Transparent; + + if (_pathSpriteShape != null) + { + _strokeSubscription.Disposable = + Brush.AssignAndObserveBrush(brush, c => _pathSpriteShape.StrokeBrush = Visual.Compositor.CreateColorBrush(brush.Color)); + } + } + } +} diff --git a/src/Uno.UI/UI/Xaml/UIElement.Layout.wasm.cs b/src/Uno.UI/UI/Xaml/UIElement.Layout.netstd.cs similarity index 98% rename from src/Uno.UI/UI/Xaml/UIElement.Layout.wasm.cs rename to src/Uno.UI/UI/Xaml/UIElement.Layout.netstd.cs index a45d0407f04b..383a23119e39 100644 --- a/src/Uno.UI/UI/Xaml/UIElement.Layout.wasm.cs +++ b/src/Uno.UI/UI/Xaml/UIElement.Layout.netstd.cs @@ -1,4 +1,5 @@ -using Windows.Foundation; +#if !__NETSTD_REFERENCE__ +using Windows.Foundation; using System; namespace Windows.UI.Xaml @@ -162,3 +163,4 @@ internal set } } } +#endif diff --git a/src/Uno.UI/UI/Xaml/UIElement.Pointers.Skia.cs b/src/Uno.UI/UI/Xaml/UIElement.Pointers.Skia.cs new file mode 100644 index 000000000000..74953de24ff5 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/UIElement.Pointers.Skia.cs @@ -0,0 +1,328 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using Windows.Devices.Input; +using Windows.UI.Input; +using Windows.UI.Xaml.Input; +using Microsoft.Extensions.Logging; +using Uno.Extensions; +using Uno.Logging; +using Uno.Foundation.Extensibility; +using Windows.UI.Core; +using Windows.Foundation; + +namespace Windows.UI.Xaml +{ + partial class UIElement + { + private class PointerManager + { + public PointerManager() + { + Window.Current.CoreWindow.PointerMoved += CoreWindow_PointerMoved; + Window.Current.CoreWindow.PointerEntered += CoreWindow_PointerEntered; + Window.Current.CoreWindow.PointerExited += CoreWindow_PointerExited; + Window.Current.CoreWindow.PointerPressed += CoreWindow_PointerPressed; + Window.Current.CoreWindow.PointerReleased += CoreWindow_PointerReleased; + Window.Current.CoreWindow.PointerWheelChanged += CoreWindow_PointerWheelChanged; + } + + private void CoreWindow_PointerWheelChanged(CoreWindow sender, PointerEventArgs args) + { + if (this.Log().IsEnabled(LogLevel.Trace)) + { + this.Log().Trace($"CoreWindow_PointerWheelChanged ({args.CurrentPoint.Position})"); + } + + PropagateEvent(args, e => + { + var pointer = new Pointer(args.CurrentPoint.PointerId, PointerDeviceType.Mouse, false, isInRange: true); + var pointerArgs = new PointerRoutedEventArgs(args, pointer, e) { CanBubbleNatively = true }; + TraverseAncestors(e, pointerArgs, e2 => e2.OnNativePointerWheel(pointerArgs)); + }); + } + + private void CoreWindow_PointerEntered(CoreWindow sender, PointerEventArgs args) + { + if (this.Log().IsEnabled(LogLevel.Trace)) + { + this.Log().Trace($"CoreWindow_PointerEntered ({args.CurrentPoint.Position})"); + } + } + + private void CoreWindow_PointerExited(CoreWindow sender, PointerEventArgs args) + { + if (this.Log().IsEnabled(LogLevel.Trace)) + { + this.Log().Trace($"CoreWindow_PointerExited ({args.CurrentPoint.Position})"); + } + + + } + + private void CoreWindow_PointerReleased(CoreWindow sender, PointerEventArgs args) + { + if (this.Log().IsEnabled(LogLevel.Trace)) + { + this.Log().Trace($"CoreWindow_PointerReleased ({args.CurrentPoint.Position})"); + } + + var pointer = new Pointer(args.CurrentPoint.PointerId, PointerDeviceType.Mouse, false, isInRange: true); + if (UIElement.PointerCapture.TryGet(pointer, out var capture)) + { + foreach(var target in capture.Targets) + { + var pointerArgs = new PointerRoutedEventArgs(args, pointer, target.Element) { CanBubbleNatively = true }; + TraverseAncestors(target.Element, pointerArgs, e => e.OnNativePointerUp(pointerArgs)); + } + } + else + { + PropagateEvent(args, e => + { + // Console.WriteLine($"PointerManager.Released [{e}/{e.GetHashCode():X8}"); + var pointerArgs = new PointerRoutedEventArgs(args, pointer, e) { CanBubbleNatively = true }; + TraverseAncestors(e, pointerArgs, e2 => e2.OnNativePointerUp(pointerArgs)); + }); + } + } + + private void CoreWindow_PointerPressed(CoreWindow sender, PointerEventArgs args) + { + if (this.Log().IsEnabled(LogLevel.Trace)) + { + this.Log().Trace($"CoreWindow_PointerPressed ({args.CurrentPoint.Position})"); + } + + PropagateEvent(args, e => + { + // Console.WriteLine($"PointerManager.Pressed [{e}/{e.GetHashCode():X8}"); + var pointer = new Pointer(args.CurrentPoint.PointerId, PointerDeviceType.Mouse, false, isInRange: true); + var pointerArgs = new PointerRoutedEventArgs(args, pointer, e) { CanBubbleNatively = true }; + TraverseAncestors(e, pointerArgs, e2 => e2.OnNativePointerDown(pointerArgs)); + }); + } + + private void CoreWindow_PointerMoved(CoreWindow sender, PointerEventArgs args) + { + if (this.Log().IsEnabled(LogLevel.Trace)) + { + this.Log().Trace($"CoreWindow_PointerMoved ({args.CurrentPoint.Position})"); + } + + var pointer = new Pointer(args.CurrentPoint.PointerId, PointerDeviceType.Mouse, false, isInRange: true); + + if (UIElement.PointerCapture.TryGet(pointer, out var capture)) + { + foreach (var target in capture.Targets) + { + var pointerArgs = new PointerRoutedEventArgs(args, pointer, target.Element) { CanBubbleNatively = true }; + + TraverseAncestors(target.Element, pointerArgs, e => e.OnNativePointerMove(pointerArgs)); + } + } + else + { + PropagateEvent(args, e => + { + var pointerArgs = new PointerRoutedEventArgs(args, pointer, e) { CanBubbleNatively = true }; + TraverseAncestors(e, pointerArgs, e2 => e2.OnNativePointerMove(pointerArgs)); + }); + } + } + + private void TraverseAncestors(UIElement element, PointerRoutedEventArgs args, Action action) + { + action(element); + + foreach(var parent in element.GetParents().OfType()) + { + action(parent); + + if (args.Handled) + { + break; + } + } + } + + private void PropagateEvent(PointerEventArgs args, Action raiseEvent) + { + if(Window.Current.Content is UIElement root) + { + PropagageEventRecursive(args, new Point(0, 0), root, raiseEvent); + } + } + + private bool PropagageEventRecursive(PointerEventArgs args, Point root, UIElement element, Action raiseEvent) + { + bool raised = false; + var rect = element.LayoutSlotWithMarginsAndAlignments; + rect.X += root.X; + rect.Y += root.Y; + + var position = args.CurrentPoint.Position; + + if (element.RenderTransform != null) + { + position = element.RenderTransform.Inverse.TransformPoint(position); + } + + if (position.X >= rect.X + && position.Y >= rect.Y + && position.X <= rect.X + rect.Width + && position.Y <= rect.Y + rect.Height) + { + + foreach (var e in element.GetChildren().ToArray()) + { + raised |= PropagageEventRecursive(args, rect.Location, e, raiseEvent); + } + + var isHitTestVisible = + element.GetValue(HitTestVisibilityProperty) is HitTestVisibility hitTestVisibility + && hitTestVisibility == HitTestVisibility.Visible; + + if (!raised && isHitTestVisible) + { + if (!element._pointerEntered) + { + // Console.WriteLine($"PointerManager.Entered [{element}/{element.GetHashCode():X8}"); + element._pointerEntered = true; + + var pointer = new Pointer(args.CurrentPoint.PointerId, PointerDeviceType.Mouse, false, isInRange: true); + + var pointerArgs = new PointerRoutedEventArgs(args, pointer, element); + TraverseAncestors(element, pointerArgs, e => e.OnNativePointerEnter(pointerArgs)); + } + + raiseEvent(element); + raised = true; + } + } + else + { + if (element._pointerEntered) + { + element._pointerEntered = false; + // Console.WriteLine($"PointerManager.Exited [{element}/{element.GetHashCode():X8}"); + + var pointer = new Pointer(args.CurrentPoint.PointerId, PointerDeviceType.Mouse, false, isInRange: true); + var pointerArgs = new PointerRoutedEventArgs(args, pointer, element); + TraverseAncestors(element, pointerArgs, e => e.OnNativePointerExited(pointerArgs)); + } + } + + return raised; + } + } + + private bool _pointerEntered; + + // TODO Should be per CoreWindow + private static PointerManager _pointerManager; + + partial void InitializePointersPartial() + { + if (_pointerManager == null) + { + _pointerManager = new PointerManager(); + } + } + + partial void AddPointerHandler(RoutedEvent routedEvent, int handlersCount, object handler, bool handledEventsToo) + { + + } + + + #region HitTestVisibility + internal void UpdateHitTest() + { + this.CoerceValue(HitTestVisibilityProperty); + } + + private enum HitTestVisibility + { + /// + /// The element and its children can't be targeted by hit-testing. + /// + /// + /// This occurs when IsHitTestVisible="False", IsEnabled="False", or Visibility="Collapsed". + /// + Collapsed, + + /// + /// The element can't be targeted by hit-testing. + /// + /// + /// This usually occurs if an element doesn't have a Background/Fill. + /// + Invisible, + + /// + /// The element can be targeted by hit-testing. + /// + Visible, + } + + /// + /// Represents the final calculated hit-test visibility of the element. + /// + /// + /// This property should never be directly set, and its value should always be calculated through coercion (see . + /// + private static readonly DependencyProperty HitTestVisibilityProperty = + DependencyProperty.Register( + "HitTestVisibility", + typeof(HitTestVisibility), + typeof(UIElement), + new FrameworkPropertyMetadata( + HitTestVisibility.Visible, + FrameworkPropertyMetadataOptions.Inherits, + coerceValueCallback: (s, e) => CoerceHitTestVisibility(s, e), + propertyChangedCallback: (s, e) => OnHitTestVisibilityChanged(s, e) + ) + ); + + /// + /// This calculates the final hit-test visibility of an element. + /// + /// + private static object CoerceHitTestVisibility(DependencyObject dependencyObject, object baseValue) + { + var element = (UIElement)dependencyObject; + + // The HitTestVisibilityProperty is never set directly. This means that baseValue is always the result of the parent's CoerceHitTestVisibility. + var baseHitTestVisibility = (HitTestVisibility)baseValue; + + // If the parent is collapsed, we should be collapsed as well. This takes priority over everything else, even if we would be visible otherwise. + if (baseHitTestVisibility == HitTestVisibility.Collapsed) + { + return HitTestVisibility.Collapsed; + } + + // If we're not locally hit-test visible, visible, or enabled, we should be collapsed. Our children will be collapsed as well. + if (!element.IsHitTestVisible || element.Visibility != Visibility.Visible || !element.IsEnabledOverride()) + { + return HitTestVisibility.Collapsed; + } + + // If we're not hit (usually means we don't have a Background/Fill), we're invisible. Our children will be visible or not, depending on their state. + if (!element.IsViewHit()) + { + return HitTestVisibility.Invisible; + } + + // If we're not collapsed or invisible, we can be targeted by hit-testing. This means that we can be the source of pointer events. + return HitTestVisibility.Visible; + } + + private static void OnHitTestVisibilityChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args) + { + } + #endregion + + } +} diff --git a/src/Uno.UI/UI/Xaml/UIElement.RoutedEvents.cs b/src/Uno.UI/UI/Xaml/UIElement.RoutedEvents.cs index 902e7d331c81..9a864d873b33 100644 --- a/src/Uno.UI/UI/Xaml/UIElement.RoutedEvents.cs +++ b/src/Uno.UI/UI/Xaml/UIElement.RoutedEvents.cs @@ -264,7 +264,7 @@ public event PointerEventHandler PointerReleased remove => RemoveHandler(PointerReleasedEvent, value); } -#if !__WASM__ +#if !__WASM__ && !__SKIA__ [global::Uno.NotImplemented] #endif public event PointerEventHandler PointerWheelChanged diff --git a/src/Uno.UI/UI/Xaml/UIElement.Skia.cs b/src/Uno.UI/UI/Xaml/UIElement.Skia.cs new file mode 100644 index 000000000000..13a331555729 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/UIElement.Skia.cs @@ -0,0 +1,300 @@ +using Windows.Foundation; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; +using System; +using System.Collections.Generic; +using System.Text; +using System.Linq; +using Windows.UI.Composition; +using System.Numerics; +using Uno.Extensions; +using Uno.Logging; +using Uno.UI; +using Uno.UI.Extensions; + +namespace Windows.UI.Xaml +{ + public partial class UIElement : DependencyObject + { + // Even if this a concept of FrameworkElement, the loaded state is handled by the UIElement in order to avoid + // to cast to FrameworkElement each time a child is added or removed. + internal bool IsLoaded; + + internal Size _unclippedDesiredSize; + internal Point _visualOffset; + internal List _children = new List(); + private ContainerVisual _visual; + private Visibility _visibilityCache; + internal double _canvasTop; + internal double _canvasLeft; + private Rect _currentFinalRect; + + private protected int? Depth { get; private set; } + + public UIElement() + { + Initialize(); + InitializePointers(); + + RegisterPropertyChangedCallback(VisibilityProperty, OnVisibilityPropertyChanged); + RegisterPropertyChangedCallback(Controls.Canvas.LeftProperty, OnCanvasLeftChanged); + RegisterPropertyChangedCallback(Controls.Canvas.TopProperty, OnCanvasTopChanged); + + UpdateHitTest(); + } + + private void OnCanvasTopChanged(DependencyObject sender, DependencyProperty dp) + { + _canvasTop = (double)this.GetValue(Controls.Canvas.TopProperty); + } + + private void OnCanvasLeftChanged(DependencyObject sender, DependencyProperty dp) + { + _canvasLeft = (double)this.GetValue(Controls.Canvas.LeftProperty); + } + + private void OnVisibilityPropertyChanged(DependencyObject sender, DependencyProperty dp) + { + UpdateHitTest(); + + _visibilityCache = (Visibility)GetValue(VisibilityProperty); + } + + internal ContainerVisual Visual + { + get { + + if (_visual == null) + { + _visual = Window.Current.Compositor.CreateContainerVisual(); + _visual.Comment = $"Owner:{GetType()}/{Name}"; + } + + return _visual; + } + } + + /// + /// The origin of the view's bounds relative to its parent. + /// + internal Point RelativePosition => _visualOffset; + + public void AddChild(UIElement child, int? index = null) + { + if (child == null) + { + return; + } + + var currentParent = child.GetParent() as UIElement; + + // Remove child from current parent, if any + if (currentParent != this && currentParent != null) + { + // ---IMPORTANT--- + // This behavior is different than UWP: + // On UWP the behavior would be to throw an "Element already has a logical parent" exception. + + // It is done here to align Wasm with Android and iOS where the control is + // simply "moved" when attached to another parent. + + // This could lead to "child kidnapping", like the one happening in ComboBox & ComboBoxItem + + this.Log().Info($"{this}.AddChild({child}): Removing child {child} from its current parent {currentParent}."); + currentParent.RemoveChild(child); + } + + child.SetParent(this); + OnAddingChild(child); + + _children.Add(child); + + UpdateChildVisual(child); + OnChildAdded(child); + + InvalidateMeasure(); + } + + private void OnChildAdded(UIElement child) + { + + } + + internal virtual void OnElementLoaded() + { + IsLoaded = true; + foreach (var innerChild in _children) + { + innerChild.OnElementLoaded(); + } + } + + private bool IsParentLoaded() + { + var root = Window.Current.Content; + + var current = this.GetParent(); + + while (current != null && current != root) + { + current = this.GetParent(); + } + + return current == root; + } + + private void OnAddingChild(UIElement child) + { + if (IsLoaded) + { + child.OnElementLoaded(); + } + } + + partial void OnOpacityChanged(DependencyPropertyChangedEventArgs args) + { + UpdateOpacity(); + } + + partial void OnIsHitTestVisibleChangedPartial(bool oldValue, bool newValue) + { + UpdateHitTest(); + } + + private void UpdateOpacity() => Visual.Opacity = Visibility == Visibility.Visible ? (float)Opacity : 0; + + private void UpdateChildVisual(UIElement child) + { + Visual.Children.InsertAtTop(child.Visual); + } + + internal UIElement RemoveChild(UIElement child) + { + _children.Remove(child); + child.SetParent(null); + + if (Visual != null) + { + Visual.Children.Remove(child.Visual); + } + + return child; + } + + internal void ClearChildren() + { + foreach (var child in _children) + { + child.SetParent(null); + // OnChildRemoved(child); + } + + _children.Clear(); + InvalidateMeasure(); + } + + internal UIElement FindFirstChild() => _children.FirstOrDefault(); + + public string Name { get; set; } + + partial void InitializeCapture(); + + internal bool IsPointerCaptured { get; set; } + + internal virtual bool IsEnabledOverride() => true; + + public virtual IEnumerable GetChildren() => _children; + + public IntPtr Handle { get; set; } + + internal Windows.Foundation.Point GetPosition(Point position, global::Windows.UI.Xaml.UIElement relativeTo) + { + throw new NotSupportedException(); + } + + protected virtual void OnVisibilityChanged(Visibility oldValue, Visibility newVisibility) + { + UpdateOpacity(); + + if (newVisibility == Visibility.Collapsed) + { + _desiredSize = new Size(0, 0); + _size = new Size(0, 0); + } + } + + partial void OnRenderTransformSet() + { + } + + internal void ArrangeVisual(Rect finalRect, bool clipToBounds, Rect? clippedFrame = default) + { + LayoutSlotWithMarginsAndAlignments = + VisualTreeHelper.GetParent(this) is UIElement parent + ? finalRect.DeflateBy(parent.GetBorderThickness()) + : finalRect; + + var oldFinalRect = _currentFinalRect; + _currentFinalRect = finalRect; + + var oldRect = oldFinalRect; + var newRect = finalRect; + if (oldRect != newRect) + { + if ( + newRect.Width < 0 + || newRect.Height < 0 + || double.IsNaN(newRect.Width) + || double.IsNaN(newRect.Height) + || double.IsNaN(newRect.X) + || double.IsNaN(newRect.Y) + ) + { + throw new InvalidOperationException($"{this}: Invalid frame size {newRect}. No dimension should be NaN or negative value."); + } + + Rect? getClip() + { + // Disable clipping for Scrollviewer (edge seems to disable scrolling if + // the clipping is enabled to the size of the scrollviewer, even if overflow-y is auto) + if (this is Controls.ScrollViewer) + { + return null; + } + else if (Clip != null) + { + return Clip.Rect; + } + + return new Rect(0, 0, newRect.Width, newRect.Height); + } + + OnArrangeVisual(newRect, getClip()); + } + else + { + this.Log().DebugIfEnabled(() => $"{this}: ArrangeVisual({_currentFinalRect}) -- SKIPPED (no change)"); + } + } + + internal virtual void OnArrangeVisual(Rect rect, Rect? clip) + { + Visual.Offset = new Vector3((float)rect.X, (float)rect.Y, 0); + Visual.Size = new Vector2((float)rect.Width, (float)rect.Height); + + if (clip is Rect rectClip) + { + Visual.Clip = new InsetClip() { + TopInset = (float)rectClip.Top, + LeftInset = (float)rectClip.Left, + BottomInset = (float)rectClip.Bottom, + RightInset = (float)rectClip.Right, + }; + } + else + { + Visual.Clip = null; + } + } + } +} diff --git a/src/Uno.UI/UI/Xaml/UIElement.cs b/src/Uno.UI/UI/Xaml/UIElement.cs index 364d74279ec2..fc1ce92a182a 100644 --- a/src/Uno.UI/UI/Xaml/UIElement.cs +++ b/src/Uno.UI/UI/Xaml/UIElement.cs @@ -317,7 +317,7 @@ internal void ApplyClip() if (NeedsClipToSlot) { -#if __WASM__ +#if NETSTANDARD var boundsClipping = new Rect(0, 0, RenderSize.Width, RenderSize.Height); #else var boundsClipping = ClippedFrame ?? Rect.Empty; @@ -395,7 +395,7 @@ internal static string SetDependencyPropertyValueInternal(DependencyObject owner internal bool NeedsClipToSlot { get; set; } -#if !__WASM__ +#if !NETSTANDARD /// /// Backing property for /// @@ -422,7 +422,7 @@ public virtual void Measure(Size availableSize) { } -#if !__WASM__ +#if !NETSTANDARD /// /// This is the Frame that should be used as "available Size" for the Arrange phase. /// @@ -492,7 +492,7 @@ public FocusState FocusState internal set { SetValue(FocusStateProperty, value); } } - public static DependencyProperty FocusStateProperty = + public static DependencyProperty FocusStateProperty { get; } = DependencyProperty.Register( "FocusState", typeof(FocusState), @@ -512,7 +512,7 @@ public bool IsTabStop set { SetValue(IsTabStopProperty, value); } } - public static DependencyProperty IsTabStopProperty = + public static DependencyProperty IsTabStopProperty { get; } = DependencyProperty.Register( "IsTabStop", typeof(bool), diff --git a/src/Uno.UI/UI/Xaml/UIElement.netstdref.cs b/src/Uno.UI/UI/Xaml/UIElement.netstdref.cs new file mode 100644 index 000000000000..b25b341b9aa2 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/UIElement.netstdref.cs @@ -0,0 +1,49 @@ +using Windows.Foundation; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Windows.UI.Xaml +{ + public partial class UIElement : DependencyObject + { + public UIElement() + { + Initialize(); + InitializePointers(); + } + + internal bool ShouldInterceptInvalidate { get; set; } + + public IntPtr Handle { get; } + + public string Name { get; set; } + + /// + /// Determines if InvalidateMeasure has been called + /// + internal bool IsMeasureDirty => false; + + /// + /// Determines if InvalidateArrange has been called + /// + internal bool IsArrangeDirty => false; + + internal bool IsPointerCaptured { get; set; } + + internal Size LastAvailableSize => Size.Empty; + + internal Windows.Foundation.Point GetPosition(Point position, global::Windows.UI.Xaml.UIElement relativeTo) + { + throw new NotSupportedException(); + } + + internal void ClearChildren() { } + + protected virtual void OnVisibilityChanged(Visibility oldValue, Visibility newVisibility) + { + } + } +} diff --git a/src/Uno.UI/UI/Xaml/UIElement.wasm.cs b/src/Uno.UI/UI/Xaml/UIElement.wasm.cs index c8640ec735ff..aa453bcb53c3 100644 --- a/src/Uno.UI/UI/Xaml/UIElement.wasm.cs +++ b/src/Uno.UI/UI/Xaml/UIElement.wasm.cs @@ -15,11 +15,15 @@ using Uno.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.System; +using System.Reflection; +using Uno.Core.Comparison; namespace Windows.UI.Xaml { public partial class UIElement : DependencyObject { + internal const string DefaultHtmlTag = "div"; + // Even if this a concept of FrameworkElement, the loaded state is handled by the UIElement in order to avoid // to cast to FrameworkElement each time a child is added or removed. internal bool IsLoaded; @@ -80,13 +84,18 @@ private Rect GetBoundingClientRect() return new Rect(double.Parse(sizeParts[0]), double.Parse(sizeParts[1]), double.Parse(sizeParts[2]), double.Parse(sizeParts[3])); } - public UIElement(string htmlTag = "div", bool isSvg = false) + public UIElement() : this(null, false) { } + + public UIElement(string htmlTag = DefaultHtmlTag) : this(htmlTag, false) { } + + public UIElement(string htmlTag, bool isSvg) { Initialize(); _gcHandle = GCHandle.Alloc(this, GCHandleType.Weak); _isFrameworkElement = this is FrameworkElement; - HtmlTag = htmlTag; + + HtmlTag = GetHtmlTag(htmlTag); HtmlTagIsSvg = isSvg; var type = GetType(); @@ -94,7 +103,6 @@ public UIElement(string htmlTag = "div", bool isSvg = false) Handle = GCHandle.ToIntPtr(_gcHandle); HtmlId = Handle; - Uno.UI.Xaml.WindowManagerInterop.CreateContent( htmlId: HtmlId, htmlTag: HtmlTag, @@ -108,6 +116,43 @@ public UIElement(string htmlTag = "div", bool isSvg = false) UpdateHitTest(); } + private static Dictionary _htmlTagCache = new Dictionary(FastTypeComparer.Default); + private static Type _htmlElementAttribute; + private static PropertyInfo _htmlTagAttributeTagGetter; + private static Assembly _unoUIAssembly = typeof(UIElement).Assembly; + + private string GetHtmlTag(string htmlTag) + { + var currentType = GetType(); + + if (currentType.Assembly != _unoUIAssembly) + { + if (_htmlElementAttribute == null) + { + _htmlElementAttribute = Assembly.Load("Uno.UI.Runtime.Wasm").GetType("Uno.UI.Runtime.Wasm.HtmlElementAttribute", true); + _htmlTagAttributeTagGetter = _htmlElementAttribute.GetProperty("Tag"); + } + + if (!_htmlTagCache.TryGetValue(currentType, out var htmlTagOverride)) + { + htmlTagOverride = DefaultHtmlTag; + + if (currentType.GetCustomAttribute(_htmlElementAttribute) is Attribute attr) + { + _htmlTagCache[currentType] = htmlTagOverride = _htmlTagAttributeTagGetter.GetValue(attr, Array.Empty()) as string; + } + + _htmlTagCache[currentType] = htmlTagOverride; + } + + return htmlTagOverride; + } + else + { + return htmlTag; + } + } + ~UIElement() { if (this.Log().IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) @@ -205,7 +250,7 @@ protected internal void SetClasses(string[] cssClasses, int index = -1) /// The dimensions to apply to the element /// Whether the element should be clipped to its bounds /// The Clip rect to set, if any - protected internal void ArrangeElementNative(Rect rect, bool clipToBounds, Rect? clipRect) + protected internal void ArrangeVisual(Rect rect, bool clipToBounds, Rect? clipRect) { LayoutSlotWithMarginsAndAlignments = VisualTreeHelper.GetParent(this) is UIElement parent diff --git a/src/Uno.UI/UI/Xaml/UIElementCollection.Skia.cs b/src/Uno.UI/UI/Xaml/UIElementCollection.Skia.cs new file mode 100644 index 000000000000..6cd634879890 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/UIElementCollection.Skia.cs @@ -0,0 +1,70 @@ +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using Uno.Extensions; +using System; + +namespace Windows.UI.Xaml.Controls +{ + public partial class UIElementCollection + { + private readonly UIElement _owner; + + internal UIElementCollection(UIElement view) + { + _owner = view; + } + + protected void AddCore(UIElement item) + { + _owner.AddChild(item); + } + + protected IEnumerable ClearCore() + { + var deleted = _owner._children.ToArray(); + _owner.ClearChildren(); + + return deleted; + } + + protected bool ContainsCore(UIElement item) + { + return _owner._children.Contains(item); + } + + protected void CopyToCore(UIElement[] array, int arrayIndex) + => _owner._children.ToArray().CopyTo(array, arrayIndex); + + + protected int CountCore() => _owner._children.Count; + + protected UIElement GetAtIndexCore(int index) => _owner._children[index]; + + protected List.Enumerator GetEnumerator() => _owner._children.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + protected int IndexOfCore(UIElement item) => _owner._children.IndexOf(item); + + protected void InsertCore(int index, UIElement item) + { + _owner.AddChild(item, index); + } + + protected void MoveCore(uint oldIndex, uint newIndex) + { + // _owner.MoveChildTo((int)oldIndex, (int)newIndex); + } + + protected UIElement RemoveAtCore(int index) + { + var item = _owner._children.ElementAtOrDefault(index); + _owner.RemoveChild(item); + return item; + } + + protected bool RemoveCore(UIElement item) => _owner.RemoveChild(item) != null; + + protected UIElement SetAtIndexCore(int index, UIElement value) => throw new NotImplementedException(); + } +} diff --git a/src/Uno.UI/UI/Xaml/UIElementCollection.netstdref.cs b/src/Uno.UI/UI/Xaml/UIElementCollection.netstdref.cs new file mode 100644 index 000000000000..734a4cd92d07 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/UIElementCollection.netstdref.cs @@ -0,0 +1,73 @@ +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using Uno.Extensions; +using System; +using UIElement = Windows.UI.Xaml.UIElement; + +namespace Windows.UI.Xaml.Controls +{ + public partial class UIElementCollection + { + + private readonly List _elements; + private readonly FrameworkElement _owner; + + internal UIElementCollection(FrameworkElement view) + { + _elements = view._children; + _owner = view; + } + + private void AddCore(UIElement item) => _owner.AddChild(item); + + private IEnumerable ClearCore() + { + var old = _elements.ToArray(); + _elements.Clear(); + + return old; + } + + private bool ContainsCore(UIElement item) + { + throw new NotImplementedException(); + } + + private void CopyToCore(UIElement[] array, int arrayIndex) + { + throw new NotImplementedException(); + } + + private int CountCore() => _elements.Count; + + private UIElement GetAtIndexCore(int index) => _elements[index]; + + private IEnumerator GetEnumerator() => _elements.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => _elements.GetEnumerator(); + + private int IndexOfCore(UIElement item) => _elements.IndexOf(item); + + private void InsertCore(int index, UIElement item) => _owner.AddChild(item, index); + + private void MoveCore(uint oldIndex, uint newIndex) + { + throw new NotImplementedException(); + } + + private UIElement RemoveAtCore(int index) + { + var item = _elements.ElementAtOrDefault(index); + if (item != null) + { + _owner.RemoveChild(item); + } + return item; + } + + private bool RemoveCore(UIElement item) => _owner.RemoveChild(item) != null; + + private UIElement SetAtIndexCore(int index, UIElement value) => _elements[index] = value; + } +} diff --git a/src/Uno.UI/UI/Xaml/UIElementCollection.wasm.cs b/src/Uno.UI/UI/Xaml/UIElementCollection.wasm.cs index 966db3017044..2cdc41b1c5bd 100644 --- a/src/Uno.UI/UI/Xaml/UIElementCollection.wasm.cs +++ b/src/Uno.UI/UI/Xaml/UIElementCollection.wasm.cs @@ -11,7 +11,7 @@ public partial class UIElementCollection { private readonly UIElement _owner; - public UIElementCollection(UIElement view) + internal UIElementCollection(UIElement view) { _owner = view; } diff --git a/src/Uno.UI/UI/Xaml/UIElementExtensions.net.cs b/src/Uno.UI/UI/Xaml/UIElementExtensions.cs similarity index 78% rename from src/Uno.UI/UI/Xaml/UIElementExtensions.net.cs rename to src/Uno.UI/UI/Xaml/UIElementExtensions.cs index a38b43158e4a..e864413d42cb 100644 --- a/src/Uno.UI/UI/Xaml/UIElementExtensions.net.cs +++ b/src/Uno.UI/UI/Xaml/UIElementExtensions.cs @@ -6,6 +6,9 @@ namespace Windows.UI.Xaml { public static partial class UIElementExtensions { + /// + /// Get the parent view in the visual tree. + /// public static UIElement GetVisualTreeParent(this UIElement uiElement) => (uiElement as FrameworkElement)?.Parent as UIElement; } } diff --git a/src/Uno.UI/UI/Xaml/UIElementExtensions.netstdref.cs b/src/Uno.UI/UI/Xaml/UIElementExtensions.netstdref.cs new file mode 100644 index 000000000000..5b5920ce5962 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/UIElementExtensions.netstdref.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Windows.UI.Xaml +{ + public static partial class UIElementExtensions + { + } +} diff --git a/src/Uno.UI/UI/Xaml/UIElementExtensions.wasm.cs b/src/Uno.UI/UI/Xaml/UIElementExtensions.wasm.cs index 644b019b3eb9..c5f0a0b97829 100644 --- a/src/Uno.UI/UI/Xaml/UIElementExtensions.wasm.cs +++ b/src/Uno.UI/UI/Xaml/UIElementExtensions.wasm.cs @@ -50,10 +50,5 @@ public static void UnregisterHtmlCustomEventHandler(this UIElement element, stri { element.UnregisterEventHandler(eventName, handler); } - - /// - /// Get the parent view in the visual tree. - /// - public static UIElement GetVisualTreeParent(this UIElement element) => element?.GetParent() as UIElement; } } diff --git a/src/Uno.UI/UI/Xaml/Window.Desktop.cs b/src/Uno.UI/UI/Xaml/Window.Desktop.cs index f5e864cfb054..70dc95e57331 100644 --- a/src/Uno.UI/UI/Xaml/Window.Desktop.cs +++ b/src/Uno.UI/UI/Xaml/Window.Desktop.cs @@ -1,4 +1,4 @@ -#if NET461 +#if NET461 || __NETSTD_REFERENCE__ using System; using System.Linq; using System.Runtime.InteropServices; diff --git a/src/Uno.UI/UI/Xaml/Window.Skia.cs b/src/Uno.UI/UI/Xaml/Window.Skia.cs new file mode 100644 index 000000000000..53b2229a75d3 --- /dev/null +++ b/src/Uno.UI/UI/Xaml/Window.Skia.cs @@ -0,0 +1,197 @@ +using System; +using System.Diagnostics; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Threading; +using SkiaSharp; +using Uno; +using Uno.Disposables; +using Uno.Extensions; +using Uno.Logging; +using Uno.UI; +using Windows.Foundation; +using Windows.Foundation.Metadata; +using Windows.UI.Composition; +using Windows.UI.Core; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Media; + +namespace Windows.UI.Xaml +{ + public sealed partial class Window + { + private static Window _current; + private Grid _window; + // private PopupRoot _popupRoot; + // private ScrollViewer _rootScrollViewer; + private Border _rootBorder; + private UIElement _content; + + public Window() + { + Init(); + + Compositor = new Compositor(); + } + + public void Init() + { + Dispatcher = CoreDispatcher.Main; + CoreWindow = new CoreWindow(); + } + + internal Action InvalidateRender; + + internal void QueueInvalidateRender() + { + if (!_isMeasuring) + { + CoreDispatcher.Main.RunAsync(CoreDispatcherPriority.Normal, () => { InvalidateRender(); }); + } + } + + private static bool _isMeasureQueued = false; + private static bool _isMeasuring = false; + + internal static void InvalidateMeasure() + { + Current.InnerInvalidateMeasure(); + } + + internal void InnerInvalidateMeasure() + { + if (_window != null) + { + if (!_isMeasureQueued) + { + _isMeasureQueued = true; + + CoreDispatcher.Main.RunAsync(CoreDispatcherPriority.Normal, () => { + try + { + _isMeasureQueued = false; + + _isMeasuring = true; + + var sw = Stopwatch.StartNew(); + _window.Measure(Bounds.Size); + _window.Arrange(Bounds); + sw.Stop(); + + if (this.Log().IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) + { + this.Log().Debug($"DispatchInvalidateMeasure: {sw.Elapsed}"); + } + + InvalidateRender(); + } + finally + { + _isMeasuring = false; + } + }); + } + + + } + } + + internal void OnNativeSizeChanged(Size size) + { + var newBounds = new Rect(0, 0, size.Width, size.Height); + + if (newBounds != Bounds) + { + if (this.Log().IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) + { + this.Log().Debug($"OnNativeSizeChanged: {size}"); + } + + Bounds = newBounds; + + InvalidateMeasure(); + RaiseSizeChanged(new WindowSizeChangedEventArgs(size)); + } + } + + public Compositor Compositor { get; } + + partial void InternalActivate() + { + // WebAssemblyRuntime.InvokeJS("Uno.UI.WindowManager.current.activate();"); + } + + private void InternalSetContent(UIElement content) + { + if (_window == null) + { + _rootBorder = new Border(); + //_rootScrollViewer = new ScrollViewer() + //{ + // VerticalScrollBarVisibility = ScrollBarVisibility.Disabled, + // HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled, + // VerticalScrollMode = ScrollMode.Disabled, + // HorizontalScrollMode = ScrollMode.Disabled, + // Content = _rootBorder + //}; + //// _popupRoot = new PopupRoot(); + //_window = new Grid() + //{ + // Visual = Compositor.CreateContainerVisual(), + // Children = + // { + // _rootScrollViewer, + // // , _popupRoot + // } + //}; + + _window = new Grid { + IsLoaded = true, + Children = { _rootBorder } + }; + + Compositor.RootVisual = _window.Visual; + } + + _rootBorder.Child = _content = content; + } + + private UIElement InternalGetContent() => _content; + + private static Window InternalGetCurrentWindow() + { + if (_current == null) + { + _current = new Window(); + } + + return _current; + } + + internal IDisposable OpenPopup(Popup popup) + { + if (this.Log().IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) + { + this.Log().Debug($"Creating popup"); + } + + var popupChild = popup.Child; + //_popupRoot.Children.Add(popupChild); + + return new CompositeDisposable( + Disposable.Create(() => { + + if (this.Log().IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) + { + this.Log().Debug($"Closing popup"); + } + + //_popupRoot.Children.Remove(popupChild); + }), + VisualTreeHelper.RegisterOpenPopup(popup) + ); + } + } +} diff --git a/src/Uno.UI/Uno.UI.csproj b/src/Uno.UI/Uno.UI.csproj index 88a80d887646..5666b2c2fdc9 100644 --- a/src/Uno.UI/Uno.UI.csproj +++ b/src/Uno.UI/Uno.UI.csproj @@ -1,4 +1,4 @@ - + xamarinmac20;MonoAndroid10.0;xamarinios10;net461;netstandard2.0 MonoAndroid90;MonoAndroid10.0;xamarinios10;net461;netstandard2.0;xamarinmac20 @@ -20,8 +20,8 @@ false true - ..\T4Generator\bin\$(Configuration) - $(T4Path)\T4Generator.exe + Reference + True obj\$(TargetFramework)\Resources\Resource.Designer.cs @@ -42,71 +42,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TextTemplatingFileGenerator - %(RecursiveDir)%(Filename).g.cs - - - - True - True - %(RecursiveDir)$([System.String]::new(%(FileName)).Replace('.g','.tt')) - - - %(RecursiveDir)$([System.String]::new(%(FileName)).Replace('.g','.tt')) - - - - - - - - @@ -117,6 +52,14 @@ + + + + + + + + @@ -190,64 +133,6 @@ - - - - - - InputFile=.\Mixins\Android\BaseActivity.Callbacks.tt;OutputPath=.\Mixins\Android;Configuration=$(Configuration);Platform=$(Platform) - - - InputFile=.\Mixins\Android\FrameworkElementMixins.tt;OutputPath=.\Mixins\Android;Configuration=$(Configuration);Platform=$(Platform) - - - InputFile=.\Mixins\Android\VisualStatesMixins.tt;OutputPath=.\Mixins\Android;Configuration=$(Configuration);Platform=$(Platform) - - - InputFile=.\Mixins\DependencyPropertyMixins.tt;OutputPath=.\Mixins;Configuration=$(Configuration);Platform=$(Platform) - - - InputFile=.\Mixins\iOS\FrameworkElementMixins.tt;OutputPath=.\Mixins\iOS;Configuration=$(Configuration);Platform=$(Platform) - - - InputFile=.\Mixins\iOS\VisualStatesMixins.tt;OutputPath=.\Mixins\iOS;Configuration=$(Configuration);Platform=$(Platform) - - - InputFile=.\Mixins\macOS\FrameworkElementMixins.tt;OutputPath=.\Mixins\macOS;Configuration=$(Configuration);Platform=$(Platform) - - - InputFile=.\Mixins\macOS\VisualStatesMixins.tt;OutputPath=.\Mixins\macOS;Configuration=$(Configuration);Platform=$(Platform) - - - InputFile=.\Mixins\Wasm\VisualStatesMixins.tt;OutputPath=.\Mixins\Wasm;Configuration=$(Configuration);Platform=$(Platform) - - - InputFile=.\Mixins\net461\VisualStatesMixins.tt;OutputPath=.\Mixins\net461;Configuration=$(Configuration);Platform=$(Platform) - - - - - - - - - - - - <_T4AOTFiles Include="$(T4Path)/*.dll" Exclude="$(T4Path)/System.Text.Encoding.CodePages.dll" /> - - - - - - - - - - @@ -276,12 +161,6 @@ - - - Uno.UI.xml - - - false @@ -293,11 +172,14 @@ true TargetFramework - - false - true - TargetFramework - + + + + + + + + @@ -327,4 +209,7 @@ + + + diff --git a/src/Uno.UI/XmlnsDefinitionAttribute.cs b/src/Uno.UI/XmlnsDefinitionAttribute.cs index a73f0caab063..5416b9a41c1e 100644 --- a/src/Uno.UI/XmlnsDefinitionAttribute.cs +++ b/src/Uno.UI/XmlnsDefinitionAttribute.cs @@ -20,14 +20,21 @@ namespace System.Windows.Markup { internal static class XamlConstants { +#if HAS_UNO_WINUI + public const string RootUINamespace = "Microsoft.UI"; +#else public const string RootUINamespace = "Windows.UI"; +#endif + + public const string WindowsUINamespace = "Windows.UI"; + public const string BaseXamlNamespace = RootUINamespace + ".Xaml"; internal static class Namespaces { public const string Controls = BaseXamlNamespace + ".Controls"; public const string Primitives = Controls + ".Primitives"; - public const string Text = RootUINamespace + ".Text"; + public const string Text = WindowsUINamespace + ".Text"; public const string Data = BaseXamlNamespace + ".Data"; public const string Documents = BaseXamlNamespace + ".Documents"; public const string Media = BaseXamlNamespace + ".Media"; diff --git a/src/Uno.UWP.Skia/AssemblyInfo.skia.cs b/src/Uno.UWP.Skia/AssemblyInfo.skia.cs new file mode 100644 index 000000000000..11e611065afc --- /dev/null +++ b/src/Uno.UWP.Skia/AssemblyInfo.skia.cs @@ -0,0 +1,4 @@ +using global::System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Uno.UI.Runtime.Skia.Gtk")] +[assembly: InternalsVisibleTo("Uno.UI.Runtime.Skia.Wpf")] diff --git a/src/Uno.UWP.Skia/Uno.Skia.csproj b/src/Uno.UWP.Skia/Uno.Skia.csproj new file mode 100644 index 000000000000..5190489b54bc --- /dev/null +++ b/src/Uno.UWP.Skia/Uno.Skia.csproj @@ -0,0 +1,43 @@ + + + + netstandard2.0 + + + + $(UnoTargetFrameworkOverride) + + + + Uno + Windows + $(DefineConstants);XAMARIN;IS_UNO;HAS_UMBRELLA_UI;HAS_UMBRELLA_BINDING;HAS_CRIPPLEDREFLECTION + true + + + true + + $(NoWarn);NU1701 + + false + true + + Skia + ..\Uno.UWP\ + + + + + + + + + + + + + + + + + diff --git a/src/Uno.UWP.Wasm/Uno.Wasm.csproj b/src/Uno.UWP.Wasm/Uno.Wasm.csproj new file mode 100644 index 000000000000..24afc3b88134 --- /dev/null +++ b/src/Uno.UWP.Wasm/Uno.Wasm.csproj @@ -0,0 +1,42 @@ + + + + netstandard2.0 + + + + $(UnoTargetFrameworkOverride) + + + + Uno + Windows + $(DefineConstants);XAMARIN;IS_UNO;HAS_UMBRELLA_UI;HAS_UMBRELLA_BINDING;HAS_CRIPPLEDREFLECTION + true + + + true + + $(NoWarn);NU1701 + + false + true + + WebAssembly + ..\Uno.UWP\ + + + + + + + + + + + + + + + + diff --git a/src/Uno.UWP/ApplicationModel/Activation/ProtocolActivatedEventArgs.cs b/src/Uno.UWP/ApplicationModel/Activation/ProtocolActivatedEventArgs.cs index 514766dec805..2dc30b648f66 100644 --- a/src/Uno.UWP/ApplicationModel/Activation/ProtocolActivatedEventArgs.cs +++ b/src/Uno.UWP/ApplicationModel/Activation/ProtocolActivatedEventArgs.cs @@ -1,5 +1,4 @@ -#if __IOS__ || __ANDROID__ || __WASM__ || __MACOS__ -using System; +using System; namespace Windows.ApplicationModel.Activation { @@ -14,6 +13,12 @@ public partial class ProtocolActivatedEventArgs : IViewSwitcherProvider, IActivatedEventArgsWithUser { + internal ProtocolActivatedEventArgs() + { + + } + +#if __IOS__ || __ANDROID__ || __WASM__ || __MACOS__ /// /// Internal-only constructor for protocol activation. /// @@ -39,6 +44,6 @@ internal ProtocolActivatedEventArgs(Uri uri, ApplicationExecutionState previousE /// Gets the Uniform Resource Identifier (URI) for which the app was activated. /// public Uri Uri { get; } +#endif } } -#endif diff --git a/src/Uno.UWP/ApplicationModel/DataTransfer/Clipboard.netstdref.cs b/src/Uno.UWP/ApplicationModel/DataTransfer/Clipboard.netstdref.cs new file mode 100644 index 000000000000..ddc35c928fa7 --- /dev/null +++ b/src/Uno.UWP/ApplicationModel/DataTransfer/Clipboard.netstdref.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Uno.Foundation; + +namespace Windows.ApplicationModel.DataTransfer +{ + public static partial class Clipboard + { + private static void StartContentChanged() + { + } + + private static void StopContentChanged() + { + } + } +} diff --git a/src/Uno.UWP/ApplicationModel/DataTransfer/Clipboard.skia.cs b/src/Uno.UWP/ApplicationModel/DataTransfer/Clipboard.skia.cs new file mode 100644 index 000000000000..ddc35c928fa7 --- /dev/null +++ b/src/Uno.UWP/ApplicationModel/DataTransfer/Clipboard.skia.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Uno.Foundation; + +namespace Windows.ApplicationModel.DataTransfer +{ + public static partial class Clipboard + { + private static void StartContentChanged() + { + } + + private static void StopContentChanged() + { + } + } +} diff --git a/src/Uno.UWP/AssemblyInfo.cs b/src/Uno.UWP/AssemblyInfo.cs index 33f1bea2be46..562770726ec3 100644 --- a/src/Uno.UWP/AssemblyInfo.cs +++ b/src/Uno.UWP/AssemblyInfo.cs @@ -3,6 +3,7 @@ using System.Runtime.InteropServices; [assembly: InternalsVisibleTo("Uno.UI")] +[assembly: InternalsVisibleTo("Uno.UI.Wasm")] [assembly: InternalsVisibleTo("Uno.UI.RuntimeTests")] [assembly: InternalsVisibleTo("Uno.UI.Tests")] diff --git a/src/Uno.UWP/Devices/Geolocation/Geolocator.wasm.cs b/src/Uno.UWP/Devices/Geolocation/Geolocator.wasm.cs index ad027323ec1a..b68b9d3656d3 100644 --- a/src/Uno.UWP/Devices/Geolocation/Geolocator.wasm.cs +++ b/src/Uno.UWP/Devices/Geolocation/Geolocator.wasm.cs @@ -52,32 +52,35 @@ partial void StopPositionChanged() InvokeJS(command); } - public static async Task RequestAccessAsync() + public static IAsyncOperation RequestAccessAsync() { - var accessRequest = new TaskCompletionSource(); - lock (_pendingAccessRequests) + return AsyncOperation.FromTask(async ct => { - //enqueue request - _pendingAccessRequests.Add(accessRequest); - - if (_pendingAccessRequests.Count == 1) + var accessRequest = new TaskCompletionSource(); + lock (_pendingAccessRequests) { - //there are no access requests currently waiting for resolution, we need to invoke the check in JS - var command = $"{JsType}.requestAccess()"; - InvokeJS(command); + //enqueue request + _pendingAccessRequests.Add(accessRequest); + + if (_pendingAccessRequests.Count == 1) + { + //there are no access requests currently waiting for resolution, we need to invoke the check in JS + var command = $"{JsType}.requestAccess()"; + InvokeJS(command); + } } - } - //await access status asynchronously, will come back through DispatchAccessRequest call - var result = await accessRequest.Task; + //await access status asynchronously, will come back through DispatchAccessRequest call + var result = await accessRequest.Task; - //if geolocation is not well accessible, default geoposition should be recommended - if (result != GeolocationAccessStatus.Allowed) - { - IsDefaultGeopositionRecommended = true; - } + //if geolocation is not well accessible, default geoposition should be recommended + if (result != GeolocationAccessStatus.Allowed) + { + IsDefaultGeopositionRecommended = true; + } - return result; + return result; + }); } /// @@ -87,7 +90,7 @@ public static async Task RequestAccessAsync() /// 5 seconds for high accuracy requests /// /// Geoposition - public Task GetGeopositionAsync() => + public IAsyncOperation GetGeopositionAsync() => GetGeopositionAsync( ActualDesiredAccuracyInMeters < 50 ? TimeSpan.FromSeconds(3) : TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(10)); @@ -98,15 +101,19 @@ public Task GetGeopositionAsync() => /// Maximum age of the geoposition /// Timeout for geoposition retrieval /// - public async Task GetGeopositionAsync(TimeSpan maximumAge, TimeSpan timeout) + public IAsyncOperation GetGeopositionAsync(TimeSpan maximumAge, TimeSpan timeout) { - BroadcastStatus(PositionStatus.Initializing); //GPS is initializing - var completionRequest = new TaskCompletionSource(); - var requestId = Guid.NewGuid().ToString(); - _pendingGeopositionRequests.TryAdd(requestId, completionRequest); - var command = FormattableString.Invariant($"{JsType}.getGeoposition({ActualDesiredAccuracyInMeters},{maximumAge.TotalMilliseconds},{timeout.TotalMilliseconds},\"{requestId}\")"); - InvokeJS(command); - return await completionRequest.Task; + return AsyncOperation.FromTask(async ct => + { + + BroadcastStatus(PositionStatus.Initializing); //GPS is initializing + var completionRequest = new TaskCompletionSource(); + var requestId = Guid.NewGuid().ToString(); + _pendingGeopositionRequests.TryAdd(requestId, completionRequest); + var command = FormattableString.Invariant($"{JsType}.getGeoposition({ActualDesiredAccuracyInMeters},{maximumAge.TotalMilliseconds},{timeout.TotalMilliseconds},\"{requestId}\")"); + InvokeJS(command); + return await completionRequest.Task; + }); } [Preserve] diff --git a/src/Uno.UWP/Devices/Sensors/Accelerometer.Skia.cs b/src/Uno.UWP/Devices/Sensors/Accelerometer.Skia.cs new file mode 100644 index 000000000000..c2005debe7c0 --- /dev/null +++ b/src/Uno.UWP/Devices/Sensors/Accelerometer.Skia.cs @@ -0,0 +1,28 @@ +using Uno; +using System; +using System.Collections.Generic; +using System.Text; +using Uno.Devices.Sensors.Helpers; + +namespace Windows.Devices.Sensors +{ + public partial class Accelerometer + { + private Accelerometer() + { + } + + private static Accelerometer TryCreateInstance() + { + return null; + } + + private void StartReadingChanged() { } + + private void StopReadingChanged() { } + + private void StartShaken() { } + + private void StopShaken() { } + } +} diff --git a/src/Uno.UWP/Devices/Sensors/AccelerometerReading.cs b/src/Uno.UWP/Devices/Sensors/AccelerometerReading.cs index 1f47efcda548..695dd43cc23a 100644 --- a/src/Uno.UWP/Devices/Sensors/AccelerometerReading.cs +++ b/src/Uno.UWP/Devices/Sensors/AccelerometerReading.cs @@ -1,5 +1,4 @@ -#if __IOS__ || __ANDROID__ || __WASM__ -using System; +using System; using System.Collections.Generic; using System.Text; @@ -7,6 +6,12 @@ namespace Windows.Devices.Sensors { public partial class AccelerometerReading { + private AccelerometerReading() + { + + } + +#if __IOS__ || __ANDROID__ || __WASM__ internal AccelerometerReading( double accelerationX, double accelerationY, @@ -26,6 +31,6 @@ internal AccelerometerReading( public double AccelerationZ { get; } public DateTimeOffset Timestamp { get; } +#endif } } -#endif diff --git a/src/Uno.UWP/Devices/Sensors/AccelerometerReadingChangedEvenArgs.cs b/src/Uno.UWP/Devices/Sensors/AccelerometerReadingChangedEvenArgs.cs index 97c89a46977f..4cc85c9e9a20 100644 --- a/src/Uno.UWP/Devices/Sensors/AccelerometerReadingChangedEvenArgs.cs +++ b/src/Uno.UWP/Devices/Sensors/AccelerometerReadingChangedEvenArgs.cs @@ -1,5 +1,4 @@ -#if __IOS__ || __ANDROID__ || __WASM__ -using System; +using System; using System.Collections.Generic; using System.Text; @@ -7,12 +6,18 @@ namespace Windows.Devices.Sensors { public partial class AccelerometerReadingChangedEventArgs { + internal AccelerometerReadingChangedEventArgs() + { + + } + +#if __IOS__ || __ANDROID__ || __WASM__ internal AccelerometerReadingChangedEventArgs(AccelerometerReading reading) { Reading = reading; } public AccelerometerReading Reading { get; } +#endif } } -#endif diff --git a/src/Uno.UWP/Devices/Sensors/AccelerometerShakenEventArgs.cs b/src/Uno.UWP/Devices/Sensors/AccelerometerShakenEventArgs.cs index 352fed7f5424..697a6c0118f0 100644 --- a/src/Uno.UWP/Devices/Sensors/AccelerometerShakenEventArgs.cs +++ b/src/Uno.UWP/Devices/Sensors/AccelerometerShakenEventArgs.cs @@ -1,5 +1,4 @@ -#if __IOS__ || __ANDROID__ || __WASM__ -using System; +using System; using System.Collections.Generic; using System.Text; @@ -7,12 +6,17 @@ namespace Windows.Devices.Sensors { public partial class AccelerometerShakenEventArgs { + internal AccelerometerShakenEventArgs() + { + } + +#if __IOS__ || __ANDROID__ || __WASM__ internal AccelerometerShakenEventArgs(DateTimeOffset timestamp) { Timestamp = timestamp; } public DateTimeOffset Timestamp { get; } +#endif } } -#endif diff --git a/src/Uno.UWP/Devices/Sensors/Gyrometer.Skia.cs b/src/Uno.UWP/Devices/Sensors/Gyrometer.Skia.cs new file mode 100644 index 000000000000..0764783f9a54 --- /dev/null +++ b/src/Uno.UWP/Devices/Sensors/Gyrometer.Skia.cs @@ -0,0 +1,23 @@ +using System; +using System.Diagnostics; +using Uno; +using Uno.Devices.Sensors.Helpers; + +namespace Windows.Devices.Sensors +{ + public partial class Gyrometer + { + private static Gyrometer TryCreateInstance() + { + return null; + } + + private void StartReading() + { + } + + private void StopReading() + { + } + } +} diff --git a/src/Uno.UWP/Devices/Sensors/Magnetometer.Skia.cs b/src/Uno.UWP/Devices/Sensors/Magnetometer.Skia.cs new file mode 100644 index 000000000000..f83eec76d63e --- /dev/null +++ b/src/Uno.UWP/Devices/Sensors/Magnetometer.Skia.cs @@ -0,0 +1,23 @@ +using System; +using System.Diagnostics; +using Uno; +using Uno.Devices.Sensors.Helpers; + +namespace Windows.Devices.Sensors +{ + public partial class Magnetometer + { + private static Magnetometer TryCreateInstance() + { + return null; + } + + private void StartReading() + { + } + + private void StopReading() + { + } + } +} diff --git a/src/Uno.UWP/Graphics/IGeometrySource2D.cs b/src/Uno.UWP/Graphics/IGeometrySource2D.cs new file mode 100644 index 000000000000..701517d01796 --- /dev/null +++ b/src/Uno.UWP/Graphics/IGeometrySource2D.cs @@ -0,0 +1,8 @@ +#pragma warning disable 108 // new keyword hiding +#pragma warning disable 114 // new keyword hiding +namespace Windows.Graphics +{ + public partial interface IGeometrySource2D + { + } +} diff --git a/src/Uno.UWP/Networking/Connectivity/ConnectionProfile.netstdref.cs b/src/Uno.UWP/Networking/Connectivity/ConnectionProfile.netstdref.cs new file mode 100644 index 000000000000..be7e01a332ea --- /dev/null +++ b/src/Uno.UWP/Networking/Connectivity/ConnectionProfile.netstdref.cs @@ -0,0 +1,17 @@ +namespace Windows.Networking.Connectivity +{ + public partial class ConnectionProfile + { + internal static ConnectionProfile GetInternetConnectionProfile() => + new ConnectionProfile(); + + private ConnectionProfile() + { + } + + private NetworkConnectivityLevel GetNetworkConnectivityLevelImpl() + { + return NetworkConnectivityLevel.None; + } + } +} diff --git a/src/Uno.UWP/Networking/Connectivity/ConnectionProfile.skia.cs b/src/Uno.UWP/Networking/Connectivity/ConnectionProfile.skia.cs new file mode 100644 index 000000000000..be7e01a332ea --- /dev/null +++ b/src/Uno.UWP/Networking/Connectivity/ConnectionProfile.skia.cs @@ -0,0 +1,17 @@ +namespace Windows.Networking.Connectivity +{ + public partial class ConnectionProfile + { + internal static ConnectionProfile GetInternetConnectionProfile() => + new ConnectionProfile(); + + private ConnectionProfile() + { + } + + private NetworkConnectivityLevel GetNetworkConnectivityLevelImpl() + { + return NetworkConnectivityLevel.None; + } + } +} diff --git a/src/Uno.UWP/Networking/Connectivity/NetworkInformation.netstdref.cs b/src/Uno.UWP/Networking/Connectivity/NetworkInformation.netstdref.cs new file mode 100644 index 000000000000..da88a70a8854 --- /dev/null +++ b/src/Uno.UWP/Networking/Connectivity/NetworkInformation.netstdref.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Uno; + +namespace Windows.Networking.Connectivity +{ + public partial class NetworkInformation + { + private const string JsType = "Windows.Networking.Connectivity.NetworkInformation"; + + private static void StartNetworkStatusChanged() + { + } + + private static void StopNetworkStatusChanged() + { + } + } +} diff --git a/src/Uno.UWP/Networking/Connectivity/NetworkInformation.skia.cs b/src/Uno.UWP/Networking/Connectivity/NetworkInformation.skia.cs new file mode 100644 index 000000000000..da88a70a8854 --- /dev/null +++ b/src/Uno.UWP/Networking/Connectivity/NetworkInformation.skia.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Uno; + +namespace Windows.Networking.Connectivity +{ + public partial class NetworkInformation + { + private const string JsType = "Windows.Networking.Connectivity.NetworkInformation"; + + private static void StartNetworkStatusChanged() + { + } + + private static void StopNetworkStatusChanged() + { + } + } +} diff --git a/src/Uno.UWP/Security.Credentials/PasswordVault.Skia.cs b/src/Uno.UWP/Security.Credentials/PasswordVault.Skia.cs new file mode 100644 index 000000000000..b9859007571f --- /dev/null +++ b/src/Uno.UWP/Security.Credentials/PasswordVault.Skia.cs @@ -0,0 +1,15 @@ +using System; +using Uno; + +namespace Windows.Security.Credentials +{ + [NotImplemented] + /* sealed */ partial class PasswordVault + { + [NotImplemented] + public PasswordVault() + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Uno.UWP/Security.Credentials/PasswordVault.netstdref.cs b/src/Uno.UWP/Security.Credentials/PasswordVault.netstdref.cs new file mode 100644 index 000000000000..b9859007571f --- /dev/null +++ b/src/Uno.UWP/Security.Credentials/PasswordVault.netstdref.cs @@ -0,0 +1,15 @@ +using System; +using Uno; + +namespace Windows.Security.Credentials +{ + [NotImplemented] + /* sealed */ partial class PasswordVault + { + [NotImplemented] + public PasswordVault() + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Uno.UWP/Storage/ApplicationData.netstdref.cs b/src/Uno.UWP/Storage/ApplicationData.netstdref.cs new file mode 100644 index 000000000000..5de4ccac42b8 --- /dev/null +++ b/src/Uno.UWP/Storage/ApplicationData.netstdref.cs @@ -0,0 +1,23 @@ +using System; +using System.IO; + +namespace Windows.Storage +{ + partial class ApplicationData + { + private static string GetLocalCacheFolder() + => Path.GetTempPath(); + + private static string GetTemporaryFolder() + => Path.GetTempPath(); + + private static string GetLocalFolder() + => AppDomain.CurrentDomain.BaseDirectory; + + private static string GetRoamingFolder() + => Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + + private static string GetSharedLocalFolder() + => Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); + } +} diff --git a/src/Uno.UWP/Storage/ApplicationData.skia.cs b/src/Uno.UWP/Storage/ApplicationData.skia.cs new file mode 100644 index 000000000000..5de4ccac42b8 --- /dev/null +++ b/src/Uno.UWP/Storage/ApplicationData.skia.cs @@ -0,0 +1,23 @@ +using System; +using System.IO; + +namespace Windows.Storage +{ + partial class ApplicationData + { + private static string GetLocalCacheFolder() + => Path.GetTempPath(); + + private static string GetTemporaryFolder() + => Path.GetTempPath(); + + private static string GetLocalFolder() + => AppDomain.CurrentDomain.BaseDirectory; + + private static string GetRoamingFolder() + => Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + + private static string GetSharedLocalFolder() + => Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); + } +} diff --git a/src/Uno.UWP/Storage/ApplicationDataContainer.skia.cs b/src/Uno.UWP/Storage/ApplicationDataContainer.skia.cs new file mode 100644 index 000000000000..bcd6a764db5d --- /dev/null +++ b/src/Uno.UWP/Storage/ApplicationDataContainer.skia.cs @@ -0,0 +1,233 @@ +#nullable enable +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using Microsoft.Extensions.Logging; +using Uno.Extensions; +using Uno.Logging; +using Windows.Foundation.Collections; + +namespace Windows.Storage +{ + public partial class ApplicationDataContainer + { + partial void InitializePartial(ApplicationData owner) + { + Values = new FilePropertySet(owner, Locality); + } + + private class FilePropertySet : IPropertySet + { + private const string UWPFileName = ".UWPAppSettings"; + private readonly Dictionary _values = new Dictionary(); + private readonly string _folderPath; + private readonly string _filePath; + + public FilePropertySet(ApplicationData owner, ApplicationDataLocality locality) + { + StorageFolder folder; + switch (locality) + { + case ApplicationDataLocality.Local: + folder = owner.LocalFolder; + break; + + case ApplicationDataLocality.Roaming: + folder = owner.RoamingFolder; + break; + case ApplicationDataLocality.LocalCache: + folder = owner.LocalCacheFolder; + break; + + case ApplicationDataLocality.Temporary: + folder = owner.TemporaryFolder; + break; + + default: + throw new ArgumentOutOfRangeException(nameof(locality)); + } + + _folderPath = folder.Path; + _filePath = Path.Combine(folder.Path, UWPFileName); + + ReadFromFile(); + } + + public object? this[string key] + { + get + { + if (_values.TryGetValue(key, out var value)) + { + return DataTypeSerializer.Deserialize(value); + } + + return null; + } + set + { + if (value != null) + { + _values[key] = DataTypeSerializer.Serialize(value); + } + else + { + Remove(key); + } + + WriteToFile(); + } + } + + private void ReadFromFile() + { + try + { + + if (File.Exists(_filePath)) + { + using (var reader = new BinaryReader(File.OpenRead(_filePath))) + { + var count = reader.ReadInt32(); + + if (this.Log().IsEnabled(LogLevel.Debug)) + { + this.Log().Debug($"Reading {count} settings values"); + } + + for (int i = 0; i < count; i++) + { + var key = reader.ReadString(); + var value = reader.ReadString(); + + _values[key] = value; + } + } + } + else + { + if (this.Log().IsEnabled(LogLevel.Debug)) + { + this.Log().Debug($"File {_filePath} does not exist, skipping reading settings"); + } + } + } + catch (Exception e) + { + if (this.Log().IsEnabled(LogLevel.Error)) + { + this.Log().Error($"Failed to read settings from {_filePath}", e); + } + } + } + + private void WriteToFile() + { + try + { + Directory.CreateDirectory(_folderPath); + + if (this.Log().IsEnabled(LogLevel.Debug)) + { + this.Log().Debug($"Writing {_values.Count} settings to {_filePath}"); + } + + using (var writer = new BinaryWriter(File.OpenWrite(_filePath))) + { + writer.Write(_values.Count); + + foreach (var pair in _values) + { + writer.Write(pair.Key); + writer.Write(pair.Value ?? ""); + } + } + } + catch (Exception e) + { + if (this.Log().IsEnabled(LogLevel.Error)) + { + this.Log().Error($"Failed to write settings to {_filePath}", e); + } + } + } + + public ICollection Keys + => _values.Keys; + + public ICollection Values + => _values.Values.Select(DataTypeSerializer.Deserialize).ToList(); + + public int Count + => _values.Count; + + public bool IsReadOnly => false; + +#pragma warning disable CS0067 + public event MapChangedEventHandler? MapChanged; +#pragma warning restore CS0067 + + public void Add(string key, object value) + { + if (ContainsKey(key)) + { + throw new ArgumentException("An item with the same key has already been added."); + } + if (value != null) + { + _values.Add(key, DataTypeSerializer.Serialize(value)); + WriteToFile(); + } + } + + public void Add(KeyValuePair item) + => Add(item.Key, item.Value); + + public void Clear() + { + _values.Clear(); + WriteToFile(); + } + + public bool Contains(KeyValuePair item) + => throw new NotSupportedException(); + + public bool ContainsKey(string key) + => _values.ContainsKey(key); + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + => throw new NotSupportedException(); + + public IEnumerator> GetEnumerator() + => throw new NotSupportedException(); + + public bool Remove(string key) + { + var ret = _values.Remove(key); + + WriteToFile(); + + return ret; + } + + public bool Remove(KeyValuePair item) => Remove(item.Key); + + public bool TryGetValue(string key, out object? value) + { + if (_values.TryGetValue(key, out var innervalue)) + { + value = DataTypeSerializer.Deserialize(innervalue); + return true; + } + + value = null; + return false; + } + + IEnumerator IEnumerable.GetEnumerator() => throw new NotSupportedException(); + } + } +} diff --git a/src/Uno.UWP/System/DispatcherQueueTimer.netstdref.cs b/src/Uno.UWP/System/DispatcherQueueTimer.netstdref.cs new file mode 100644 index 000000000000..188c800313b2 --- /dev/null +++ b/src/Uno.UWP/System/DispatcherQueueTimer.netstdref.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Windows.System.Threading; + +namespace Windows.System +{ + partial class DispatcherQueueTimer + { + private void StartNative(TimeSpan interval) + { + throw new NotImplementedException("DispatcherQueueTimer not supported"); + } + + private void StartNative(TimeSpan dueTime, TimeSpan interval) + { + throw new NotImplementedException("DispatcherQueueTimer not supported"); + } + + private void StopNative() + { + throw new NotImplementedException("DispatcherQueueTimer not supported"); + } + } +} diff --git a/src/Uno.UWP/System/DispatcherQueueTimer.skia.cs b/src/Uno.UWP/System/DispatcherQueueTimer.skia.cs new file mode 100644 index 000000000000..188c800313b2 --- /dev/null +++ b/src/Uno.UWP/System/DispatcherQueueTimer.skia.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Windows.System.Threading; + +namespace Windows.System +{ + partial class DispatcherQueueTimer + { + private void StartNative(TimeSpan interval) + { + throw new NotImplementedException("DispatcherQueueTimer not supported"); + } + + private void StartNative(TimeSpan dueTime, TimeSpan interval) + { + throw new NotImplementedException("DispatcherQueueTimer not supported"); + } + + private void StopNative() + { + throw new NotImplementedException("DispatcherQueueTimer not supported"); + } + } +} diff --git a/src/Uno.UWP/System/Launcher.Skia.cs b/src/Uno.UWP/System/Launcher.Skia.cs new file mode 100644 index 000000000000..f9099ce4c8ba --- /dev/null +++ b/src/Uno.UWP/System/Launcher.Skia.cs @@ -0,0 +1,14 @@ +using System; +using System.Threading.Tasks; +using Uno.Foundation; + +namespace Windows.System +{ + public static partial class Launcher + { + public static async Task LaunchUriPlatformAsync(Uri uri) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Uno.UWP/System/Profile/AnalyticsInfo.cs b/src/Uno.UWP/System/Profile/AnalyticsInfo.cs index 463f4963af8c..42d46e78bdac 100644 --- a/src/Uno.UWP/System/Profile/AnalyticsInfo.cs +++ b/src/Uno.UWP/System/Profile/AnalyticsInfo.cs @@ -1,11 +1,11 @@ -#if __ANDROID__ || __IOS__ || __WASM__ || __MACOS__ namespace Windows.System.Profile { public static partial class AnalyticsInfo { +#if __ANDROID__ || __IOS__ || __WASM__ || __MACOS__ public static string DeviceForm => GetDeviceForm().ToString(); public static AnalyticsVersionInfo VersionInfo { get; } = new AnalyticsVersionInfo(); +#endif } } -#endif diff --git a/src/Uno.UWP/UI/Composition/CompositionAnimation.cs b/src/Uno.UWP/UI/Composition/CompositionAnimation.cs index 13657e261af7..656c56842131 100644 --- a/src/Uno.UWP/UI/Composition/CompositionAnimation.cs +++ b/src/Uno.UWP/UI/Composition/CompositionAnimation.cs @@ -4,6 +4,12 @@ namespace Windows.UI.Composition { public partial class CompositionAnimation { - + internal CompositionAnimation() : base(null) + { + + } + internal CompositionAnimation(Compositor compositor) : base(compositor) + { + } } } diff --git a/src/Uno.UWP/UI/Composition/CompositionBrush.cs b/src/Uno.UWP/UI/Composition/CompositionBrush.cs index 14dffb424240..f63b8f5b4747 100644 --- a/src/Uno.UWP/UI/Composition/CompositionBrush.cs +++ b/src/Uno.UWP/UI/Composition/CompositionBrush.cs @@ -3,5 +3,12 @@ namespace Windows.UI.Composition { public partial class CompositionBrush : CompositionObject { + internal CompositionBrush() + { + } + + internal CompositionBrush(Compositor compositor) : base(compositor) + { + } } } diff --git a/src/Uno.UWP/UI/Composition/CompositionClip.cs b/src/Uno.UWP/UI/Composition/CompositionClip.cs new file mode 100644 index 000000000000..62e84acd76d7 --- /dev/null +++ b/src/Uno.UWP/UI/Composition/CompositionClip.cs @@ -0,0 +1,15 @@ +using System.Numerics; + +namespace Windows.UI.Composition +{ + public partial class CompositionClip : CompositionObject + { + public Matrix3x2 TransformMatrix { get; set; } + public Vector2 Scale { get; set; } + public float RotationAngleInDegrees { get; set; } + public float RotationAngle { get; set; } + public Vector2 Offset { get; set; } + public Vector2 CenterPoint { get; set; } + public Vector2 AnchorPoint { get; set; } + } +} diff --git a/src/Uno.UWP/UI/Composition/CompositionColorBrush.cs b/src/Uno.UWP/UI/Composition/CompositionColorBrush.cs index 1a598af27750..00cb4c058114 100644 --- a/src/Uno.UWP/UI/Composition/CompositionColorBrush.cs +++ b/src/Uno.UWP/UI/Composition/CompositionColorBrush.cs @@ -5,11 +5,18 @@ namespace Windows.UI.Composition { - public partial class CompositionColorBrush : global::Windows.UI.Composition.CompositionBrush + public partial class CompositionColorBrush : CompositionBrush { private List _colorChangedHandlers = new List(); private Color _color; + internal CompositionColorBrush() => throw new NotSupportedException(); + + public CompositionColorBrush(Compositor compositor) : base(compositor) + { + + } + public Color Color { get { return _color; } diff --git a/src/Uno.UWP/UI/Composition/CompositionGeometricClip.cs b/src/Uno.UWP/UI/Composition/CompositionGeometricClip.cs new file mode 100644 index 000000000000..f5c9fb077f33 --- /dev/null +++ b/src/Uno.UWP/UI/Composition/CompositionGeometricClip.cs @@ -0,0 +1,17 @@ +#pragma warning disable 108 // new keyword hiding +#pragma warning disable 114 // new keyword hiding +namespace Windows.UI.Composition +{ + public partial class CompositionGeometricClip : global::Windows.UI.Composition.CompositionClip + { + public CompositionViewBox ViewBox + { + get; set; + } + + public CompositionGeometry Geometry + { + get; set; + } + } +} diff --git a/src/Uno.UWP/UI/Composition/CompositionGeometry.cs b/src/Uno.UWP/UI/Composition/CompositionGeometry.cs new file mode 100644 index 000000000000..eb20d1eaa885 --- /dev/null +++ b/src/Uno.UWP/UI/Composition/CompositionGeometry.cs @@ -0,0 +1,21 @@ +namespace Windows.UI.Composition +{ + public partial class CompositionGeometry : CompositionObject + { + internal CompositionGeometry(Compositor compositor) : base(compositor) + { + + } + + internal CompositionGeometry() + { + + } + + public float TrimStart { get; set; } + + public float TrimOffset { get; set; } + + public float TrimEnd { get; set; } + } +} diff --git a/src/Uno.UWP/UI/Composition/CompositionObject.cs b/src/Uno.UWP/UI/Composition/CompositionObject.cs index ce3728a01729..a1d09eb9c2e4 100644 --- a/src/Uno.UWP/UI/Composition/CompositionObject.cs +++ b/src/Uno.UWP/UI/Composition/CompositionObject.cs @@ -1,5 +1,6 @@ using System; +using Windows.UI.Core; namespace Windows.UI.Composition { @@ -7,7 +8,18 @@ public partial class CompositionObject : global::System.IDisposable { private object _gate = new object(); - public Compositor Compositor => Compositor.Current; + internal CompositionObject() + { + } + + internal CompositionObject(Compositor compositor) + { + Compositor = compositor; + } + + public Compositor Compositor { get; } + + public CoreDispatcher Dispatcher => CoreDispatcher.Main; public void StartAnimation(string propertyName, CompositionAnimation animation) { @@ -18,7 +30,8 @@ internal virtual void StartAnimationCore(string propertyName, CompositionAnimati public void StopAnimation(string propertyName) { - } + + public string Comment { get; set; } } } diff --git a/src/Uno.UWP/UI/Composition/CompositionPath.Skia.cs b/src/Uno.UWP/UI/Composition/CompositionPath.Skia.cs new file mode 100644 index 000000000000..d3a9b1b70d62 --- /dev/null +++ b/src/Uno.UWP/UI/Composition/CompositionPath.Skia.cs @@ -0,0 +1,11 @@ +#pragma warning disable 108 // new keyword hiding +#pragma warning disable 114 // new keyword hiding +using SkiaSharp; +using System; + +namespace Windows.UI.Composition +{ + public partial class CompositionPath + { + } +} diff --git a/src/Uno.UWP/UI/Composition/CompositionPath.cs b/src/Uno.UWP/UI/Composition/CompositionPath.cs new file mode 100644 index 000000000000..43609b603c00 --- /dev/null +++ b/src/Uno.UWP/UI/Composition/CompositionPath.cs @@ -0,0 +1,16 @@ +#pragma warning disable 108 // new keyword hiding +#pragma warning disable 114 // new keyword hiding +using Windows.Graphics; + +namespace Windows.UI.Composition +{ + public partial class CompositionPath : IGeometrySource2D + { + public CompositionPath(IGeometrySource2D source) + { + GeometrySource = source; + } + + internal IGeometrySource2D GeometrySource { get; } + } +} diff --git a/src/Uno.UWP/UI/Composition/CompositionPathGeometry.cs b/src/Uno.UWP/UI/Composition/CompositionPathGeometry.cs new file mode 100644 index 000000000000..d127129bc274 --- /dev/null +++ b/src/Uno.UWP/UI/Composition/CompositionPathGeometry.cs @@ -0,0 +1,12 @@ +namespace Windows.UI.Composition +{ + public partial class CompositionPathGeometry : CompositionGeometry + { + internal CompositionPathGeometry(Compositor compositor, CompositionPath path = null) : base(compositor) + { + Path = path; + } + + public CompositionPath Path { get; set; } + } +} diff --git a/src/Uno.UWP/UI/Composition/CompositionScopedBatch.cs b/src/Uno.UWP/UI/Composition/CompositionScopedBatch.cs index 249aba61f376..7f015503b7e6 100644 --- a/src/Uno.UWP/UI/Composition/CompositionScopedBatch.cs +++ b/src/Uno.UWP/UI/Composition/CompositionScopedBatch.cs @@ -1,5 +1,4 @@ -#pragma warning disable 108 // new keyword hiding -#pragma warning disable 114 // new keyword hiding +using System; using Uno; using Windows.Foundation; @@ -7,7 +6,8 @@ namespace Windows.UI.Composition { public partial class CompositionScopedBatch : global::Windows.UI.Composition.CompositionObject { - public CompositionScopedBatch(CompositionBatchTypes batchType) + internal CompositionScopedBatch() => throw new NotSupportedException(); + internal CompositionScopedBatch(Compositor compositor, CompositionBatchTypes batchType) : base(compositor) { BatchType = batchType; } diff --git a/src/Uno.UWP/UI/Composition/CompositionShape.Skia.cs b/src/Uno.UWP/UI/Composition/CompositionShape.Skia.cs new file mode 100644 index 000000000000..00585cf8b317 --- /dev/null +++ b/src/Uno.UWP/UI/Composition/CompositionShape.Skia.cs @@ -0,0 +1,13 @@ +using SkiaSharp; +using System.Numerics; + +namespace Windows.UI.Composition +{ + public partial class CompositionShape + { + internal virtual void Render(SKSurface surface, SKImageInfo info) + { + + } + } +} diff --git a/src/Uno.UWP/UI/Composition/CompositionShape.cs b/src/Uno.UWP/UI/Composition/CompositionShape.cs new file mode 100644 index 000000000000..af3f879bfdfc --- /dev/null +++ b/src/Uno.UWP/UI/Composition/CompositionShape.cs @@ -0,0 +1,19 @@ +using System.Numerics; + +namespace Windows.UI.Composition +{ + public partial class CompositionShape : global::Windows.UI.Composition.CompositionObject + { + public Matrix3x2 TransformMatrix { get; set; } + + public Vector2 Scale { get; set; } + + public float RotationAngleInDegrees { get; set; } + + public float RotationAngle { get; set; } + + public global::System.Numerics.Vector2 Offset { get; set; } + + public global::System.Numerics.Vector2 CenterPoint { get; set; } + } +} diff --git a/src/Uno.UWP/UI/Composition/CompositionShapeCollection.cs b/src/Uno.UWP/UI/Composition/CompositionShapeCollection.cs new file mode 100644 index 000000000000..4efc02f8cc0a --- /dev/null +++ b/src/Uno.UWP/UI/Composition/CompositionShapeCollection.cs @@ -0,0 +1,53 @@ +using System.Collections; +using System.Collections.Generic; + +namespace Windows.UI.Composition +{ + public partial class CompositionShapeCollection : CompositionObject, IList, IEnumerable + { + private List _shapes = new List(); + private ShapeVisual shapeVisual; + + internal CompositionShapeCollection(ShapeVisual shapeVisual) => this.shapeVisual = shapeVisual; + + public int Count => _shapes.Count; + + public int IndexOf(CompositionShape item) + => _shapes.IndexOf(item); + + public void Insert(int index, CompositionShape item) + => _shapes.Insert(index, item); + + public void RemoveAt(int index) + => _shapes.RemoveAt(index); + + public CompositionShape this[int index] + { + get => _shapes[index]; + set => _shapes[index] = value; + } + + public void Add(CompositionShape item) + => _shapes.Add(item); + + public void Clear() + => _shapes.Clear(); + + public bool Contains(CompositionShape item) + => _shapes.Contains(item); + + public void CopyTo(CompositionShape[] array, int arrayIndex) + => _shapes.CopyTo(array, arrayIndex); + + public bool Remove(CompositionShape item) + => _shapes.Remove(item); + + public bool IsReadOnly => false; + + public IEnumerator GetEnumerator() + => _shapes.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() + => _shapes.GetEnumerator(); + } +} diff --git a/src/Uno.UWP/UI/Composition/CompositionSpriteShape.Skia.cs b/src/Uno.UWP/UI/Composition/CompositionSpriteShape.Skia.cs new file mode 100644 index 000000000000..518143bddfcf --- /dev/null +++ b/src/Uno.UWP/UI/Composition/CompositionSpriteShape.Skia.cs @@ -0,0 +1,76 @@ +#pragma warning disable 108 // new keyword hiding +#pragma warning disable 114 // new keyword hiding +using SkiaSharp; +using System; + +namespace Windows.UI.Composition +{ + public partial class CompositionSpriteShape : CompositionShape + { + private SKPaint _strokePaint; + private SKPaint _fillPaint; + + public CompositionSpriteShape() + { + } + + internal override void Render(SKSurface surface, SKImageInfo info) + { + if (Geometry is CompositionPathGeometry cpg) + { + if (cpg.Path.GeometrySource is SkiaGeometrySource2D geometrySource) + { + if(FillBrush != null) + { + TryCreateFillPaint(); + + if (FillBrush is CompositionColorBrush fill) + { + _fillPaint.Color = fill.Color.ToSKColor(); + } + + surface.Canvas.DrawPath(geometrySource.Geometry, _fillPaint); + } + + if (StrokeBrush != null) + { + TryCreateStrokePaint(); + + if (StrokeBrush is CompositionColorBrush stroke) + { + _strokePaint.StrokeWidth = StrokeThickness; + _strokePaint.Color = stroke.Color.ToSKColor(); + } + + surface.Canvas.DrawPath(geometrySource.Geometry, _strokePaint); + } + } + else + { + throw new InvalidOperationException($"CompositionPath does not support the {cpg.Path?.GeometrySource} geometry source"); + } + } + } + + private void TryCreateStrokePaint() + { + if (_strokePaint == null) + { + _strokePaint = new SKPaint(); + _strokePaint.IsStroke = true; + _strokePaint.IsAntialias = true; + _strokePaint.IsAutohinted = true; + } + } + private void TryCreateFillPaint() + { + if (_fillPaint == null) + { + _fillPaint = new SKPaint(); + _fillPaint.IsStroke = false; + _fillPaint.IsAntialias = true; + _fillPaint.IsAutohinted = true; + } + } + } +} diff --git a/src/Uno.UWP/UI/Composition/CompositionSpriteShape.cs b/src/Uno.UWP/UI/Composition/CompositionSpriteShape.cs new file mode 100644 index 000000000000..993824ddfdb9 --- /dev/null +++ b/src/Uno.UWP/UI/Composition/CompositionSpriteShape.cs @@ -0,0 +1,36 @@ +#pragma warning disable 108 // new keyword hiding +#pragma warning disable 114 // new keyword hiding +namespace Windows.UI.Composition +{ + public partial class CompositionSpriteShape : CompositionShape + { + internal CompositionSpriteShape(CompositionGeometry geometry = null) + { + Geometry = geometry; + } + + public float StrokeThickness { get; set; } + + public CompositionStrokeCap StrokeStartCap { get; set; } + + public float StrokeMiterLimit { get; set; } + + public CompositionStrokeLineJoin StrokeLineJoin { get; set; } + + public CompositionStrokeCap StrokeEndCap { get; set; } + + public float StrokeDashOffset { get; set; } + + public CompositionStrokeCap StrokeDashCap { get; set; } + + public CompositionBrush StrokeBrush { get; set; } + + public bool IsStrokeNonScaling { get; set; } + + public CompositionGeometry Geometry { get; set; } + + public CompositionBrush FillBrush { get; set; } + + public CompositionStrokeDashArray StrokeDashArray { get; set; } + } +} diff --git a/src/Uno.UWP/UI/Composition/CompositionViewBox.cs b/src/Uno.UWP/UI/Composition/CompositionViewBox.cs new file mode 100644 index 000000000000..9508232cbd00 --- /dev/null +++ b/src/Uno.UWP/UI/Composition/CompositionViewBox.cs @@ -0,0 +1,15 @@ +#pragma warning disable 108 // new keyword hiding +#pragma warning disable 114 // new keyword hiding +using System.Numerics; + +namespace Windows.UI.Composition +{ + public partial class CompositionViewBox : CompositionObject + { + public float VerticalAlignmentRatio { get; set; } + public CompositionStretch Stretch { get; set; } + public Vector2 Size { get; set; } + public Vector2 Offset { get; set; } + public float HorizontalAlignmentRatio { get; set; } + } +} diff --git a/src/Uno.UWP/UI/Composition/Compositor.Skia.cs b/src/Uno.UWP/UI/Composition/Compositor.Skia.cs new file mode 100644 index 000000000000..930772d66995 --- /dev/null +++ b/src/Uno.UWP/UI/Composition/Compositor.Skia.cs @@ -0,0 +1,95 @@ + +using SkiaSharp; +using System.Diagnostics; +using System.Numerics; +using Windows.Services.Maps; + +namespace Windows.UI.Composition +{ + public partial class Compositor + { + internal ContainerVisual RootVisual { get; set; } + + //public CompositionSurfaceBrush CreateSurfaceBrush() + //{ + // throw new global::System.NotImplementedException("The member CompositionSurfaceBrush Compositor.CreateSurfaceBrush() is not implemented in Uno."); + //} + + //public CompositionSurfaceBrush CreateSurfaceBrush(ICompositionSurface surface) + //{ + // throw new global::System.NotImplementedException("The member CompositionSurfaceBrush Compositor.CreateSurfaceBrush(ICompositionSurface surface) is not implemented in Uno."); + //} + + internal void Render(SKSurface surface, SKImageInfo info) + { + var sw = Stopwatch.StartNew(); + + if (RootVisual != null) + { + foreach (var visual in RootVisual.Children) + { + RenderVisual(surface, info, visual); + } + } + + sw.Stop(); + + // global::System.Console.WriteLine($"Render time {sw.Elapsed}"); + } + + private static void RenderVisual(SKSurface surface, SKImageInfo info, Visual visual) + { + if (visual.Opacity != 0) + { + surface.Canvas.Save(); + + var visualMatrix = surface.Canvas.TotalMatrix; + + visualMatrix = visualMatrix.PreConcat(SKMatrix.CreateTranslation(visual.Offset.X, visual.Offset.Y)); + + if (visual.RotationAngleInDegrees != 0) + { + visualMatrix = visualMatrix.PreConcat(SKMatrix.CreateRotationDegrees(visual.RotationAngleInDegrees, visual.CenterPoint.X, visual.CenterPoint.Y)); + } + + if (visual.TransformMatrix != Matrix4x4.Identity) + { + visualMatrix = visualMatrix.PreConcat(visual.TransformMatrix.ToSKMatrix44().Matrix); + } + + surface.Canvas.SetMatrix(visualMatrix); + + if(visual.Clip is InsetClip insetClip) + { + surface.Canvas.ClipRect(new SKRect { + Top = insetClip.TopInset, + Bottom = insetClip.BottomInset, + Left = insetClip.LeftInset, + Right = insetClip.RightInset + }); + } + + visual.Render(surface, info); + + switch (visual) + { + case SpriteVisual spriteVisual: + foreach (var inner in spriteVisual.Children) + { + RenderVisual(surface, info, inner); + } + break; + + case ContainerVisual containerVisual: + foreach (var inner in containerVisual.Children) + { + RenderVisual(surface, info, inner); + } + break; + } + + surface.Canvas.Restore(); + } + } + } +} diff --git a/src/Uno.UWP/UI/Composition/Compositor.cs b/src/Uno.UWP/UI/Composition/Compositor.cs index e48507d25b5c..3122a5665aee 100644 --- a/src/Uno.UWP/UI/Composition/Compositor.cs +++ b/src/Uno.UWP/UI/Composition/Compositor.cs @@ -1,4 +1,3 @@ - using Windows.UI; namespace Windows.UI.Composition @@ -7,45 +6,46 @@ public partial class Compositor : global::System.IDisposable { private static object _gate = new object(); - public static Compositor Current { get; } = new Compositor(); - public ContainerVisual CreateContainerVisual() - { - return new ContainerVisual() + => new ContainerVisual(this) { }; - } public SpriteVisual CreateSpriteVisual() - { - return new SpriteVisual() + => new SpriteVisual(this) { }; - } public CompositionColorBrush CreateColorBrush() - { - return new CompositionColorBrush() + => new CompositionColorBrush(this) { }; - } public CompositionColorBrush CreateColorBrush(Color color) - { - return new CompositionColorBrush() + => new CompositionColorBrush(this) { Color = color }; - } public ScalarKeyFrameAnimation CreateScalarKeyFrameAnimation() - { - return new ScalarKeyFrameAnimation(); - } + => new ScalarKeyFrameAnimation(this); public CompositionScopedBatch CreateScopedBatch(CompositionBatchTypes batchType) - { - return new CompositionScopedBatch(batchType); - } + => new CompositionScopedBatch(this, batchType); + + public global::Windows.UI.Composition.ShapeVisual CreateShapeVisual() + => new ShapeVisual(this); + + public global::Windows.UI.Composition.CompositionSpriteShape CreateSpriteShape() + => new CompositionSpriteShape(); + + public CompositionSpriteShape CreateSpriteShape(CompositionGeometry geometry) + => new CompositionSpriteShape(geometry); + + public CompositionPathGeometry CreatePathGeometry() + => new CompositionPathGeometry(this); + + public global::Windows.UI.Composition.CompositionPathGeometry CreatePathGeometry(global::Windows.UI.Composition.CompositionPath path) + => new CompositionPathGeometry(this, path); } } diff --git a/src/Uno.UWP/UI/Composition/ContainerVisual.Skia.cs b/src/Uno.UWP/UI/Composition/ContainerVisual.Skia.cs new file mode 100644 index 000000000000..88e646d0b832 --- /dev/null +++ b/src/Uno.UWP/UI/Composition/ContainerVisual.Skia.cs @@ -0,0 +1,8 @@ +using SkiaSharp; + +namespace Windows.UI.Composition +{ + public partial class ContainerVisual : Visual + { + } +} diff --git a/src/Uno.UWP/UI/Composition/ContainerVisual.cs b/src/Uno.UWP/UI/Composition/ContainerVisual.cs index 9cdeb110a439..c5b89d10a388 100644 --- a/src/Uno.UWP/UI/Composition/ContainerVisual.cs +++ b/src/Uno.UWP/UI/Composition/ContainerVisual.cs @@ -4,9 +4,13 @@ namespace Windows.UI.Composition { public partial class ContainerVisual : global::Windows.UI.Composition.Visual { - internal ContainerVisual() + internal ContainerVisual() : base(null) { - Children = new VisualCollection(this); + } + + internal ContainerVisual(Compositor compositor) : base(compositor) + { + Children = new VisualCollection(compositor, this); } public VisualCollection Children { get; } diff --git a/src/Uno.UWP/UI/Composition/InsetClip.cs b/src/Uno.UWP/UI/Composition/InsetClip.cs new file mode 100644 index 000000000000..4598ea805109 --- /dev/null +++ b/src/Uno.UWP/UI/Composition/InsetClip.cs @@ -0,0 +1,15 @@ +#pragma warning disable 108 // new keyword hiding +#pragma warning disable 114 // new keyword hiding +namespace Windows.UI.Composition +{ + public partial class InsetClip : CompositionClip + { + public float TopInset { get; set; } + + public float RightInset { get; set; } + + public float LeftInset { get; set; } + + public float BottomInset { get; set; } + } +} diff --git a/src/Uno.UWP/UI/Composition/KeyFrameAnimation.cs b/src/Uno.UWP/UI/Composition/KeyFrameAnimation.cs index e96a053cec3c..ce88f36bc324 100644 --- a/src/Uno.UWP/UI/Composition/KeyFrameAnimation.cs +++ b/src/Uno.UWP/UI/Composition/KeyFrameAnimation.cs @@ -1,5 +1,4 @@ -#pragma warning disable 108 // new keyword hiding -#pragma warning disable 114 // new keyword hiding +using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -9,6 +8,12 @@ public partial class KeyFrameAnimation : CompositionAnimation { private ImmutableArray _keys = ImmutableArray.Empty; + internal KeyFrameAnimation() => throw new NotSupportedException(); + + internal KeyFrameAnimation(Compositor compositor) : base(compositor) + { + } + public AnimationStopBehavior StopBehavior { get; set; } public int IterationCount { get; set; } diff --git a/src/Uno.UWP/UI/Composition/ScalarKeyFrameAnimation.cs b/src/Uno.UWP/UI/Composition/ScalarKeyFrameAnimation.cs index cd6daf884af1..0c97b71e9c82 100644 --- a/src/Uno.UWP/UI/Composition/ScalarKeyFrameAnimation.cs +++ b/src/Uno.UWP/UI/Composition/ScalarKeyFrameAnimation.cs @@ -8,6 +8,10 @@ public partial class ScalarKeyFrameAnimation : global::Windows.UI.Composition.Ke { private List<(float normalizedProgressKey, float value)> _keys = new List<(float normalizedProgressKey, float value)>(); + internal ScalarKeyFrameAnimation(Compositor compositor) : base(compositor) + { + } + public override void InsertKeyFrame(float normalizedProgressKey, float value) => base.InsertKeyFrame(normalizedProgressKey, value); public override void InsertKeyFrame(float normalizedProgressKey, float value, CompositionEasingFunction easingFunction) => base.InsertKeyFrame(normalizedProgressKey, value, easingFunction); diff --git a/src/Uno.UWP/UI/Composition/ShapeVisual.Skia.cs b/src/Uno.UWP/UI/Composition/ShapeVisual.Skia.cs new file mode 100644 index 000000000000..53707c19a737 --- /dev/null +++ b/src/Uno.UWP/UI/Composition/ShapeVisual.Skia.cs @@ -0,0 +1,15 @@ +using SkiaSharp; + +namespace Windows.UI.Composition +{ + public partial class ShapeVisual + { + internal override void Render(SKSurface surface, SKImageInfo info) + { + foreach(var shape in Shapes) + { + shape.Render(surface, info); + } + } + } +} diff --git a/src/Uno.UWP/UI/Composition/ShapeVisual.cs b/src/Uno.UWP/UI/Composition/ShapeVisual.cs new file mode 100644 index 000000000000..c66c2af0d597 --- /dev/null +++ b/src/Uno.UWP/UI/Composition/ShapeVisual.cs @@ -0,0 +1,15 @@ +namespace Windows.UI.Composition +{ + public partial class ShapeVisual : global::Windows.UI.Composition.ContainerVisual + { + public ShapeVisual(Compositor compositor) + : base(compositor) + { + Shapes = new CompositionShapeCollection(this); + } + + public CompositionViewBox ViewBox { get; set; } + + public CompositionShapeCollection Shapes { get; } + } +} diff --git a/src/Uno.UWP/UI/Composition/SkiaExtensions.Skia.cs b/src/Uno.UWP/UI/Composition/SkiaExtensions.Skia.cs new file mode 100644 index 000000000000..ec81b6b779c3 --- /dev/null +++ b/src/Uno.UWP/UI/Composition/SkiaExtensions.Skia.cs @@ -0,0 +1,49 @@ +using SkiaSharp; +using System; +using System.Collections.Generic; +using System.Numerics; +using System.Text; +using Windows.Foundation; +using Windows.UI; + +namespace Windows.UI.Composition +{ + public static class SkiaExtensions + { + public static SKRect ToSKRect(this Rect rect) + => new SKRect((float)rect.Left, (float)rect.Top, (float)rect.Right, (float)rect.Bottom); + + public static Size ToSize(this SKSize size) + => new Size(size.Width, size.Height); + + public static SKColor ToSKColor(this Color color) + => new SKColor(red: color.R, green: color.G, blue: color.B, alpha: color.A); + + public static SKMatrix44 ToSKMatrix44(this Matrix4x4 m) + { + var ret = new SKMatrix44(); + + ret[0,0] = m.M11; + ret[1,0] = m.M12; + ret[2,0] = m.M13; + ret[3,0] = m.M14; + + ret[0,1] = m.M21; + ret[1,1] = m.M22; + ret[2,1] = m.M23; + ret[3,1] = m.M24; + + ret[0,2] = m.M31; + ret[1,2] = m.M32; + ret[2,2] = m.M33; + ret[3,2] = m.M34; + + ret[0,3] = m.M41; + ret[1,3] = m.M42; + ret[2,3] = m.M43; + ret[3,3] = m.M44; + + return ret; + } + } +} diff --git a/src/Uno.UWP/UI/Composition/SkiaGeometrySource2D.Skia.cs b/src/Uno.UWP/UI/Composition/SkiaGeometrySource2D.Skia.cs new file mode 100644 index 000000000000..9087b1c25e6a --- /dev/null +++ b/src/Uno.UWP/UI/Composition/SkiaGeometrySource2D.Skia.cs @@ -0,0 +1,18 @@ +using SkiaSharp; +using System; +using System.Collections.Generic; +using System.Text; +using Windows.Graphics; + +namespace Windows.UI.Composition +{ + public class SkiaGeometrySource2D : IGeometrySource2D + { + public SkiaGeometrySource2D(SKPath source = null) + { + Geometry = new SKPath(); + } + + public SKPath Geometry { get; } + } +} diff --git a/src/Uno.UWP/UI/Composition/SpriteVisual.Skia.cs b/src/Uno.UWP/UI/Composition/SpriteVisual.Skia.cs new file mode 100644 index 000000000000..06e0b82450fc --- /dev/null +++ b/src/Uno.UWP/UI/Composition/SpriteVisual.Skia.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Numerics; +using SkiaSharp; +using Uno.Extensions; +using Uno.Logging; + +namespace Windows.UI.Composition +{ + public partial class SpriteVisual : ContainerVisual + { + private readonly SKPaint _paint + = new SKPaint() + { + IsAntialias = true, + }; + + partial void OnBrushChangedPartial(CompositionBrush brush) + { + if (brush is CompositionColorBrush b) + { + _paint.Color = new SKColor(b.Color.R, b.Color.G, b.Color.B, b.Color.A); + } + else + { + this.Log().Error($"The brush type {brush?.GetType()} is not supported for sprite visuals."); + } + } + + internal override void Render(SKSurface surface, SKImageInfo info) + { + base.Render(surface, info); + + surface.Canvas.Save(); + + surface.Canvas.DrawRect( + new SKRect(left: 0, top: 0, right: Size.X, bottom: Size.Y), + _paint + ); + + surface.Canvas.Restore(); + } + } +} diff --git a/src/Uno.UWP/UI/Composition/SpriteVisual.cs b/src/Uno.UWP/UI/Composition/SpriteVisual.cs index 0b30209ca0ac..f5a68df2085f 100644 --- a/src/Uno.UWP/UI/Composition/SpriteVisual.cs +++ b/src/Uno.UWP/UI/Composition/SpriteVisual.cs @@ -6,6 +6,11 @@ public partial class SpriteVisual : ContainerVisual { private CompositionBrush _brush; + public SpriteVisual(Compositor compositor) : base(compositor) + { + + } + public CompositionBrush Brush { get diff --git a/src/Uno.UWP/UI/Composition/Visual.Android.cs b/src/Uno.UWP/UI/Composition/Visual.Android.cs index bc0e5b55ad8e..da38f2ebe6cb 100644 --- a/src/Uno.UWP/UI/Composition/Visual.Android.cs +++ b/src/Uno.UWP/UI/Composition/Visual.Android.cs @@ -7,7 +7,7 @@ namespace Windows.UI.Composition { public partial class Visual : global::Windows.UI.Composition.CompositionObject { - public View NativeOwner { get; set; } + internal View NativeOwner { get; set; } } } -#endif \ No newline at end of file +#endif diff --git a/src/Uno.UWP/UI/Composition/Visual.Skia.cs b/src/Uno.UWP/UI/Composition/Visual.Skia.cs new file mode 100644 index 000000000000..02d8ea2e7045 --- /dev/null +++ b/src/Uno.UWP/UI/Composition/Visual.Skia.cs @@ -0,0 +1,22 @@ +#if !__IOS__ +using System.Numerics; +using System; +using SkiaSharp; + +namespace Windows.UI.Composition +{ + public partial class Visual : global::Windows.UI.Composition.CompositionObject + { + internal virtual void Render(SKSurface surface, SKImageInfo info) + { + + } + + public CompositionClip Clip + { + get; + set; + } + } +} +#endif diff --git a/src/Uno.UWP/UI/Composition/Visual.cs b/src/Uno.UWP/UI/Composition/Visual.cs index 49c982628093..4d4abc6c3975 100644 --- a/src/Uno.UWP/UI/Composition/Visual.cs +++ b/src/Uno.UWP/UI/Composition/Visual.cs @@ -12,6 +12,13 @@ public partial class Visual : global::Windows.UI.Composition.CompositionObject private float _rotationAngleInDegrees; private Vector3 _rotationAxis = new Vector3(0, 0, 1); + public Visual(Compositor compositor) : base(compositor) + { + + } + + public Matrix4x4 TransformMatrix { get; set; } = Matrix4x4.Identity; + public Vector3 Offset { get { return _offset; } @@ -56,7 +63,7 @@ public Vector2 Size partial void OnSizeChanged(Vector2 value); - public float Opacity { get; set; } + public float Opacity { get; set; } = 1.0f; public Vector3 RotationAxis { diff --git a/src/Uno.UWP/UI/Composition/Visual.generic.cs b/src/Uno.UWP/UI/Composition/Visual.generic.cs new file mode 100644 index 000000000000..f3770eb7150e --- /dev/null +++ b/src/Uno.UWP/UI/Composition/Visual.generic.cs @@ -0,0 +1,11 @@ +#if !__IOS__ && !__SKIA__ && !__WASM__ && !__ANDROID__ && !__MACOS__ && !NETFRAMEWORK +using System.Numerics; +using System; + +namespace Windows.UI.Composition +{ + public partial class Visual : global::Windows.UI.Composition.CompositionObject + { + } +} +#endif diff --git a/src/Uno.UWP/UI/Composition/Visual.iOS.cs b/src/Uno.UWP/UI/Composition/Visual.iOS.cs index e3e4132148e7..c8621b83b08a 100644 --- a/src/Uno.UWP/UI/Composition/Visual.iOS.cs +++ b/src/Uno.UWP/UI/Composition/Visual.iOS.cs @@ -9,9 +9,9 @@ namespace Windows.UI.Composition { public partial class Visual : global::Windows.UI.Composition.CompositionObject { - public UIView NativeOwner { get; set; } + internal UIView NativeOwner { get; set; } - public CALayer NativeLayer { get; } + internal CALayer NativeLayer { get; } internal Visual() { @@ -85,4 +85,4 @@ internal static double ToRadians(double angle) } } } -#endif \ No newline at end of file +#endif diff --git a/src/Uno.UWP/UI/Composition/Visual.macOS.cs b/src/Uno.UWP/UI/Composition/Visual.macOS.cs index 0ce2fc9c651a..2597de958647 100644 --- a/src/Uno.UWP/UI/Composition/Visual.macOS.cs +++ b/src/Uno.UWP/UI/Composition/Visual.macOS.cs @@ -5,6 +5,6 @@ namespace Windows.UI.Composition { public partial class Visual : global::Windows.UI.Composition.CompositionObject { - public object NativeOwner { get; set; } + internal object NativeOwner { get; set; } } -} \ No newline at end of file +} diff --git a/src/Uno.UWP/UI/Composition/Visual.net.cs b/src/Uno.UWP/UI/Composition/Visual.net.cs index 0ce2fc9c651a..b5d8343c1f56 100644 --- a/src/Uno.UWP/UI/Composition/Visual.net.cs +++ b/src/Uno.UWP/UI/Composition/Visual.net.cs @@ -5,6 +5,6 @@ namespace Windows.UI.Composition { public partial class Visual : global::Windows.UI.Composition.CompositionObject { - public object NativeOwner { get; set; } + internal object NativeOwner { get; set; } } -} \ No newline at end of file +} diff --git a/src/Uno.UWP/UI/Composition/Visual.netstdref.cs b/src/Uno.UWP/UI/Composition/Visual.netstdref.cs new file mode 100644 index 000000000000..b5d8343c1f56 --- /dev/null +++ b/src/Uno.UWP/UI/Composition/Visual.netstdref.cs @@ -0,0 +1,10 @@ +using System.Numerics; +using System; + +namespace Windows.UI.Composition +{ + public partial class Visual : global::Windows.UI.Composition.CompositionObject + { + internal object NativeOwner { get; set; } + } +} diff --git a/src/Uno.UWP/UI/Composition/Visual.wasm.cs b/src/Uno.UWP/UI/Composition/Visual.wasm.cs index 0ce2fc9c651a..2597de958647 100644 --- a/src/Uno.UWP/UI/Composition/Visual.wasm.cs +++ b/src/Uno.UWP/UI/Composition/Visual.wasm.cs @@ -5,6 +5,6 @@ namespace Windows.UI.Composition { public partial class Visual : global::Windows.UI.Composition.CompositionObject { - public object NativeOwner { get; set; } + internal object NativeOwner { get; set; } } -} \ No newline at end of file +} diff --git a/src/Uno.UWP/UI/Composition/VisualCollection.Android.cs b/src/Uno.UWP/UI/Composition/VisualCollection.Android.cs index 1c58cd89c980..b621d283fb96 100644 --- a/src/Uno.UWP/UI/Composition/VisualCollection.Android.cs +++ b/src/Uno.UWP/UI/Composition/VisualCollection.Android.cs @@ -5,13 +5,6 @@ namespace Windows.UI.Composition { public partial class VisualCollection : global::Windows.UI.Composition.CompositionObject, global::System.Collections.Generic.IEnumerable { - private readonly Visual _owner; - - public VisualCollection(Visual owner) - { - _owner = owner; - } - partial void InsertAbovePartial(Visual newChild, Visual sibling) { } diff --git a/src/Uno.UWP/UI/Composition/VisualCollection.Skia.cs b/src/Uno.UWP/UI/Composition/VisualCollection.Skia.cs new file mode 100644 index 000000000000..1f272692eb11 --- /dev/null +++ b/src/Uno.UWP/UI/Composition/VisualCollection.Skia.cs @@ -0,0 +1,31 @@ +using System; + +namespace Windows.UI.Composition +{ + public partial class VisualCollection : global::Windows.UI.Composition.CompositionObject, global::System.Collections.Generic.IEnumerable + { + partial void InsertAbovePartial(Visual newChild, Visual sibling) + { + } + + partial void InsertAtBottomPartial(Visual newChild) + { + } + + partial void InsertAtTopPartial(Visual newChild) + { + } + + partial void InsertBelowPartial(Visual newChild, Visual sibling) + { + } + + partial void RemoveAllPartial() + { + } + + partial void RemovePartial(Visual child) + { + } + } +} diff --git a/src/Uno.UWP/UI/Composition/VisualCollection.cs b/src/Uno.UWP/UI/Composition/VisualCollection.cs index c354488c862a..e6604b41be04 100644 --- a/src/Uno.UWP/UI/Composition/VisualCollection.cs +++ b/src/Uno.UWP/UI/Composition/VisualCollection.cs @@ -1,5 +1,3 @@ -#pragma warning disable 108 // new keyword hiding -#pragma warning disable 114 // new keyword hiding using System.Collections; using System.Collections.Generic; @@ -7,8 +5,20 @@ namespace Windows.UI.Composition { public partial class VisualCollection : CompositionObject, IEnumerable { + private readonly Visual _owner; + private List _visuals = new List(); + internal VisualCollection(Compositor compositor, Visual owner) : base(compositor) + { + _owner = owner; + } + + internal VisualCollection(Visual owner) + { + _owner = owner; + } + public int Count => _visuals.Count; public void InsertAbove(Visual newChild, Visual sibling) diff --git a/src/Uno.UWP/UI/Composition/VisualCollection.iOS.cs b/src/Uno.UWP/UI/Composition/VisualCollection.iOS.cs index e5fcd30d2a19..a940bc5d42be 100644 --- a/src/Uno.UWP/UI/Composition/VisualCollection.iOS.cs +++ b/src/Uno.UWP/UI/Composition/VisualCollection.iOS.cs @@ -5,13 +5,6 @@ namespace Windows.UI.Composition { public partial class VisualCollection : global::Windows.UI.Composition.CompositionObject, global::System.Collections.Generic.IEnumerable { - private readonly Visual _owner; - - public VisualCollection(Visual owner) - { - _owner = owner; - } - partial void InsertAbovePartial(Visual newChild, Visual sibling) { _owner.NativeLayer.InsertSublayerAbove(newChild.NativeLayer, sibling.NativeLayer); diff --git a/src/Uno.UWP/UI/Composition/VisualCollection.macOS.cs b/src/Uno.UWP/UI/Composition/VisualCollection.macOS.cs index be0017ade2c1..efc2be663a71 100644 --- a/src/Uno.UWP/UI/Composition/VisualCollection.macOS.cs +++ b/src/Uno.UWP/UI/Composition/VisualCollection.macOS.cs @@ -5,13 +5,6 @@ namespace Windows.UI.Composition { public partial class VisualCollection : global::Windows.UI.Composition.CompositionObject, global::System.Collections.Generic.IEnumerable { - private readonly Visual _owner; - - public VisualCollection(Visual owner) - { - _owner = owner; - } - partial void InsertAbovePartial(Visual newChild, Visual sibling) { } diff --git a/src/Uno.UWP/UI/Composition/VisualCollection.net.cs b/src/Uno.UWP/UI/Composition/VisualCollection.net.cs index b2cd58b07e7d..1f272692eb11 100644 --- a/src/Uno.UWP/UI/Composition/VisualCollection.net.cs +++ b/src/Uno.UWP/UI/Composition/VisualCollection.net.cs @@ -4,13 +4,6 @@ namespace Windows.UI.Composition { public partial class VisualCollection : global::Windows.UI.Composition.CompositionObject, global::System.Collections.Generic.IEnumerable { - private readonly Visual _owner; - - public VisualCollection(Visual owner) - { - _owner = owner; - } - partial void InsertAbovePartial(Visual newChild, Visual sibling) { } diff --git a/src/Uno.UWP/UI/Composition/VisualCollection.netstdref.cs b/src/Uno.UWP/UI/Composition/VisualCollection.netstdref.cs new file mode 100644 index 000000000000..1f272692eb11 --- /dev/null +++ b/src/Uno.UWP/UI/Composition/VisualCollection.netstdref.cs @@ -0,0 +1,31 @@ +using System; + +namespace Windows.UI.Composition +{ + public partial class VisualCollection : global::Windows.UI.Composition.CompositionObject, global::System.Collections.Generic.IEnumerable + { + partial void InsertAbovePartial(Visual newChild, Visual sibling) + { + } + + partial void InsertAtBottomPartial(Visual newChild) + { + } + + partial void InsertAtTopPartial(Visual newChild) + { + } + + partial void InsertBelowPartial(Visual newChild, Visual sibling) + { + } + + partial void RemoveAllPartial() + { + } + + partial void RemovePartial(Visual child) + { + } + } +} diff --git a/src/Uno.UWP/UI/Composition/VisualCollection.wasm.cs b/src/Uno.UWP/UI/Composition/VisualCollection.wasm.cs index b2cd58b07e7d..1f272692eb11 100644 --- a/src/Uno.UWP/UI/Composition/VisualCollection.wasm.cs +++ b/src/Uno.UWP/UI/Composition/VisualCollection.wasm.cs @@ -4,13 +4,6 @@ namespace Windows.UI.Composition { public partial class VisualCollection : global::Windows.UI.Composition.CompositionObject, global::System.Collections.Generic.IEnumerable { - private readonly Visual _owner; - - public VisualCollection(Visual owner) - { - _owner = owner; - } - partial void InsertAbovePartial(Visual newChild, Visual sibling) { } diff --git a/src/Uno.UWP/UI/Core/CoreDispatcher.Skia.cs b/src/Uno.UWP/UI/Core/CoreDispatcher.Skia.cs new file mode 100644 index 000000000000..c39b9071d8c9 --- /dev/null +++ b/src/Uno.UWP/UI/Core/CoreDispatcher.Skia.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text; +using System.Threading.Tasks; + +namespace Windows.UI.Core +{ + public sealed partial class CoreDispatcher + { + /// + /// Provide a action that will delegate the dispach of CoreDispatcher work + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static Action DispatchOverride; + + public static bool HasThreadAccessOverride { get; set; } = true; + + private bool GetHasThreadAccess() => HasThreadAccessOverride; + + public static CoreDispatcher Main { get; } = new CoreDispatcher(); + + + partial void EnqueueNative() + { + if(DispatchOverride == null) + { + throw new InvalidOperationException("CoreDispatcher.DispatchOverride must be set"); + } + + DispatchOverride(() => DispatchItems()); + } + } +} diff --git a/src/Uno.UWP/UI/Core/CoreDispatcher.netstdref.cs b/src/Uno.UWP/UI/Core/CoreDispatcher.netstdref.cs new file mode 100644 index 000000000000..43fec8fccf9e --- /dev/null +++ b/src/Uno.UWP/UI/Core/CoreDispatcher.netstdref.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Windows.UI.Core +{ + public sealed partial class CoreDispatcher + { + public static bool HasThreadAccessOverride { get; set; } = true; + + private bool GetHasThreadAccess() => HasThreadAccessOverride; + + public static CoreDispatcher Main { get; } = new CoreDispatcher(); + + internal bool IsQueueEmpty => _queues.All(q => q.Count == 0); + } +} diff --git a/src/Uno.UWP/UI/Core/CoreWindow.cs b/src/Uno.UWP/UI/Core/CoreWindow.cs index a775af0a76b1..9f46d047e7d1 100644 --- a/src/Uno.UWP/UI/Core/CoreWindow.cs +++ b/src/Uno.UWP/UI/Core/CoreWindow.cs @@ -20,8 +20,11 @@ public static CoreWindow GetForCurrentThread() internal CoreWindow() { _current = this; + InitializePartial(); } + partial void InitializePartial(); + public CoreDispatcher Dispatcher => CoreDispatcher.Main; diff --git a/src/Uno.UWP/UI/Core/CoreWindow.skia.cs b/src/Uno.UWP/UI/Core/CoreWindow.skia.cs new file mode 100644 index 000000000000..442970cdd5f0 --- /dev/null +++ b/src/Uno.UWP/UI/Core/CoreWindow.skia.cs @@ -0,0 +1,60 @@ +using System; +using Uno.Foundation; +using Uno.Foundation.Extensibility; +using Windows.Foundation; + +namespace Windows.UI.Core +{ + public interface ICoreWindowExtension + { + + } + + public partial class CoreWindow : ICoreWindowEvents + { + private ICoreWindowExtension _coreWindowExtension; + + public event TypedEventHandler PointerEntered; + public event TypedEventHandler PointerExited; + public event TypedEventHandler PointerMoved; + public event TypedEventHandler PointerPressed; + public event TypedEventHandler PointerReleased; + public event TypedEventHandler PointerWheelChanged; + + partial void InitializePartial() + { + if(!ApiExtensibility.CreateInstance(this, out _coreWindowExtension)) + { + // throw new InvalidOperationException($"Unable to find ICoreWindowExtension extension"); + } + } + + void ICoreWindowEvents.RaisePointerEntered(PointerEventArgs args) + => PointerEntered?.Invoke(this, args); + + void ICoreWindowEvents.RaisePointerExited(PointerEventArgs args) + => PointerExited?.Invoke(this, args); + + void ICoreWindowEvents.RaisePointerMoved(PointerEventArgs args) + => PointerMoved?.Invoke(this, args); + + void ICoreWindowEvents.RaisePointerPressed(PointerEventArgs args) + => PointerPressed?.Invoke(this, args); + + void ICoreWindowEvents.RaisePointerReleased(PointerEventArgs args) + => PointerReleased?.Invoke(this, args); + + void ICoreWindowEvents.RaisePointerWheelChanged(PointerEventArgs args) + => PointerWheelChanged?.Invoke(this, args); + } + + public interface ICoreWindowEvents + { + void RaisePointerEntered(PointerEventArgs args); + void RaisePointerExited(PointerEventArgs args); + void RaisePointerMoved(PointerEventArgs args); + void RaisePointerPressed(PointerEventArgs args); + void RaisePointerReleased(PointerEventArgs args); + void RaisePointerWheelChanged(PointerEventArgs args); + } +} diff --git a/src/Uno.UWP/UI/Core/PointerEventArgs.cs b/src/Uno.UWP/UI/Core/PointerEventArgs.cs new file mode 100644 index 000000000000..f8c642906687 --- /dev/null +++ b/src/Uno.UWP/UI/Core/PointerEventArgs.cs @@ -0,0 +1,30 @@ +#pragma warning disable 108 // new keyword hiding +#pragma warning disable 114 // new keyword hiding +using Windows.UI.Input; + +namespace Windows.UI.Core +{ + public partial class PointerEventArgs : ICoreWindowEventArgs + { + internal PointerEventArgs(PointerPoint currentPoint) + { + CurrentPoint = currentPoint; + } + + public bool Handled + { + get; + set; + } + + public PointerPoint CurrentPoint { get; } + + [global::Uno.NotImplemented] + public global::Windows.System.VirtualKeyModifiers KeyModifiers + => throw new global::System.NotImplementedException("The member VirtualKeyModifiers PointerEventArgs.KeyModifiers is not implemented in Uno."); + + [global::Uno.NotImplemented] + public global::System.Collections.Generic.IList GetIntermediatePoints() + => throw new global::System.NotImplementedException("The member IList PointerEventArgs.GetIntermediatePoints() is not implemented in Uno."); + } +} diff --git a/src/Uno.UWP/UI/Input/GestureRecognizer.cs b/src/Uno.UWP/UI/Input/GestureRecognizer.cs index 290eae954606..0f2f8315dfb2 100644 --- a/src/Uno.UWP/UI/Input/GestureRecognizer.cs +++ b/src/Uno.UWP/UI/Input/GestureRecognizer.cs @@ -115,7 +115,7 @@ internal void ProcessMoveEvents(IList value, bool isRelevant) internal void ProcessUpEvent(PointerPoint value, bool isRelevant) { -#if NET461 || __WASM__ +#if NET461 || NETSTANDARD2_0 if (_gestures.TryGetValue(value.PointerId, out var gesture)) { _gestures.Remove(value.PointerId); diff --git a/src/Uno.UWP/Uno.csproj b/src/Uno.UWP/Uno.csproj index 3ab353b02d33..02a43c570c46 100644 --- a/src/Uno.UWP/Uno.csproj +++ b/src/Uno.UWP/Uno.csproj @@ -25,6 +25,8 @@ false true + + Reference