@@ -406,6 +406,60 @@ static CompositionColorBrush TranslateBoundSolidColor(
406406 return result ;
407407 }
408408
409+ // Animate Vector2 property of object with TrimmedAnimatable while applying OriginOffset to it.
410+ // Returns non-null Sn.Vector2 value if no animation is needed (and no animation was applied).
411+ static Sn . Vector2 ? AnimateVector2WithOriginOffsetOrGetValue (
412+ LayerContext context ,
413+ CompositionObject obj ,
414+ string propertyName ,
415+ TrimmedAnimatable < Vector2 > value )
416+ {
417+ if ( context is not ShapeLayerContext || ( ( ShapeLayerContext ) context ) . OriginOffset is null )
418+ {
419+ if ( value . IsAnimated )
420+ {
421+ Animate . Vector2 ( context , value , obj , propertyName ) ;
422+ return null ;
423+ }
424+ else
425+ {
426+ return ConvertTo . Vector2 ( value . InitialValue ) ;
427+ }
428+ }
429+
430+ var offset = ( ( ShapeLayerContext ) context ) . OriginOffset ! ;
431+
432+ if ( ! offset . IsAnimated && ! value . IsAnimated )
433+ {
434+ return ConvertTo . Vector2 ( value . InitialValue ) + offset . OffsetValue ;
435+ }
436+
437+ // Animate source property first.
438+ // We are using this auxiliary property to store original animation,
439+ // so that its value can be used in expression animation of property itself.
440+ string sourcePropertyName = propertyName + "Source" ;
441+ obj . Properties . InsertVector2 ( sourcePropertyName , ConvertTo . Vector2 ( value . InitialValue ) ) ;
442+ Animate . Vector2 ( context , value , obj , sourcePropertyName ) ;
443+
444+ // Create expression that offsets source property by origin offset.
445+ WinCompData . Expressions . Vector2 expression = offset . IsAnimated ?
446+ ExpressionFactory . OriginOffsetExressionAdded ( sourcePropertyName , offset . OffsetExpression ) :
447+ ExpressionFactory . OriginOffsetValueAdded ( sourcePropertyName , offset . OffsetValue ) ;
448+
449+ var expressionAnimation = context . ObjectFactory . CreateExpressionAnimation ( expression ) ;
450+ expressionAnimation . SetReferenceParameter ( "my" , obj ) ;
451+ if ( offset . IsAnimated )
452+ {
453+ // Expression can use geometry.
454+ expressionAnimation . SetReferenceParameter ( "geometry" , offset . Geometry ) ;
455+ }
456+
457+ // Animate original property with expression that applies origin offset to it.
458+ Animate . WithExpression ( obj , expressionAnimation , propertyName ) ;
459+
460+ return null ;
461+ }
462+
409463 static CompositionLinearGradientBrush ? TranslateLinearGradient (
410464 LayerContext context ,
411465 IGradient linearGradient ,
@@ -419,22 +473,16 @@ static CompositionColorBrush TranslateBoundSolidColor(
419473 var startPoint = Optimizer . TrimAnimatable ( context , linearGradient . StartPoint ) ;
420474 var endPoint = Optimizer . TrimAnimatable ( context , linearGradient . EndPoint ) ;
421475
422- if ( startPoint . IsAnimated )
423- {
424- Animate . Vector2 ( context , startPoint , result , nameof ( result . StartPoint ) ) ;
425- }
426- else
476+ var startPointValue = AnimateVector2WithOriginOffsetOrGetValue ( context , result , nameof ( result . StartPoint ) , startPoint ) ;
477+ if ( startPointValue is not null )
427478 {
428- result . StartPoint = ConvertTo . Vector2 ( startPoint . InitialValue ) ;
479+ result . StartPoint = startPointValue ! ;
429480 }
430481
431- if ( endPoint . IsAnimated )
432- {
433- Animate . Vector2 ( context , endPoint , result , nameof ( result . EndPoint ) ) ;
434- }
435- else
482+ var endPointValue = AnimateVector2WithOriginOffsetOrGetValue ( context , result , nameof ( result . EndPoint ) , endPoint ) ;
483+ if ( endPointValue is not null )
436484 {
437- result . EndPoint = ConvertTo . Vector2 ( endPoint . InitialValue ) ;
485+ result . EndPoint = endPointValue ! ;
438486 }
439487
440488 var gradientStops = Optimizer . TrimAnimatable ( context , linearGradient . GradientStops ) ;
@@ -470,13 +518,10 @@ static CompositionColorBrush TranslateBoundSolidColor(
470518 var startPoint = Optimizer . TrimAnimatable ( context , gradient . StartPoint ) ;
471519 var endPoint = Optimizer . TrimAnimatable ( context , gradient . EndPoint ) ;
472520
473- if ( startPoint . IsAnimated )
474- {
475- Animate . Vector2 ( context , startPoint , result , nameof ( result . EllipseCenter ) ) ;
476- }
477- else
521+ var startPointValue = AnimateVector2WithOriginOffsetOrGetValue ( context , result , nameof ( result . EllipseCenter ) , startPoint ) ;
522+ if ( startPointValue is not null )
478523 {
479- result . EllipseCenter = ConvertTo . Vector2 ( startPoint . InitialValue ) ;
524+ result . EllipseCenter = startPointValue ! ;
480525 }
481526
482527 if ( endPoint . IsAnimated )
0 commit comments