/// <summary>
 /// Updates the state of the the ImageLoadEngine after loading an image
 /// </summary>
 private async void PostLoadImage()
 {
     switch (_engineState)
     {
         case ImageEngineState.Idle:
             // Do Nothing
             _scheduledObject = null;
             break;
         case ImageEngineState.Loading:
             // Loading is complete. No image pending load.
             _engineState = ImageEngineState.Idle;
             _scheduledObject = null;
             // Now that the load has completed, Invalidate the Measure
             InvalidateMeasure();
             break;
         case ImageEngineState.Scheduled:
             // New image waiting in the pipeline to be rendered.
             _engineState = ImageEngineState.Loading;
             // Load the image
             await LoadImageAsync(_scheduledObject, _frameLayer.Size.ToSize());
             break;
     }
 }
        private void ClearImageFrame()
        {
            // Clear the progress in the Placeholder
            ProgressHandler(-1);

            if (RenderFast)
            {
                // Make the frameVisualContent transparent
                _frameContentVisual.Brush = _compositor.CreateColorBrush(Colors.Transparent);
                // Dispose the ImageSurface
                _imageSurface?.Dispose();
                _imageSurface = null;
                // Engine is now idle
                _engineState = ImageEngineState.Idle;
            }
            else
            {
                _compositor.CreateScopedBatch(CompositionBatchTypes.Animation,
                    () =>
                    {
                        // Fade out the frameVisualContent
                        _frameContentVisual.StartAnimation(() => _frameContentVisual.Opacity, _fadeOutAnimation);
                    },
                    () =>
                    {
                        // Make the frameVisualContent transparent
                        _frameContentVisual.Brush = _compositor.CreateColorBrush(Colors.Transparent);
                        //await _imageSurface.RedrawAsync(cachedUri, size, _imageOptions);
                        _frameContentVisual.Opacity = 1;
                        // Dispose the ImageSurface
                        _imageSurface?.Dispose();
                        _imageSurface = null;
                        // Engine is now idle
                        _engineState = ImageEngineState.Idle;
                    });
            }
        }
 /// <summary>
 /// Updates the state of the the ImageLoadEngine before loading an image
 /// </summary>
 private async void ScheduleNextLoad()
 {
     _scheduledObject = Source;
     switch (_engineState)
     {
         case ImageEngineState.Idle:
             _engineState = ImageEngineState.Loading;
             // Load the image
             await LoadImageAsync(_scheduledObject, _frameLayer.Size.ToSize());
             break;
         case ImageEngineState.Loading:
             _engineState = ImageEngineState.Scheduled;
             break;
         case ImageEngineState.Scheduled:
             break;
     }
 }
        /// <summary>
        /// Loads the Uri scheduled for load. If after loading there is another
        /// Uri scheduled it loads that and keeps on repeating this until there
        /// are no more Uris scheduled for load.
        /// </summary>
        /// <param name="objectToLoad">Object scheduled to be loaded in the ImageFrame</param>
        /// <param name="size">Size of the ImageSurface</param>
        /// <param name="isLoadingNext">Whether loading in the imageSurface or the 
        /// nextImageSurface</param>
        /// <returns>Uri</returns>
        private async Task<Uri> LoadNextScheduledObject(object objectToLoad, Size size, bool isLoadingNext)
        {
            bool loadNext;
            Uri cachedUri;

            do
            {
                _currentObject = objectToLoad;
                cachedUri = await ImageCache.GetCachedUriAsync(objectToLoad, ProgressHandler);

                // Load the new uri
                if (isLoadingNext)
                {
                    _nextImageSurface =
                                    await _generator.CreateImageSurfaceAsync(cachedUri, size, _imageOptions);
                }
                else
                {
                    _imageSurface = await _generator.CreateImageSurfaceAsync(cachedUri, size, _imageOptions);
                }

                // Report 99% progress
                ProgressHandler(99);

                // Since the loading of the object takes some time, it could be possible
                // that a new object has been scheduled for load. In that case, discard
                // the current object and load the scheduled object
                if (_engineState == ImageEngineState.Scheduled)
                {
                    loadNext = true;
                    objectToLoad = _scheduledObject;
                    _engineState = ImageEngineState.Loading;
                }
                else
                {
                    loadNext = false;
                }
            } while (loadNext);

            return cachedUri;
        }
        /// <summary>
        /// Handles the Arrange pass during Layout
        /// </summary>
        /// <param name="finalSize">Final Size of the control</param>
        /// <returns>Total size occupied by the Children</returns>
        protected override Size ArrangeOverride(Size finalSize)
        {
            // Taking into account the BorderThickness and Padding
            var borders = BorderThickness;
            var padding = Padding;
            var corners = CornerRadius;
            var borderSize = borders.CollapseThickness();
            var paddingSize = padding.CollapseThickness();

            // Calculate the Offset for the frameVisual
            var left = (borders.Left + padding.Left).Single();
            var top = (borders.Top + padding.Top).Single();

            // Calculate the Dimensions of the frameVisual
            var width = Math.Max(0, finalSize.Width - borderSize.Width - paddingSize.Width).Single();
            var height = Math.Max(0, finalSize.Height - borderSize.Height - paddingSize.Height).Single();

            // Set the Size and Offset of visuals in the ImageFrame
            var frameSize = new Vector2(width, height);
            _rootContainer.Size = frameSize;
            _frameLayer.Size = frameSize;
            _frameBackgroundVisual.Size = frameSize;
            _frameContentVisual.Size = frameSize;
            _placeholderContentVisual.Size = frameSize;
            _placeholderBackgroundVisual.Size = frameSize;
            _shadowVisual.Size = frameSize;
            _nextVisualContent.Size = frameSize;
            _rootContainer.Offset = new Vector3(left, top, 0);

            // Update the frameLayerMask in case the CornerRadius or 
            // BorderThickness or Padding has changed
            var pathInfo = new CompositionPathInfo(corners, borders, padding, false);
            using (var geometry =
                CompositionGenerator.GenerateGeometry(_generator.Device, frameSize.ToSize(),
                    pathInfo, Vector2.Zero))
            {
                _frameLayerMask.Redraw(_frameLayer.Size.ToSize(), geometry);
            }

            // If the FrameBackground has changed since the last time it was
            // applied to the frameBackgroundVisual, then animate the brush's
            // color to the new color.
            var brush = _frameBackgroundVisual.Brush as CompositionColorBrush;
            if (brush != null)
            {
                if (!brush.Color.Equals(FrameBackground))
                {
                    // If we are rendering fast, then no need to animate.
                    // Just set the final value.
                    if (RenderFast)
                    {
                        brush.Color = FrameBackground;
                    }
                    else
                    {
                        _colorAnimation.InsertKeyFrame(1f, FrameBackground);
                        brush.StartAnimation("Color", _colorAnimation);
                    }
                }
            }

            // If the PlaceholderBackground has changed since the last time it was
            // applied to the _placeholderBackgroundVisual, then update the brush's
            // color to the new color.
            brush = _placeholderBackgroundVisual.Brush as CompositionColorBrush;
            if (brush != null)
            {
                if (!brush.Color.Equals(PlaceholderBackground))
                {
                    brush.Color = PlaceholderBackground;
                }
            }

            // Redraw the placeholder content with the latest placeholder color
            _placeholderContentMask.Redraw(PlaceholderColor, PlaceholderBackground);

            // Set the stretch property of placeholder content's brush according to its size
            if ((width > PlaceholderSize.Width) && (height > PlaceholderSize.Height))
            {
                _placeholderContentBrush.Stretch = CompositionStretch.None;
            }
            else
            {
                _placeholderContentBrush.Stretch = CompositionStretch.Uniform;
            }

            // Update the imageOptions
            _imageOptions.Stretch = Stretch;
            _imageOptions.HorizontalAlignment = AlignX;
            _imageOptions.VerticalAlignment = AlignY;
            _imageOptions.Interpolation = Interpolation;
            _imageOptions.SurfaceBackgroundColor = Colors.Transparent;
            _imageOptions.AutoResize = !RenderOptimized;

            // If Source is valid then try loading/refreshing the ImageSurface
            if (Source != null)
            {
                if (_imageSurface != null)
                {
                    // Resize the ImageSurface to the new size
                    _imageSurface.Resize(frameSize.ToSize(), _imageOptions);
                    // Update the surface brush based on the Stretch and Alignment options
                    if (RenderFast)
                    {
                        // Use no animations to update alignment if we are rendering fast
                        (_frameContentVisual.Brush as CompositionSurfaceBrush)?.UpdateSurfaceBrushOptions(Stretch,
                            AlignX, AlignY);
                    }
                    else
                    {
                        // Update stretch and alignment using animation
                        (_frameContentVisual.Brush as CompositionSurfaceBrush)?.UpdateSurfaceBrushOptions(Stretch,
                            AlignX, AlignY, _alignXAnimation, _alignYAnimation);
                    }
                }
                else
                {
                    // Load the Source to the ImageSurface
                    ScheduleNextLoad();
                }
            }
            else
            {
                // If the frameContentVisual had any previous brush, fade it out
                if (_imageSurface == null)
                {
                    // Make the frameVisualContent transparent
                    _frameContentVisual.Brush = _compositor.CreateColorBrush(Colors.Transparent);
                    DisplayPlaceHolder();
                    _engineState = ImageEngineState.Idle;
                }
            }

            // Handle shadow
            if (DisplayShadow)
            {
                // If OptimizeShadow is True then use the sharedShadow otherwise use the instance shadow
                var shadow = OptimizeShadow
                             ? ShadowProvider.GetSharedShadow(_compositor) 
                             : (_shadow ?? (_shadow = _compositor.CreateDropShadow()));

                shadow.BlurRadius = ShadowBlurRadius.Single();
                shadow.Color = ShadowColor;
                shadow.Offset = new Vector3(ShadowOffsetX.Single(), ShadowOffsetY.Single(), 0);
                shadow.Opacity = ShadowOpacity.Single();
                shadow.Mask = _layerEffectBrush.GetSourceParameter("mask");

                _shadowVisual.Shadow = shadow;
            }
            else
            {
                _shadowVisual.Shadow = null;
            }

            return base.ArrangeOverride(finalSize);
        }