aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Tango.AnimatedGif/AnimationCache.cs
blob: b9eaf189a4a44c6037437e4535900ca408a4f67f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
using System;
using System.Collections.Generic;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;

namespace Tango.AnimatedGif
{
    static class AnimationCache
    {
        private class CacheKey
        {
            private readonly ImageSource _source;
            private readonly RepeatBehavior _repeatBehavior;

            public CacheKey(ImageSource source, RepeatBehavior repeatBehavior)
            {
                _source = source;
                _repeatBehavior = repeatBehavior;
            }

            private bool Equals(CacheKey other)
            {
                return ImageEquals(_source, other._source)
                    && Equals(_repeatBehavior, other._repeatBehavior);
            }

            public override bool Equals(object obj)
            {
                if (ReferenceEquals(null, obj)) return false;
                if (ReferenceEquals(this, obj)) return true;
                if (obj.GetType() != this.GetType()) return false;
                return Equals((CacheKey)obj);
            }

            public override int GetHashCode()
            {
                unchecked
                {
                    return (ImageGetHashCode(_source) * 397) ^ _repeatBehavior.GetHashCode();
                }
            }

            private static int ImageGetHashCode(ImageSource image)
            {
                if (image != null)
                {
                    var uri = GetUri(image);
                    if (uri != null)
                        return uri.GetHashCode();
                }
                return 0;
            }

            private static bool ImageEquals(ImageSource x, ImageSource y)
            {
                if (Equals(x, y))
                    return true;
                if ((x == null) != (y == null))
                    return false;
                // They can't both be null or Equals would have returned true
                // and if any is null, the previous would have detected it
                // ReSharper disable PossibleNullReferenceException
                if (x.GetType() != y.GetType())
                    return false;
                // ReSharper restore PossibleNullReferenceException
                var xUri = GetUri(x);
                var yUri = GetUri(y);
                return xUri != null && xUri == yUri;
            }

            private static Uri GetUri(ImageSource image)
            {
                var bmp = image as BitmapImage;
                if (bmp != null && bmp.UriSource != null)
                {
                    if (bmp.UriSource.IsAbsoluteUri)
                        return bmp.UriSource;
                    if (bmp.BaseUri != null)
                        return new Uri(bmp.BaseUri, bmp.UriSource);
                }
                var frame = image as BitmapFrame;
                if (frame != null)
                {
                    string s = frame.ToString();
                    if (s != frame.GetType().FullName)
                    {
                        Uri fUri;
                        if (Uri.TryCreate(s, UriKind.RelativeOrAbsolute, out fUri))
                        {
                            if (fUri.IsAbsoluteUri)
                                return fUri;
                            if (frame.BaseUri != null)
                                return new Uri(frame.BaseUri, fUri);
                        }
                    }
                }
                return null;
            }
        }

        private static readonly Dictionary<CacheKey, ObjectAnimationUsingKeyFrames> _animationCache = new Dictionary<CacheKey, ObjectAnimationUsingKeyFrames>();
        private static readonly Dictionary<CacheKey, int> _referenceCount = new Dictionary<CacheKey, int>();

        public static void IncrementReferenceCount(ImageSource source, RepeatBehavior repeatBehavior)
        {
            var cacheKey = new CacheKey(source, repeatBehavior);
            int count;
            _referenceCount.TryGetValue(cacheKey, out count);
            count++;
            _referenceCount[cacheKey] = count;
        }

        public static void DecrementReferenceCount(ImageSource source, RepeatBehavior repeatBehavior)
        {
            var cacheKey = new CacheKey(source, repeatBehavior);
            int count;
            _referenceCount.TryGetValue(cacheKey, out count);
            if (count > 0)
            {
                count--;
                _referenceCount[cacheKey] = count;
            }
            if (count == 0)
            {
                _animationCache.Remove(cacheKey);
                _referenceCount.Remove(cacheKey);
            }
        }

        public static void AddAnimation(ImageSource source, RepeatBehavior repeatBehavior, ObjectAnimationUsingKeyFrames animation)
        {
            var key = new CacheKey(source, repeatBehavior);
            _animationCache[key] = animation;
        }

        public static void RemoveAnimation(ImageSource source, RepeatBehavior repeatBehavior, ObjectAnimationUsingKeyFrames animation)
        {
            var key = new CacheKey(source, repeatBehavior);
            _animationCache.Remove(key);
        }

        public static ObjectAnimationUsingKeyFrames GetAnimation(ImageSource source, RepeatBehavior repeatBehavior)
        {
            var key = new CacheKey(source, repeatBehavior);
            ObjectAnimationUsingKeyFrames animation;
            _animationCache.TryGetValue(key, out animation);
            return animation;
        }
    }
}