faa193c746d62080ad73f02e377a04811072382d
[WebKit-https.git] / WebCore / ksvg2 / svg / SVGAnimateColorElement.cpp
1 /*
2     Copyright (C) 2004, 2005 Nikolas Zimmermann <wildfox@kde.org>
3                   2004, 2005 Rob Buis <buis@kde.org>
4
5     This file is part of the KDE project
6
7     This library is free software; you can redistribute it and/or
8     modify it under the terms of the GNU Library General Public
9     License as published by the Free Software Foundation; either
10     version 2 of the License, or (at your option) any later version.
11
12     This library is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15     Library General Public License for more details.
16
17     You should have received a copy of the GNU Library General Public License
18     along with this library; see the file COPYING.LIB.  If not, write to
19     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20     Boston, MA 02111-1307, USA.
21 */
22
23 #include "config.h"
24 #ifdef SVG_SUPPORT
25
26 #include "SVGColor.h"
27 #include "SVGAnimateColorElement.h"
28 #include "KSVGTimeScheduler.h"
29 #include "PlatformString.h"
30 #include "Document.h"
31 #include "SVGDocumentExtensions.h"
32 #include "SVGSVGElement.h"
33 #include <math.h>
34
35 namespace WebCore {
36
37 SVGAnimateColorElement::SVGAnimateColorElement(const QualifiedName& tagName, Document *doc)
38     : SVGAnimationElement(tagName, doc)
39     , m_toColor(new SVGColor())
40     , m_fromColor(new SVGColor())
41     , m_currentItem(-1)
42     , m_redDiff(0)
43     , m_greenDiff(0)
44     , m_blueDiff(0)
45 {
46 }
47
48 SVGAnimateColorElement::~SVGAnimateColorElement()
49 {
50 }
51
52 void SVGAnimateColorElement::handleTimerEvent(double timePercentage)
53 {
54     // Start condition.
55     if (!m_connected) {
56         // Save initial color... (needed for fill="remove" or additve="sum")
57         RefPtr<SVGColor> temp = new SVGColor();
58         temp->setRGBColor(targetAttribute());
59
60         m_initialColor = temp->color();
61
62         // Animation mode handling
63         switch(detectAnimationMode())
64         {
65             case TO_ANIMATION:
66             case FROM_TO_ANIMATION:
67             {
68                 String toColorString(m_to);
69                 m_toColor->setRGBColor(toColorString);
70     
71                 String fromColorString;
72                 if (!m_from.isEmpty()) // from-to animation
73                     fromColorString = m_from;
74                 else // to animation
75                     fromColorString = m_initialColor.name();
76     
77                 m_fromColor->setRGBColor(fromColorString);    
78
79                 // Calculate color differences, once.
80                 Color qTo = m_toColor->color();
81                 Color qFrom = m_fromColor->color();
82     
83                 m_redDiff = qTo.red() - qFrom.red();
84                 m_greenDiff = qTo.green() - qFrom.green();
85                 m_blueDiff = qTo.blue() - qFrom.blue();
86                 
87                 break;
88             }
89             case BY_ANIMATION:
90             case FROM_BY_ANIMATION:
91             {
92                 String byColorString(m_by);
93                 m_toColor->setRGBColor(byColorString);
94
95                 String fromColorString;
96             
97                 if (!m_from.isEmpty()) // from-by animation
98                     fromColorString = m_from;
99                 else // by animation
100                     fromColorString = m_initialColor.name();
101
102                 m_fromColor->setRGBColor(fromColorString);
103
104                 Color qBy = m_toColor->color();
105                 Color qFrom = m_fromColor->color();
106
107                 // Calculate 'm_toColor' using relative values
108                 int r = qFrom.red() + qBy.red();
109                 int g = qFrom.green() + qBy.green();
110                 int b = qFrom.blue() + qBy.blue();
111
112                 Color qTo = clampColor(r, g, b);
113             
114                 String toColorString(qTo.name());
115                 m_toColor->setRGBColor(toColorString);
116             
117                 m_redDiff = qTo.red() - qFrom.red();
118                 m_greenDiff = qTo.green() - qFrom.green();
119                 m_blueDiff = qTo.blue() - qFrom.blue();
120
121                 break;
122             }
123             case VALUES_ANIMATION:
124                 break;
125             default:
126             {
127                 //kdError() << k_funcinfo << " Unable to detect animation mode! Aborting creation!" << endl;
128                 return;
129             }
130         }
131
132         ownerSVGElement()->timeScheduler()->connectIntervalTimer(this);
133         m_connected = true;
134
135         return;
136     }
137
138     // Calculations...
139     if (timePercentage >= 1.0)
140         timePercentage = 1.0;
141
142     int r = 0, g = 0, b = 0;
143     if ((m_redDiff != 0 || m_greenDiff != 0 || m_blueDiff != 0) && !m_values)
144         calculateColor(timePercentage, r, g, b);
145     else if (m_values) {
146         int itemByPercentage = calculateCurrentValueItem(timePercentage);
147
148         if (itemByPercentage == -1)
149             return;
150
151         if (m_currentItem != itemByPercentage) // Item changed...
152         {
153             ExceptionCode ec = 0;
154
155             // Extract current 'from' / 'to' values
156             String value1 = String(m_values->getItem(itemByPercentage, ec));
157             String value2 = String(m_values->getItem(itemByPercentage + 1, ec));
158
159             // Calculate r/g/b shifting values...
160             if (!value1.isEmpty() && !value2.isEmpty()) {
161                 bool apply = false;
162                 if (m_redDiff != 0 || m_greenDiff != 0 || m_blueDiff != 0) {
163                     r = m_toColor->color().red();
164                     g = m_toColor->color().green();
165                     b = m_toColor->color().blue();
166
167                     apply = true;
168                 }
169
170                 String toColorString(value2);
171                 m_toColor->setRGBColor(toColorString);
172     
173                 String fromColorString(value1);
174                 m_fromColor->setRGBColor(fromColorString);    
175
176                 Color qTo = m_toColor->color();
177                 Color qFrom = m_fromColor->color();
178
179                 m_redDiff = qTo.red() - qFrom.red();
180                 m_greenDiff = qTo.green() - qFrom.green();
181                 m_blueDiff = qTo.blue() - qFrom.blue();
182
183                 m_currentItem = itemByPercentage;
184
185                 if (!apply)
186                     return;
187             }
188         }
189         else if (m_redDiff != 0 || m_greenDiff != 0 || m_blueDiff != 0)
190         {
191             double relativeTime = calculateRelativeTimePercentage(timePercentage, m_currentItem);
192             calculateColor(relativeTime, r, g, b);
193         }
194     }
195     
196     if (!isFrozen() && timePercentage == 1.0)
197     {
198         r = m_initialColor.red();
199         g = m_initialColor.green();
200         b = m_initialColor.blue();
201     }
202
203     if (isAccumulated() && repeations() != 0.0)
204     {
205         r += m_lastColor.red();
206         g += m_lastColor.green();
207         b += m_lastColor.blue();
208     }
209
210     // Commit changes!
211     m_currentColor = clampColor(r, g, b);
212     
213     // End condition.
214     if (timePercentage == 1.0) {
215         if ((m_repeatCount > 0 && m_repeations < m_repeatCount - 1) || isIndefinite(m_repeatCount)) {
216             m_lastColor = m_currentColor;
217             m_repeations++;
218             return;
219         }
220
221         ownerSVGElement()->timeScheduler()->disconnectIntervalTimer(this);
222         m_connected = false;
223
224         // Reset...
225         m_currentItem = -1;
226
227         m_redDiff = 0;
228         m_greenDiff = 0;
229         m_blueDiff = 0;
230     }
231 }
232
233 Color SVGAnimateColorElement::clampColor(int r, int g, int b) const
234 {
235     if (r > 255)
236         r = 255;
237     else if (r < 0)
238         r = 0;
239
240     if (g > 255)
241         g = 255;
242     else if (g < 0)
243         g = 0;
244
245     if (b > 255)
246         b = 255;
247     else if (b < 0)
248         b = 0;
249
250     return Color(r, g, b);
251 }
252
253 void SVGAnimateColorElement::calculateColor(double time, int &r, int &g, int &b) const
254 {
255     r = lround(m_redDiff * time) + m_fromColor->color().red();
256     g = lround(m_greenDiff * time) + m_fromColor->color().green();
257     b = lround(m_blueDiff * time) + m_fromColor->color().blue();
258 }
259
260 Color SVGAnimateColorElement::color() const
261 {
262     return m_currentColor;
263 }
264
265 Color SVGAnimateColorElement::initialColor() const
266 {
267     return m_initialColor;
268 }
269
270 }
271
272 // vim:ts=4:noet
273 #endif // SVG_SUPPORT
274