Composition and layout refactor#1318
Conversation
…more closely with Xaml, as detailed in the docs/CoreAnimation/WinObjc.Composition.and.Layout.docx dev spec.
Some highlights include:
1. Streamlines the usage of arbitrary Xaml FrameworkElements by allowing them to be positioned just as any other UIView in the application.
2. Supports rendering over Xaml-backed UIKit controls; adding adornments, etc.
3. Supports adding subviews and sublayers to Xaml-backed UIKit controls.
4. Separates the complex details of our Core Animation composition layer into distinct and manageable subcomponents � improving maintainability.
5. Defines a concrete relationship between every UIView, its root CALayer, and its backing Xaml FrameworkElement.
6. Streamlines the UIElement tree by removing unnecessary UIElements (for example; this results in a ~30% reduction of UIElements on the initial scene of WOCCatalog).
7. Simplifies app rendering by removing our two custom Panel implementations; thus eliminating the need to take part in Arrange and Measure passes.
8. Paves the way for eventual Xaml-markup-driven UIElement trees in ported WinObjC apps, because we no longer require re-parenting Xaml FrameworkElements that are positioned by Core Animation.
9. Moves the rest of the Core Animation composition layer over to C++, to benefit from modern programming constructs such as RAII, external ref-counting (shared_ptr), etc.
In order to implement these changes, we had to move UILabel over to a fully Xaml-backed implementation (rather than following a more complicated path with fake 'textures' down into the compositor). As a result, there are some known issues around text layout in one of our internal test apps (MM); we'll address those issues (and anything else that comes up) in a stabilization pass after these changes go in.
|
@msft-Jeyaram is added to the review. #Closed |
|
@ashvarma is added to the review. #Closed |
|
@bviglietta is added to the review. #Closed |
| #import "CAAnimationInternal.h" | ||
| #import "CALayerInternal.h" | ||
|
|
||
| static const wchar_t* TAG = L"LayerTransaction"; |
There was a problem hiding this comment.
LayerTransaction [](start = 30, length = 16)
A lot of this came from CompositorInterface.mm. #Resolved
|
|
||
| void LayerProxy::SetTexture(const std::shared_ptr<IDisplayTexture>& texture, float width, float height, float contentScale) { | ||
| _currentTexture = texture; | ||
| _SetContents((texture ? texture->GetContent() : nullptr), width, height, contentScale); |
There was a problem hiding this comment.
A lot of this came from CompositorInterface.mm. #Resolved
|
|
||
| _type = [type retain]; | ||
| _subType = [subType retain]; | ||
| beginTime = 0; |
There was a problem hiding this comment.
A lot of this came from CompositorInterface.mm; sorry it's not easy to diff. #Resolved
|
|
||
| using namespace Microsoft::WRL; | ||
|
|
||
| static const wchar_t* TAG = L"DisplayTexture"; |
There was a problem hiding this comment.
DisplayTexture [](start = 30, length = 14)
A lot of this came from CompositorInterface.mm; sorry it's not easy to diff. #Resolved
|
|
||
| #import <algorithm> | ||
|
|
||
| static const wchar_t* TAG = L"DisplayProperties"; |
There was a problem hiding this comment.
DisplayProperties [](start = 30, length = 17)
A lot of this came from CompositorInterface.mm; sorry it's not easy to diff. #Resolved
| @@ -381,7 +381,9 @@ UIKIT_EXPORT_CLASS | |||
| // WinObjC Xaml Extensions | |||
There was a problem hiding this comment.
Dustin; I don't think we currently have an annotation for this. #Resolved
| @class WXFrameworkElement; | ||
| @interface UIView (UIKitXamlExtensions) | ||
| @property (nonatomic, retain) WXFrameworkElement* xamlElement; | ||
| + (WXFrameworkElement*)createXamlElement; |
There was a problem hiding this comment.
Couldn't go with the 'layerClass' model here, because the types we want to create are in UIKit.Xaml and are not yet projected to ObjC. #Resolved
| using namespace Windows::UI::Xaml::Controls; | ||
| using namespace Windows::UI::Xaml::Media; | ||
|
|
||
| static const wchar_t* TAG = L"DisplayTexture"; |
There was a problem hiding this comment.
DisplayTexture [](start = 30, length = 14)
A lot of this came from either CALayerXaml.cpp or XamlCompositor.cpp; sorry it's not easy to diff. #Resolved
| using namespace Windows::UI::Xaml::Media; | ||
| using namespace Windows::UI::Xaml::Media::Imaging; | ||
|
|
||
| static const wchar_t* TAG = L"LayerAnimation"; |
There was a problem hiding this comment.
LayerAnimation [](start = 30, length = 14)
A lot of this came from either CALayerXaml.cpp or XamlCompositor.cpp; sorry it's not easy to diff. #Resolved
| using namespace Windows::UI::Xaml::Media::Animation; | ||
| using namespace Windows::UI::Xaml::Media::Imaging; | ||
|
|
||
| static const wchar_t* TAG = L"LayerCoordinator"; |
There was a problem hiding this comment.
LayerCoordinator [](start = 30, length = 16)
A lot of this came from either CALayerXaml.cpp or XamlCompositor.cpp; sorry it's not easy to diff. #Resolved
| using namespace Windows::UI::Xaml::Controls; | ||
| using namespace Windows::UI::Xaml::Media; | ||
|
|
||
| static const wchar_t* TAG = L"LayerProxy"; |
There was a problem hiding this comment.
LayerProxy [](start = 30, length = 10)
A lot of this came from either CALayerXaml.cpp or XamlCompositor.cpp; sorry it's not easy to diff. #Resolved
| using namespace Windows::UI::Xaml::Media::Animation; | ||
| using namespace Windows::UI::Xaml::Media::Imaging; | ||
|
|
||
| static const wchar_t* TAG = L"StoryboardManager"; |
There was a problem hiding this comment.
StoryboardManager [](start = 30, length = 17)
A lot of this came from either CALayerXaml.cpp or XamlCompositor.cpp; sorry it's not easy to diff. #Resolved
|
|
||
| using namespace Microsoft::WRL; | ||
|
|
||
| static const wchar_t* TAG = L"XamlCompositor"; |
There was a problem hiding this comment.
XamlCompositor [](start = 30, length = 14)
This is the remains of CompositorInterface.mm. #Resolved
|
|
||
| /** | ||
| Microsoft Extension | ||
| All CALayers are ultimately backed by a Xaml FrameworkElement. Passing nil here will |
There was a problem hiding this comment.
We should push for a @status to note this, it'd be cool to show our additions in another chart area #Resolved
There was a problem hiding this comment.
| @Status Interoperable | ||
| */ | ||
| - (CGAffineTransform)affineTransform { | ||
| CGAffineTransform ret; |
There was a problem hiding this comment.
eTransform re [](start = 11, length = 13)
Instead of poking at these directly, you can use CGAffineTransformMake(a,b,c,d,tx,ty) #Resolved
| // Query for our backing XAML node. | ||
| // ILayerProxy will have created one if the xamlElement passed into the previous CreateLayerProxy call was nullptr. | ||
| Microsoft::WRL::ComPtr<IInspectable> inspectable(_layerProxy->GetXamlElement()); | ||
| _xamlElement = _createRtProxy([WXFrameworkElement class], inspectable.Get()); |
There was a problem hiding this comment.
use createwith here? #Resolved
| before ? [before _priv]->_presentationNode : NULL, | ||
| after ? [after _priv]->_presentationNode : NULL); | ||
| [self _currentLayerTransaction]->MoveLayer([layer _layerProxy], | ||
| before ? [before _layerProxy] : nullptr, |
There was a problem hiding this comment.
nit: shouldn't need to make ternary with messages here #ByDesign
There was a problem hiding this comment.
yeah: if before is nil, [nil _layerProxy] will return the right thing. Unless it's a C++ type, but really the ideal here is to do the right thing :P
In reply to: 86621323 [](ancestors = 86621323)
There was a problem hiding this comment.
the compiler on the reference platform memsets an out struct pointer to 0 if the destination of the message is nil.
In reply to: 86900544 [](ancestors = 86900544,86621323)
There was a problem hiding this comment.
_layerProxy returns an std::shared_ptr; not doing the nil check lead to AVs.
In reply to: 86900578 [](ancestors = 86900578,86900544,86621323)
| ret = [CATransaction _implicitAnimationForKey:key]; | ||
| if (ret != nil) { | ||
| NSObject* value = GetCACompositor()->getDisplayProperty(priv->_presentationNode, [key UTF8String]); | ||
| NSObject* value = reinterpret_cast<NSObject*>(priv->_layerProxy->GetPropertyValue([key UTF8String])); |
There was a problem hiding this comment.
priv->_layerProxy->GetPropertyValue [](start = 62, length = 35)
Sweet! #Resolved
|
|
||
| // Get the backing sublayer xaml UIElement for fromLayer | ||
| // We use the sublayer element to support proper point conversion within a scrolled view. | ||
| WXUIElement* fromLayerElement = [fromLayer _getSublayerXamlElement]; |
There was a problem hiding this comment.
WXUIElement* [](start = 4, length = 12)
Could we make this work with WXFrameworkElement instead? Just wondering if we need to keep it consistent for readability or is there something else that is used in the parent class. #Resolved
There was a problem hiding this comment.
|
|
| @@ -36,14 +36,15 @@ | |||
|
|
|||
There was a problem hiding this comment.
Nits about these guys:
__declspec(thread)objective-C things will not be properly ref-counted.- they're being compared against
NULL(not evennullptr!) instead ofnileverywhere in this file.
#Resolved
There was a problem hiding this comment.
I don't want to change this now, but I'll add a TODO in the code.
In reply to: 86900474 [](ancestors = 86900474)
good point - these should have moved along with the rest of the DisplayProperties -- into DisplayProperties.h -- and switched to an enum. In reply to: 258740082 [](ancestors = 258740082) Refers to: Frameworks/include/CACompositor.h:117 in ff95a9a. [](commit_id = ff95a9a, deletion_comment = False) |
there's no reason. they should all be underscored, but i'm not going to do that in this change - I don't want to unnecessarily add to the churn. In reply to: 258966276 [](ancestors = 258966276) Refers to: Frameworks/include/CALayerInternal.h:65 in ff95a9a. [](commit_id = ff95a9a, deletion_comment = False) |
ideally they would all be private, too....so it's easier to see which state is accessed externally, but I'm not fixing that now, either. In reply to: 259010707 [](ancestors = 259010707,258966276) Refers to: Frameworks/include/CALayerInternal.h:65 in ff95a9a. [](commit_id = ff95a9a, deletion_comment = False) |
there are a lot of missing underscores, but I'm not going to address them with this change. In reply to: 258967895 [](ancestors = 258967895) Refers to: Frameworks/include/CALayerInternal.h:111 in ff95a9a. [](commit_id = ff95a9a, deletion_comment = False) |
could have, but didn't bother making that change with this refactor. it may open up additional cans of worms, and isn't necessary at this time. In reply to: 258982393 [](ancestors = 258982393) Refers to: Frameworks/QuartzCore/CALayer.mm:101 in ff95a9a. [](commit_id = ff95a9a, deletion_comment = False) |
| Microsoft Extension | ||
| */ | ||
| + (WXFrameworkElement*)createXamlElement { | ||
| // Default to CALayer's default backing Xaml element |
There was a problem hiding this comment.
// Default to CALayer's default backing Xaml element [](start = 4, length = 52)
Stale comment? #Resolved
There was a problem hiding this comment.
nope, but i'll change it to '// Use CALayer's default backing Xaml element' since i was overusing 'default' :)
In reply to: 87280021 [](ancestors = 87280021)
Shouldn't this one be the designated initializer and call [super init] as well? You can then pipe initWithIdentifier through it for a simple optimization of the autoResizingMask setting. #Pending Refers to: Frameworks/UIKit/UIViewController.mm:248 in 6d10e3d. [](commit_id = 6d10e3d, deletion_comment = False) |
| [_pageMappings setObject:self forKey:(id)(void*)pageObj.Get()]; | ||
|
|
||
| // Create a template UIView | ||
| priv->_page = CreateRtProxy([WXCPage class], pageObj.Get()); |
There was a problem hiding this comment.
CreateRtProxy [](start = 18, length = 13)
This utility function doesn't have the autorelease support. Is that intentional? #Pending
There was a problem hiding this comment.
we should file a bug to get rid of CreateRtProxy. I'll move this one to createWith.
In reply to: 87281267 [](ancestors = 87281267)
There was a problem hiding this comment.
also - why doesn't CreateRtProxy autorelease? Quite strange.
In reply to: 87281492 [](ancestors = 87281492,87281267)
| - (instancetype)initWithFrame:(CGRect)frame { | ||
| // Run on the main thread because the underlying XAML objects can only be | ||
| // called from the UI thread | ||
| RunSynchronouslyOnMainThread(^{ |
There was a problem hiding this comment.
RunSynchronouslyOnMainThread [](start = 4, length = 28)
Should we have called [super init] preceded this as well? UIView -> UIResponder -> NSObject? I noticed that UIWebView has this pattern. #Pending
There was a problem hiding this comment.
Maybe? Although, UIView's init calls initWithFrame, which is the designated initializer for UIView. Regardless, I'd prefer to get this in before we make any more changes to UIView's init path (assuming this is functionally correct and isn't introducing any regressions).
In reply to: 87282018 [](ancestors = 87282018)
|
|
||
| Label::Label() { | ||
| InitializeComponent(); | ||
| Name = L"UILabel"; |
There was a problem hiding this comment.
Name = L"UILabel"; [](start = 4, length = 18)
I wonder if we did this in the other controls as well. Seems like a good idea. #Resolved
There was a problem hiding this comment.
I'll move it up to UILabel.mm so we can set the name of the actual (potentially derived) class.
In reply to: 87285187 [](ancestors = 87285187)
There was a problem hiding this comment.
actually, it's already handled in UIView.mm, so I'll delete it from here and also from UIButton.mm.
In reply to: 87285928 [](ancestors = 87285928,87285187)
|
|
This change refactors WinObjC's QuartzCore and UIKit stacks to align more closely with Xaml, as detailed in the docs/CoreAnimation/WinObjc.Composition.and.Layout.docx dev spec.
Some highlights include:
In order to implement these changes, we had to move UILabel over to a fully Xaml-backed implementation (rather than following a more complicated path with fake 'textures' down into the compositor). As a result, there are some known issues around text layout in one of our internal test apps (MM); we'll address those issues (and anything else that comes up) in a stabilization pass after these changes go in.
This change is