Source Code Cross Referenced for AbstractAnimate.java in  » 6.0-JDK-Modules » j2me » com » sun » perseus » model » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Modules » j2me » com.sun.perseus.model 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         *
0003:         *
0004:         * Copyright  1990-2007 Sun Microsystems, Inc. All Rights Reserved.
0005:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
0006:         * 
0007:         * This program is free software; you can redistribute it and/or
0008:         * modify it under the terms of the GNU General Public License version
0009:         * 2 only, as published by the Free Software Foundation.
0010:         * 
0011:         * This program is distributed in the hope that it will be useful, but
0012:         * WITHOUT ANY WARRANTY; without even the implied warranty of
0013:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014:         * General Public License version 2 for more details (a copy is
0015:         * included at /legal/license.txt).
0016:         * 
0017:         * You should have received a copy of the GNU General Public License
0018:         * version 2 along with this work; if not, write to the Free Software
0019:         * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020:         * 02110-1301 USA
0021:         * 
0022:         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0023:         * Clara, CA 95054 or visit www.sun.com if you need additional
0024:         * information or have any questions.
0025:         */
0026:
0027:        package com.sun.perseus.model;
0028:
0029:        import com.sun.perseus.util.SimpleTokenizer;
0030:        import com.sun.perseus.util.SVGConstants;
0031:
0032:        import org.w3c.dom.DOMException;
0033:
0034:        import java.util.Vector;
0035:
0036:        /**
0037:         * <code>AbstractAnimate</code> is used as a base class for various
0038:         * animation classes (see <code>Animate</code> and <code>AnimateMotion</code>).
0039:         *
0040:         * @version $Id: AbstractAnimate.java,v 1.5 2006/06/29 10:47:28 ln156897 Exp $
0041:         */
0042:        public abstract class AbstractAnimate extends Animation {
0043:            /**
0044:             * calcMode value for linear interpolation.
0045:             */
0046:            public static final int CALC_MODE_LINEAR = 1;
0047:
0048:            /**
0049:             * calcMode value for discrete interpolation
0050:             */
0051:            public static final int CALC_MODE_DISCRETE = 2;
0052:
0053:            /**
0054:             * calcMode value for paced interpolation.
0055:             */
0056:            public static final int CALC_MODE_PACED = 3;
0057:
0058:            /**
0059:             * calcMode for spline interpolation.
0060:             */
0061:            public static final int CALC_MODE_SPLINE = 4;
0062:
0063:            /**
0064:             * Minimum required flatness for keySpline approximations by 
0065:             * polylines.
0066:             */
0067:            public static final float MIN_FLATNESS_SQUARE = 0.01f * 0.01f;
0068:
0069:            /**
0070:             * End value specification
0071:             */
0072:            String to;
0073:
0074:            /**
0075:             * Starting value specification.
0076:             */
0077:            String from;
0078:
0079:            /**
0080:             * Intermediate value specification.
0081:             */
0082:            String by;
0083:
0084:            /**
0085:             * Complete values specification list.
0086:             */
0087:            String values;
0088:
0089:            /**
0090:             * The interpolation mode, one of the CALC_MODE_XYZ values.
0091:             */
0092:            int calcMode = CALC_MODE_LINEAR;
0093:
0094:            /**
0095:             * The actual calcMode. For types which do not support interpolation,
0096:             * the calcMode is forced to be discrete.
0097:             */
0098:            int actualCalcMode = CALC_MODE_DISCRETE;
0099:
0100:            /**
0101:             * Key times, to control the animation pace. May be null or a list of
0102:             * values between 0 and 1.
0103:             * @see <a
0104:             * href="http://www.w3.org/TR/smil20/smil-timing.html#animation-adef-keyTimes>SMIL
0105:             * 2.0 Specification</a>
0106:             */
0107:            float[] keyTimes;
0108:
0109:            /**
0110:             * Key splines, used to control the speed of animation on a particular
0111:             * time interval (interval pacing).
0112:             *
0113:             * May be null or an array of arrays of 4 floating point values.
0114:             * @see <a
0115:             * href="http://www.w3.org/TR/smil20/smil-timing.html#animation-animationNS-InterpolationKeysplines"/>SMIL
0116:             * 2.0 Specification</a>
0117:             */
0118:            float[][] keySplines;
0119:
0120:            /**
0121:             * refSplines is an array of points which define a linear approximation of
0122:             * the keySplines. refSplines is computed in the validate() method and 
0123:             * used in the curve() method. There is one float array per keySpline.
0124:             */
0125:            float[][][] refSplines;
0126:
0127:            /**
0128:             * Controls whether the animation is additive or not. True maps to the 
0129:             * SVG 'sum' value and false maps to the SVG 'replace' value.
0130:             */
0131:            boolean additive;
0132:
0133:            /**
0134:             * Controls whether the animation has a cumulative behavior or not. This
0135:             * covers the behavior over multiple iterations of the simple duration.
0136:             */
0137:            boolean accumulate;
0138:
0139:            /**
0140:             * The RefValues corresponding to this &lt;set&gt; element. A &lt;set&gt;
0141:             * element has a single segment with the same begin and end value.
0142:             */
0143:            RefValues refValues = null;
0144:
0145:            /**
0146:             * Used, temporarily, to hold the refValues for the to attribute.
0147:             */
0148:            RefValues toRefValues;
0149:
0150:            /**
0151:             * Used, temporarily, to hold the refValues for the from attribute.
0152:             */
0153:            RefValues fromRefValues;
0154:
0155:            /**
0156:             * Used, temporarily, to hold the refValues for the by attribute.
0157:             */
0158:            RefValues byRefValues;
0159:
0160:            /**
0161:             * Used, temporarily, to hold the refValues for the values attribute.
0162:             */
0163:            RefValues valuesRefValues;
0164:
0165:            /**
0166:             * refTimes holds key times for the animation.
0167:             *
0168:             * refTimes is computed in the validate method.
0169:             *
0170:             * refTimes holds the key times for the <em>begining</em> of each segment.
0171:             * Therefore, there is as many refTimes as there are segments, in all cases.
0172:             *
0173:             * @see #validate
0174:             */
0175:            float[] refTimes;
0176:
0177:            /**
0178:             * A working buffer for mapping segment index and progress
0179:             */
0180:            float[] sisp = { 0, 0 };
0181:
0182:            /**
0183:             * Simple flag to check if we are dealing with a to-animation or
0184:             * not. This flag is needed to control the addition and cumulative
0185:             * behavior on to-animations, which is different than that on other
0186:             * animations (e.g., a values or a from-to animation).
0187:             */
0188:            boolean isToAnimation;
0189:
0190:            /**
0191:             * Builds a new Animate element that belongs to the given
0192:             * document. This <code>Animate</code> will belong 
0193:             * to the <code>DocumentNode</code>'s time container.
0194:             *
0195:             * @param ownerDocument the document this node belongs to.
0196:             * @param localName the animation element's local name.
0197:             * @throws IllegalArgumentException if the input ownerDocument is null
0198:             */
0199:            public AbstractAnimate(final DocumentNode ownerDocument,
0200:                    final String localName) {
0201:                super (ownerDocument, localName);
0202:            }
0203:
0204:            /**
0205:             * This is the Animate element's animation function. 
0206:             *
0207:             * f(t) {
0208:             *     a. Compute the 'simple duration penetration' p
0209:             *       p = t / dur
0210:             *       where dur is the simple duration.
0211:             *
0212:             *     b. Compute the 'current time segment' i
0213:             *        refTimes[i] <= p < refTimes[i+1]
0214:             *
0215:             *     c. Compute the 'segment penetration' sp
0216:             *        sp = (p - refTimes[i]) 
0217:             *             / 
0218:             *             (refTimes[i+1] - refTimes[i])
0219:             *        Note: 0 <= sp <= 1
0220:             *
0221:             *     d. Compute the 'interpolated interval 
0222:             *        penetration'  isp
0223:             *
0224:             *        isp = calcMode(sp)
0225:             *        Note: 0 <= isp <= 1
0226:             *
0227:             *     e. Compute the animated value:
0228:             *        v = refValues.compute(isp)
0229:             *        v has the same number of components as refValues.
0230:             * }
0231:             *
0232:             * @param t the animation's simple time.
0233:             */
0234:            Object[] f(final long t) {
0235:                // a. Compute the simple duration penetration p
0236:
0237:                // See: http://www.w3.org/TR/smil20/smil-timing.html#animation-animationNS-InterpolationAndIndefSimpleDur
0238:                float p = 0;
0239:                if (timedElementSupport.simpleDur != null
0240:                        && timedElementSupport.simpleDur.isResolved()) {
0241:                    p = t / (float) timedElementSupport.simpleDur.value;
0242:                }
0243:
0244:                // Iterate for each component.
0245:                int nc = refValues.getComponents();
0246:                float sp = 0;
0247:                int si = 0;
0248:                float endTime = 1;
0249:                float beginTime = 0;
0250:                int i = 0;
0251:
0252:                // b. Compute the 'current time segment' index si[ci] 
0253:
0254:                // We iterate from 1 because the first value in refTimes
0255:                // is always 0. 
0256:                for (i = 1; i < refTimes.length; i++) {
0257:                    if (p < refTimes[i]) {
0258:                        endTime = refTimes[i];
0259:                        break;
0260:                    }
0261:                    beginTime = refTimes[i];
0262:                }
0263:
0264:                si = i - 1;
0265:
0266:                // c. Compute the segment penetration
0267:                if (endTime == beginTime) {
0268:                    sp = 1;
0269:                } else {
0270:                    sp = (p - beginTime) / (endTime - beginTime);
0271:                }
0272:
0273:                // d. Compute the 'interpolated segment penetration'
0274:                sp = calcMode(sp, si);
0275:
0276:                // At this point, we have computed:
0277:                // a. the array of time segment indices corresponding to 't'
0278:                // b. the array of penetration into the time segments. 
0279:                //
0280:                // The following call lets the animate implementation map 
0281:                // the time segment indices and the time segment penetration
0282:                // into refValues indices and penetration, in case these are
0283:                // different. Typically, these are the same, but they may be
0284:                // different, for example in the case of animateMotion with
0285:                // keyPoints.
0286:                sisp[0] = si;
0287:                sisp[1] = sp;
0288:                mapToSegmentProgress(si, sp, sisp);
0289:                si = (int) sisp[0];
0290:                sp = sisp[1];
0291:
0292:                // If we are dealing with a to-animation, we need to get the
0293:                // value for the single segment's start value.
0294:                if (isToAnimation) {
0295:                    Object[] baseValue = baseVal.getBaseValue();
0296:                    refValues.getSegment(0).setStart(baseValue);
0297:                    return refValues.compute(si, sp);
0298:                }
0299:
0300:                // The reminder of this method is for non-additive animations
0301:
0302:                // Compute the simple function value
0303:                Object[] v = refValues.compute(si, sp);
0304:
0305:                // Account for cumulative behavior.
0306:                if (!isToAnimation && accumulate
0307:                        && timedElementSupport.curIter > 0) {
0308:                    // Last simple time value, lv
0309:                    Object[] lv = refValues.getSegment(
0310:                            refValues.getSegments() - 1).getEnd();
0311:                    Object[] r = traitAnim.multiply(lv,
0312:                            timedElementSupport.curIter);
0313:                    v = traitAnim.sum(r, v);
0314:                }
0315:
0316:                // Now, account for additive behavior.
0317:                if (!additive) {
0318:                    return v;
0319:                }
0320:
0321:                return traitAnim.sum(baseVal.getBaseValue(), v);
0322:            }
0323:
0324:            /**
0325:             * The following call lets the animate implementation map 
0326:             * the time segment indices and the time segment penetration
0327:             * into refValues indices and penetration, in case these are
0328:             * different. Typically, these are the same, but they may be
0329:             * different, for example in the case of animateMotion with
0330:             * keyPoints.
0331:             */
0332:            protected void mapToSegmentProgress(final int si, final float sp,
0333:                    final float[] sisp) {
0334:            }
0335:
0336:            /**
0337:             * Intepolates the input value depending on the calcMode attribute
0338:             * and, in the case of spline interpolation, depending on the
0339:             * keySplines value.
0340:             *
0341:             * @param p the value to interpolate. Should be in the [0, 1] range.
0342:             * @param si the time segment from which the computation is done. This
0343:             *        is needed to identify the correct keySplines to use in 
0344:             *        case of spline animations.
0345:             */
0346:            float calcMode(final float p, final int si) {
0347:                switch (actualCalcMode) {
0348:                case CALC_MODE_DISCRETE:
0349:                    return 0;
0350:                case CALC_MODE_LINEAR:
0351:                    // Linear does not modify the current penetration
0352:                    // because we are on an x = y line.
0353:                case CALC_MODE_PACED:
0354:                    // Paced does not modify the current penetration
0355:                    // because we have computed the time intervals 
0356:                    // so as to have constant velocity. There is no
0357:                    // further interpolation in this method.
0358:                    return p;
0359:                case CALC_MODE_SPLINE:
0360:                default:
0361:                    return curve(p, refSplines[si]);
0362:                }
0363:            }
0364:
0365:            /**
0366:             * Computes an array of points which do a linear approximation of the 
0367:             * input splines.
0368:             *
0369:             * @param splines the array of splines to approximate with a polyline.
0370:             *        The splines array should be an made of four element floats.
0371:             *        if any of the elements is null, a NullPointerException will
0372:             *        be thrown. If any of the element has a length less than four,
0373:             *        an ArrayIndexOutOfBoundsException will be thrown.
0374:             * @return an array of point arrays. Each point array is a polyline
0375:             *         approximation of the input spline.
0376:             */
0377:            static float[][][] toRefSplines(final float[][] splines) {
0378:                float[][][] rSplines = new float[splines.length][][];
0379:
0380:                float[][] splineDef = new float[4][2];
0381:                for (int i = 0; i < splines.length; i++) {
0382:                    Vector v = new Vector();
0383:                    v.addElement(new float[] { 0, 0 });
0384:                    splineDef[0][0] = 0;
0385:                    splineDef[0][1] = 0;
0386:                    splineDef[1][0] = splines[i][0];
0387:                    splineDef[1][1] = splines[i][1];
0388:                    splineDef[2][0] = splines[i][2];
0389:                    splineDef[2][1] = splines[i][3];
0390:                    splineDef[3][0] = 1;
0391:                    splineDef[3][1] = 1;
0392:                    toRefSpline(splineDef, v);
0393:                    float[][] polyline = new float[v.size()][];
0394:                    v.copyInto(polyline);
0395:                    rSplines[i] = polyline;
0396:                }
0397:
0398:                return rSplines;
0399:            }
0400:
0401:            /**
0402:             * Converts the input spline curve (defined by its four control points)
0403:             * into a polyline approximation (i.e., an array of points). If the curve
0404:             * is flat enough (see the <code>isFlat</code> method), then the curve is
0405:             * approximated to a line between its two end control points and the
0406:             * last control point is added to the input <code>segment</code> vector. 
0407:             * If the curve is not flat enough, then it is sub-divided and the 
0408:             * subdivided curves are, recursively, tested for flatness.
0409:             *
0410:             * The flatness used for flatness test is controlled by the 
0411:             * <code>MIN_FLATNESS_SQUARE</code> constant.
0412:             * 
0413:             * @param curve the spline curve to approximate. Should not be null. Should
0414:             *        be an array of four arrays of two elements. If there are less than
0415:             *        four arrays or if there are less than two elements in these arrays
0416:             *        then an ArrayIndexOutOfBoundsException is thrown. If any element
0417:             *        in the curve array is null, a NullPointerException is thrown.
0418:             * @param segments the vector to which polyline points should be added. 
0419:             *        Should not be null.
0420:             */
0421:            static void toRefSpline(final float[][] curve, final Vector segments) {
0422:                if (isFlat(curve, MIN_FLATNESS_SQUARE)) {
0423:                    segments
0424:                            .addElement(new float[] { curve[3][0], curve[3][1] });
0425:                    return;
0426:                }
0427:
0428:                float[][] lcurve = new float[4][2];
0429:                float[][] rcurve = new float[4][2];
0430:
0431:                // L1 = P1
0432:                lcurve[0] = curve[0];
0433:
0434:                // L2 = (P1 + P2) / 2
0435:                lcurve[1][0] = (curve[0][0] + curve[1][0]) / 2;
0436:                lcurve[1][1] = (curve[0][1] + curve[1][1]) / 2;
0437:
0438:                // H = (P2 + P3) / 2
0439:                float[] h = new float[2];
0440:                h[0] = (curve[1][0] + curve[2][0]) / 2;
0441:                h[1] = (curve[1][1] + curve[2][1]) / 2;
0442:
0443:                // L3 = (L2 + H) / 2
0444:                lcurve[2][0] = (lcurve[1][0] + h[0]) / 2;
0445:                lcurve[2][1] = (lcurve[1][1] + h[1]) / 2;
0446:
0447:                // R3 = (P3 + P4) / 2
0448:                rcurve[2][0] = (curve[2][0] + curve[3][0]) / 2;
0449:                rcurve[2][1] = (curve[2][1] + curve[3][1]) / 2;
0450:
0451:                // R2 = (H + R3) / 2
0452:                rcurve[1][0] = (h[0] + rcurve[2][0]) / 2;
0453:                rcurve[1][1] = (h[1] + rcurve[2][1]) / 2;
0454:
0455:                // L4 = R1 = (L3 + R2) / 2
0456:                lcurve[3][0] = (lcurve[2][0] + rcurve[1][0]) / 2;
0457:                lcurve[3][1] = (lcurve[2][1] + rcurve[1][1]) / 2;
0458:                rcurve[0] = lcurve[3];
0459:
0460:                // R4 = P4
0461:                rcurve[3] = curve[3];
0462:
0463:                toRefSpline(lcurve, segments);
0464:                toRefSpline(rcurve, segments);
0465:            }
0466:
0467:            /**
0468:             * @param curve the spline curve to test for flatness. The curve is 
0469:             *        considered flat if the distance from the two intermediate control
0470:             *        points from the line between the first and the last control points
0471:             *        is less than the desired flatness maximum. The input array must 
0472:             *        have at least four elements and each one must be at least 
0473:             *        2 elements long. If not, an ArrayOutOfBoundsException is thrown. 
0474:             *        The curve array should not be null.
0475:             * @param flatness. The maximum distance allowed for the intermediate curve
0476:             *        control points.
0477:             */
0478:            static boolean isFlat(float[][] curve, float flatness) {
0479:                // Compute the square distance of P2 and P3 to the (P1, P4) line.
0480:                float dx = curve[3][0] - curve[0][0];
0481:                float dy = curve[3][1] - curve[0][1];
0482:                float div = dx * dx + dy * dy;
0483:
0484:                if (div == 0) {
0485:                    return true;
0486:                }
0487:
0488:                float den = (dx * (curve[1][1] - curve[0][1]) - dy
0489:                        * (curve[1][0] - curve[0][0]));
0490:
0491:                float dP2Sq = (den * den) / div;
0492:
0493:                den = (dx * (curve[2][1] - curve[0][1]) - dy
0494:                        * (curve[2][0] - curve[0][0]));
0495:
0496:                float dP3Sq = (den * den) / div;
0497:
0498:                return (dP2Sq <= flatness && dP3Sq <= flatness);
0499:
0500:            }
0501:
0502:            /**
0503:             * Computes the curve value for the requested value on the specified
0504:             * curves, defined by a polyline approximation.
0505:             *
0506:             * The method assumes that the input polyline points are between 0 and 1 and
0507:             * in increasing order along the x axis. The method considers the p value to
0508:             * be on the polyline's x-axis and finds the two points between which it 
0509:             * lies and returns a linear approximation for that segment.
0510:             *
0511:             * For degenerate cases (e.g., if the polyline x-axis values are not in the
0512:             * [0, 1] interval or if p is not in the [0, 1] interval either), the method
0513:             * returns 0 if the input penetration p is less than the first polyline 
0514:             * point. The method returns 1 if the input penetration is more than the 
0515:             * last polyline x-axis coordinate.
0516:             *
0517:             * @param p the value for which the curve polynomial should be computed.
0518:             * @param polyline the polyline curve approximation. Should not be null.
0519:             *        each element in the polyline array should not be null. Each
0520:             *        element in the array should be at least of length 2.
0521:             */
0522:            static float curve(final float p, final float[][] polyline) {
0523:                int i = 0;
0524:                for (; i < polyline.length; i++) {
0525:                    if (p < polyline[i][0]) {
0526:                        break;
0527:                    }
0528:                }
0529:
0530:                if (i == polyline.length || i == 0) {
0531:                    // Degenerate cases.
0532:                    //
0533:                    // This should never happen:
0534:                    //
0535:                    // Should not be polyline.length because the last entry in polyline
0536:                    // should be '1' and the maximum input value for p should be '1'.
0537:                    //
0538:                    // Should not get 0 because the first entry should be zero and the
0539:                    // input parameter should be greater or equal to zero.
0540:                    // 
0541:                    return i / (float) polyline.length; // returns 0 for 0 and 1 for 1
0542:                }
0543:
0544:                float[] from = polyline[i - 1];
0545:                float[] to = polyline[i];
0546:
0547:                // Compute the progress between from and to:
0548:                //
0549:                // p = (1 - t) * from[0] + t.to[0]
0550:                // p = t * (t[0] - from[0]) + from[0]
0551:                // t = (p - from[0]) / (to[0] - from[0])
0552:                //
0553:                // So, the interpolated progress is:
0554:                //
0555:                // ip = (1 - t) * from[1] + t.to[1]
0556:                // ip = (1 - (p - from[0]) / (to[0] - from[0])) * from[1] 
0557:                //      + ((p - from[0]) / (to[0] - from[0])) * to[1]
0558:                // ip = ((to[0] - from[0] - p + from[0]) / (to[0] - from[0])) * from[1]
0559:                //      + (to[1] * p - to[1] * from[0]) / (to[0] - from[0])
0560:                // ip = ((to[0] - p) / (to[0] - from[0]) * from[1] 
0561:                //      + (to[1] * p - to[1] * from[0]) / (to[0] - from[0])
0562:                // ip = (to[0] * from[1] - p * from[1]) / (to[0] - from[0]) 
0563:                //      + (to[1] * p - to[1] * from[0]) / (to[0] - from[0])
0564:                // ip = (to[0] * from[1] - p * from[1] + to[1] * p - to[1] * from[0]) 
0565:                //      / (to[0] - from[0])
0566:                // ip = (to[0] * from[1] - to[1] * from[0] + p * (to[1] - from[1])) 
0567:                //      / (to[0] - from[0])
0568:                return (to[0] * from[1] - to[1] * from[0] + p
0569:                        * (to[1] - from[1]))
0570:                        / (to[0] - from[0]);
0571:            }
0572:
0573:            /**
0574:             * Supported traits: to, attributeName
0575:             *
0576:             * @param traitName the name of the trait which the element may support.
0577:             * @return true if this element supports the given trait in one of the
0578:             *         trait accessor methods.
0579:             */
0580:            boolean supportsTrait(final String traitName) {
0581:                if (SVGConstants.SVG_TO_ATTRIBUTE == traitName
0582:                        || SVGConstants.SVG_FROM_ATTRIBUTE == traitName
0583:                        || SVGConstants.SVG_BY_ATTRIBUTE == traitName
0584:                        || SVGConstants.SVG_VALUES_ATTRIBUTE == traitName
0585:                        || SVGConstants.SVG_CALC_MODE_ATTRIBUTE == traitName
0586:                        || SVGConstants.SVG_KEY_TIMES_ATTRIBUTE == traitName
0587:                        || SVGConstants.SVG_KEY_SPLINES_ATTRIBUTE == traitName
0588:                        || SVGConstants.SVG_ADDITIVE_ATTRIBUTE == traitName
0589:                        || SVGConstants.SVG_ACCUMULATE_ATTRIBUTE == traitName) {
0590:                    return true;
0591:                } else {
0592:                    return super .supportsTrait(traitName);
0593:                }
0594:            }
0595:
0596:            // JAVADOC COMMENT ELIDED
0597:            public String getTraitImpl(final String name) throws DOMException {
0598:                if (SVGConstants.SVG_TO_ATTRIBUTE == name) {
0599:                    return to;
0600:                } else if (SVGConstants.SVG_FROM_ATTRIBUTE == name) {
0601:                    return from;
0602:                } else if (SVGConstants.SVG_BY_ATTRIBUTE == name) {
0603:                    return by;
0604:                } else if (SVGConstants.SVG_VALUES_ATTRIBUTE == name) {
0605:                    return values;
0606:                } else if (SVGConstants.SVG_CALC_MODE_ATTRIBUTE == name) {
0607:                    switch (calcMode) {
0608:                    case CALC_MODE_DISCRETE:
0609:                        return SVGConstants.SVG_DISCRETE_VALUE;
0610:                    case CALC_MODE_LINEAR:
0611:                        return SVGConstants.SVG_LINEAR_VALUE;
0612:                    case CALC_MODE_PACED:
0613:                        return SVGConstants.SVG_PACED_VALUE;
0614:                    case CALC_MODE_SPLINE:
0615:                    default:
0616:                        return SVGConstants.SVG_SPLINE_VALUE;
0617:                    }
0618:                } else if (SVGConstants.SVG_KEY_TIMES_ATTRIBUTE == name) {
0619:                    return toStringTrait(keyTimes);
0620:                } else if (SVGConstants.SVG_KEY_SPLINES_ATTRIBUTE == name) {
0621:                    return toStringTrait(keySplines);
0622:                } else if (SVGConstants.SVG_ADDITIVE_ATTRIBUTE == name) {
0623:                    if (additive) {
0624:                        return SVGConstants.SVG_SUM_VALUE;
0625:                    }
0626:                    return SVGConstants.SVG_REPLACE_VALUE;
0627:                } else if (SVGConstants.SVG_ACCUMULATE_ATTRIBUTE == name) {
0628:                    if (accumulate) {
0629:                        return SVGConstants.SVG_SUM_VALUE;
0630:                    }
0631:                    return SVGConstants.SVG_NONE_VALUE;
0632:                } else {
0633:                    return super .getTraitImpl(name);
0634:                }
0635:            }
0636:
0637:            // JAVADOC COMMENT ELIDED
0638:            public void setTraitImpl(final String name, final String value)
0639:                    throws DOMException {
0640:                if (SVGConstants.SVG_TO_ATTRIBUTE == name) {
0641:                    checkWriteLoading(name);
0642:                    to = value;
0643:                } else if (SVGConstants.SVG_FROM_ATTRIBUTE == name) {
0644:                    checkWriteLoading(name);
0645:                    from = value;
0646:                } else if (SVGConstants.SVG_BY_ATTRIBUTE == name) {
0647:                    checkWriteLoading(name);
0648:                    by = value;
0649:                } else if (SVGConstants.SVG_VALUES_ATTRIBUTE == name) {
0650:                    checkWriteLoading(name);
0651:                    values = value;
0652:                } else if (SVGConstants.SVG_KEY_TIMES_ATTRIBUTE == name) {
0653:                    checkWriteLoading(name);
0654:
0655:                    // Generic float array parsing
0656:                    keyTimes = parseFloatArrayTrait(name, value.replace(';',
0657:                            ','));
0658:
0659:                    // Now, check that the keyTimes values are from 0 to 1 and
0660:                    // in increasing order. Note that this only performs the 
0661:                    // validations which can be made prior to a call to validate.
0662:                    if (keyTimes[0] < 0 || keyTimes[0] > 1) {
0663:                        throw illegalTraitValue(name, value);
0664:                    }
0665:
0666:                    for (int i = 1; i < keyTimes.length; i++) {
0667:                        if (keyTimes[i] < 0 || keyTimes[i] > 1) {
0668:                            throw illegalTraitValue(name, value);
0669:                        }
0670:
0671:                        if (keyTimes[i] < keyTimes[i - 1]) {
0672:                            throw illegalTraitValue(name, value);
0673:                        }
0674:                    }
0675:                } else if (SVGConstants.SVG_KEY_SPLINES_ATTRIBUTE == name) {
0676:                    checkWriteLoading(name);
0677:
0678:                    SimpleTokenizer st = new SimpleTokenizer(value, ";");
0679:                    int n = st.countTokens();
0680:                    keySplines = new float[n][];
0681:
0682:                    for (int i = 0; i < n; i++) {
0683:                        String splineDef = st.nextToken();
0684:                        keySplines[i] = parseFloatArrayTrait(name, splineDef);
0685:                        if (keySplines[i].length != 4 || keySplines[i][0] < 0
0686:                                || keySplines[i][0] > 1 || keySplines[i][1] < 0
0687:                                || keySplines[i][1] > 1 || keySplines[i][2] < 0
0688:                                || keySplines[i][2] > 1 || keySplines[i][3] < 0
0689:                                || keySplines[i][3] > 1) {
0690:                            throw illegalTraitValue(name, value);
0691:                        }
0692:                    }
0693:                } else if (SVGConstants.SVG_ADDITIVE_ATTRIBUTE == name) {
0694:                    checkWriteLoading(name);
0695:
0696:                    if (SVGConstants.SVG_REPLACE_VALUE.equals(value)) {
0697:                        additive = false;
0698:                    } else if (SVGConstants.SVG_SUM_VALUE.equals(value)) {
0699:                        additive = true;
0700:                    } else {
0701:                        throw illegalTraitValue(name, value);
0702:                    }
0703:                } else if (SVGConstants.SVG_ACCUMULATE_ATTRIBUTE == name) {
0704:                    checkWriteLoading(name);
0705:
0706:                    if (SVGConstants.SVG_NONE_VALUE.equals(value)) {
0707:                        accumulate = false;
0708:                    } else if (SVGConstants.SVG_SUM_VALUE.equals(value)) {
0709:                        accumulate = true;
0710:                    } else {
0711:                        throw illegalTraitValue(name, value);
0712:                    }
0713:                } else if (SVGConstants.SVG_CALC_MODE_ATTRIBUTE == name) {
0714:                    if (SVGConstants.SVG_DISCRETE_VALUE.equals(value)) {
0715:                        calcMode = CALC_MODE_DISCRETE;
0716:                    } else if (SVGConstants.SVG_LINEAR_VALUE.equals(value)) {
0717:                        calcMode = CALC_MODE_LINEAR;
0718:                    } else if (SVGConstants.SVG_PACED_VALUE.equals(value)) {
0719:                        calcMode = CALC_MODE_PACED;
0720:                    } else if (SVGConstants.SVG_SPLINE_VALUE.equals(value)) {
0721:                        calcMode = CALC_MODE_SPLINE;
0722:                    } else {
0723:                        throw illegalTraitValue(name, value);
0724:                    }
0725:                } else {
0726:                    super .setTraitImpl(name, value);
0727:                }
0728:            }
0729:
0730:            /**
0731:             * Computes refTimes so that each animation segment lasts the same length
0732:             * of time.
0733:             */
0734:            float[] getDefaultTiming(RefValues refValues) {
0735:                int ns = refValues.getSegments();
0736:                float[] refTimes = new float[ns];
0737:                float startTime = 0;
0738:                float segLength = 1 / (float) ns;
0739:                for (int i = 0; i < ns; i++) {
0740:                    refTimes[i] = startTime;
0741:                    startTime += segLength;
0742:                }
0743:
0744:                return refTimes;
0745:            }
0746:
0747:            /**
0748:             * Computes refTimes so that there is a paced speed on each values segment.
0749:             */
0750:            float[] getPacedTiming(RefValues refValues) {
0751:                // a) Compute the refValues length, D
0752:                //    D = sum(from 0 to n; seg(i).length()); 
0753:                //
0754:                // b) Compute the overall paced velocity, V
0755:                //    V = D / dur; 
0756:                //
0757:                // c) For each segment i, compute its refTime:
0758:                //    refTime[j][i] = refTime[j][i-1] + (seg(i).length(j) / V(j)) / dur;
0759:
0760:                float D = refValues.getLength();
0761:
0762:                int ns = refValues.getSegments();
0763:                refTimes = new float[ns];
0764:                float prevRefTime = 0;
0765:
0766:                if (D > 0) {
0767:                    // For each segment index si
0768:                    for (int si = 1; si < ns; si++) {
0769:                        refTimes[si] = prevRefTime
0770:                                + refValues.getLength(si - 1) / D;
0771:                        prevRefTime = refTimes[si];
0772:                    }
0773:                } else {
0774:                    // Segments are all of zero length, they should be evenly spaced
0775:                    // in time.
0776:                    float sl = 1f / ns;
0777:                    for (int si = 1; si < ns; si++) {
0778:                        refTimes[si] = si * sl;
0779:                    }
0780:                }
0781:
0782:                return refTimes;
0783:            }
0784:
0785:            /**
0786:             * Validating an Animate consists in:
0787:             * a) Setting its target element. If there was no idRef, then targetElement
0788:             *    is still null and will be positioned to the parent node.
0789:             * 
0790:             * b) Validating the from, to, by and values traits with the targetElement,
0791:             *    using the target trait name, namespace and value.
0792:             *
0793:             * c) Validating the keyTimes and the keySplines trait values to check they
0794:             *    are compatible with the values specification.
0795:             *
0796:             * @throws DOMException if there is a validation error, for example if the
0797:             *         to value is incompatible with the target trait or if the target
0798:             *         trait is not animatable.
0799:             */
0800:            void validate() throws DOMException {
0801:                // =====================================================================
0802:                // a) Set the target element.
0803:                if (targetElement == null) {
0804:                    targetElement = (ElementNode) parent;
0805:                }
0806:
0807:                // =====================================================================
0808:                // Check that the traitName attribute was specified.
0809:                if (traitName == null) {
0810:                    throw illegalTraitValue(
0811:                            SVGConstants.SVG_ATTRIBUTE_NAME_ATTRIBUTE,
0812:                            traitName);
0813:                }
0814:
0815:                // =====================================================================
0816:                // b) Validate the to/from/by/values traits with the target element.  
0817:
0818:                // Note that traitName should _never_ be null when validate() is 
0819:                // invoked. It is either required (e.g., for Animate) or fixed (e.g., 
0820:                // for AnimateMotion. If, for example in some unit test configutations,
0821:                // this method is called without a specified traitName, the method 
0822:                // generates a NullPointerException.
0823:                traitAnim = targetElement.getSafeTraitAnimNS(traitNamespace,
0824:                        traitName);
0825:
0826:                // If the traitAnim type does not support interpolation, force the 
0827:                // calcMode to be discrete.
0828:                if (traitAnim.supportsInterpolation()) {
0829:                    actualCalcMode = calcMode;
0830:                } else {
0831:                    actualCalcMode = CALC_MODE_DISCRETE;
0832:                }
0833:
0834:                validateValues();
0835:
0836:                // Now, apply precedence rules to compute the actual RefValues.
0837:                selectRefValues();
0838:
0839:                // If the animation has no effect, stop here.
0840:                if (hasNoEffect) {
0841:                    return;
0842:                }
0843:
0844:                // =====================================================================
0845:                // If we are dealing with discrete timing, we need to add a last time
0846:                // segment so that we implement the desired behavior for discrete 
0847:                // timing. With a single interval with start/end values, only the start
0848:                // value will be shown. If we add a new interval with the end value, 
0849:                // then the end value will be shown for the last time interval.
0850:                if (actualCalcMode == CALC_MODE_DISCRETE) {
0851:                    refValues.makeDiscrete();
0852:                }
0853:
0854:                // Initialize the refValues
0855:                refValues.initialize();
0856:
0857:                // =====================================================================
0858:                // c. Validate that keyTimes and keySplines trait values are compatible
0859:                //    with the values specification.
0860:                computeRefTimes();
0861:
0862:                // c.1 Validate that keySplines is compatible with the animation set-up
0863:                //
0864:                // See:
0865:                // http://www.w3.org/TR/2001/REC-smil20-20010807/smil20.html#animation-animationNS-InterpolationKeysplines
0866:                //
0867:                // The attribute is ignored unless the CALC_MODE is spline. For spline
0868:                // interpolation, there must be one fewer sets of control points in the
0869:                // keySplines attribute than there are keyTimes.
0870:                //
0871:                if (actualCalcMode == CALC_MODE_SPLINE) {
0872:                    if (keySplines == null
0873:                            || refTimes.length != keySplines.length) {
0874:                        throw animationError(
0875:                                idRef,
0876:                                traitNamespace,
0877:                                traitName,
0878:                                targetElement.getNamespaceURI(),
0879:                                targetElement.getLocalName(),
0880:                                getId(),
0881:                                getNamespaceURI(),
0882:                                getLocalName(),
0883:                                Messages
0884:                                        .formatMessage(
0885:                                                Messages.ERROR_INVALID_ANIMATION_KEY_SPLINES,
0886:                                                new Object[] {
0887:                                                        getTrait(SVGConstants.SVG_KEY_SPLINES_ATTRIBUTE),
0888:                                                        getTrait(SVGConstants.SVG_KEY_TIMES_ATTRIBUTE) }));
0889:                    }
0890:
0891:                    // Turn the keySplines attribute into a set of (x, y) points
0892:                    // which can be interpolated between.
0893:                    refSplines = toRefSplines(keySplines);
0894:                }
0895:            }
0896:
0897:            /**
0898:             * Computes refTimes from the calcMode and keyTimes attributes. Validates
0899:             * that the keyTimes attribute is compatible with the animate set up. This
0900:             * may be overridden by subclasses (e.g., animateMotion), when there are 
0901:             * special rules for checking keyTimes compatiblity.
0902:             */
0903:            protected void computeRefTimes() throws DOMException {
0904:                // c.1 Validate that keyTimes is compatible with the animation set-up
0905:                //
0906:                // if (calcMode == paced)
0907:                //    refTimes such that change velocity is constant
0908:                //    refTimes = getPacedTiming(refValues) // see follow on slides
0909:                //
0910:                // else if (keyTimes defined) 
0911:                //    refTimes = keyTimes
0912:                //    if (calcMode == discreet)
0913:                //        refTimes[n] = 1 // Accounts for the added nth value 
0914:                //                        // in refValues
0915:                //
0916:                // else refTimes = f(refValues)
0917:                //     the simple duration is divided into n-1 intervals, 
0918:                //     where n = refValues.length
0919:                //     refTimes = defaultTiming(refValues)
0920:                if (actualCalcMode == CALC_MODE_PACED) {
0921:                    // keyTimes are ignored
0922:                    // See: http://www.w3.org/TR/smil20/smil-timing.html#animation-adef-keyTimes
0923:                    refTimes = getPacedTiming(refValues);
0924:                } else if (keyTimes != null) {
0925:                    // Check keyTimes is compatible with the animation specification.
0926:                    // 
0927:                    // a) In all cases, the first keyTime must be zero.
0928:                    // 
0929:                    // b) For non-discrete animations,
0930:                    //    b.1) the last keyTime must be one.
0931:                    //    b.2) there should be one more keyTimes than there are 
0932:                    //         segments.
0933:                    // 
0934:                    // c) For discrete animations,
0935:                    //    c.1) there should be as many keyTimes as there are segments.
0936:                    //
0937:                    if (/* a) */keyTimes.length < 1
0938:                            || keyTimes[0] != 0
0939:                            ||
0940:                            /* b) */(actualCalcMode != CALC_MODE_DISCRETE && (/* b.1) */keyTimes[keyTimes.length - 1] != 1 ||
0941:                            /* b.2) */keyTimes.length != refValues
0942:                                    .getSegments() + 1))
0943:                            ||
0944:                            /* c) */(actualCalcMode == CALC_MODE_DISCRETE &&
0945:                            /* c.1) */keyTimes.length != refValues
0946:                                    .getSegments())) {
0947:                        throw animationError(
0948:                                idRef,
0949:                                traitNamespace,
0950:                                traitName,
0951:                                targetElement.getNamespaceURI(),
0952:                                targetElement.getLocalName(),
0953:                                getId(),
0954:                                getNamespaceURI(),
0955:                                getLocalName(),
0956:                                Messages
0957:                                        .formatMessage(
0958:                                                Messages.ERROR_INVALID_ANIMATION_KEY_TIMES,
0959:                                                new Object[] { getTrait(SVGConstants.SVG_KEY_TIMES_ATTRIBUTE) }));
0960:                    }
0961:
0962:                    // If the calcMode is _not_ discrete, we trim the last '1' 
0963:                    // value.
0964:                    if (actualCalcMode != CALC_MODE_DISCRETE) {
0965:                        refTimes = new float[keyTimes.length - 1];
0966:                        System.arraycopy(keyTimes, 0, refTimes, 0,
0967:                                refTimes.length);
0968:                    } else {
0969:                        refTimes = keyTimes;
0970:                    }
0971:
0972:                    // Validate that there are as many refTimes as there are refValues.
0973:                    // We do the check using the first component, as we know there is at
0974:                    // least one component no matter what value type we are dealing 
0975:                    // with.
0976:                    if (refTimes.length != refValues.getSegments()) {
0977:                        throw animationError(
0978:                                idRef,
0979:                                traitNamespace,
0980:                                traitName,
0981:                                targetElement.getNamespaceURI(),
0982:                                targetElement.getLocalName(),
0983:                                getId(),
0984:                                getNamespaceURI(),
0985:                                getLocalName(),
0986:                                Messages
0987:                                        .formatMessage(
0988:                                                Messages.ERROR_INVALID_ANIMATION_KEY_TIMES,
0989:                                                new Object[] { getTrait(SVGConstants.SVG_KEY_TIMES_ATTRIBUTE) }));
0990:                    }
0991:                } else {
0992:                    // Simple case, give the same time length to each segment.
0993:                    refTimes = getDefaultTiming(refValues);
0994:                }
0995:
0996:            }
0997:
0998:            /**
0999:             * Validates the different so-called values attributes, such as the 
1000:             * to/from/by and values attributes. Derived classes may have more 'values'
1001:             * attributes, and may override this method to validate these additional 
1002:             * attributes.
1003:             *
1004:             * @throws DOMException if there is a validation error, for example if the
1005:             *         to value is incompatible with the target trait or if the target
1006:             *         trait is not animatable.
1007:             */
1008:            final void validateValues() throws DOMException {
1009:                // b.1) Validate the to traits value
1010:                toRefValues = null;
1011:                if (to != null) {
1012:                    toRefValues = traitAnim.toRefValues(this ,
1013:                            new String[] { to }, null,
1014:                            SVGConstants.SVG_TO_ATTRIBUTE);
1015:                }
1016:
1017:                // b.2) Validate the by traits value
1018:                byRefValues = null;
1019:                if (by != null) {
1020:                    byRefValues = traitAnim.toRefValues(this ,
1021:                            new String[] { by }, null,
1022:                            SVGConstants.SVG_BY_ATTRIBUTE);
1023:                }
1024:
1025:                // b.3) Validate the from traits value
1026:                fromRefValues = null;
1027:                if (from != null) {
1028:                    fromRefValues = traitAnim.toRefValues(this ,
1029:                            new String[] { from }, null,
1030:                            SVGConstants.SVG_FROM_ATTRIBUTE);
1031:                }
1032:
1033:                // b.4) Validate the values trait value
1034:                valuesRefValues = null;
1035:                if (values != null) {
1036:                    String[] v = parseStringArrayTrait(
1037:                            SVGConstants.SVG_VALUES_ATTRIBUTE, values, ";");
1038:                    valuesRefValues = traitAnim.toRefValues(this , v, null,
1039:                            SVGConstants.SVG_VALUES_ATTRIBUTE);
1040:                }
1041:
1042:                validateValuesExtra();
1043:            }
1044:
1045:            /**
1046:             * Allows extension classes to validate addition values sources.
1047:             *
1048:             * @throws DOMException if there is a validation error, for example if the
1049:             *         to value is incompatible with the target trait or if the target
1050:             *         trait is not animatable.
1051:             */
1052:            void validateValuesExtra() throws DOMException {
1053:            }
1054:
1055:            /**
1056:             * Allows extensions to select a different source for refValues, in case
1057:             * the extension has addition values sources that have higher precedence
1058:             * than the default. For example, animateMotion has the path attribute and
1059:             * the mpath children which have higher precedence.
1060:             *
1061:             * @throws DOMException if there is no way to compute a set of reference
1062:             *         values, for example if none of the values sources is specified.
1063:             */
1064:            void selectRefValuesExtra() throws DOMException {
1065:            }
1066:
1067:            /**
1068:             * Computes the 'right' source for reference values, depending on the 
1069:             * precedence rules for the different values sources. 
1070:             *
1071:             * @throws DOMException if there is no way to compute a set of reference
1072:             *         values, for example if none of the values sources is specified.
1073:             */
1074:            final void selectRefValues() throws DOMException {
1075:                refValues = null;
1076:                selectRefValuesExtra();
1077:                if (refValues != null) {
1078:                    return;
1079:                }
1080:
1081:                // Pseudo-code for accounting for precedence rules.
1082:                //
1083:                // If (values defined)
1084:                //     // values anim
1085:                //     refValues = values; 
1086:                // else if (from defined)
1087:                //     if (to defined)
1088:                //         // from-to anim
1089:                //         refValues = (from; to)
1090:                //     else if (by defined)
1091:                //         // from-by anim
1092:                //        refValues = (from; from+by) 
1093:                //     else
1094:                //     // no effect, there is nothing like a from anim
1095:                // else if (by defined)
1096:                //     // by anim
1097:                //     refValues = (0; by) and force additive anim
1098:                // else if (to defined)
1099:                //     // to anim
1100:                //     refValues = (baseVal; to)
1101:                // else
1102:                //    // no effect
1103:                //
1104:                isToAnimation = false;
1105:                if (values != null) {
1106:                    refValues = valuesRefValues;
1107:                } else if (from != null) {
1108:                    refValues = fromRefValues;
1109:
1110:                    if (to != null) {
1111:                        // from-to animatin
1112:                        refValues.getSegment(0).collapse(
1113:                                toRefValues.getSegment(0), this );
1114:                    } else if (by != null) {
1115:                        // from-by animation
1116:                        if (refValues.getSegment(0).isAdditive()) {
1117:                            try {
1118:                                refValues.getSegment(0).addToEnd(
1119:                                        byRefValues.getSegment(0).getStart());
1120:                            } catch (IllegalArgumentException iae) {
1121:                                // Incompatible by value
1122:                                throw new DOMException(
1123:                                        DOMException.NOT_SUPPORTED_ERR,
1124:                                        Messages
1125:                                                .formatMessage(
1126:                                                        Messages.ERROR_INCOMPATIBLE_FROM_BY,
1127:                                                        new Object[] {
1128:                                                                traitName,
1129:                                                                traitNamespace,
1130:                                                                getLocalName(),
1131:                                                                getNamespaceURI(),
1132:                                                                from, to }));
1133:                            }
1134:                        } else {
1135:                            throw new DOMException(
1136:                                    DOMException.NOT_SUPPORTED_ERR,
1137:                                    Messages
1138:                                            .formatMessage(
1139:                                                    Messages.ERROR_ATTRIBUTE_NOT_ADDITIVE_FROM_BY,
1140:                                                    new Object[] { traitName,
1141:                                                            traitNamespace,
1142:                                                            getLocalName(),
1143:                                                            getNamespaceURI() }));
1144:                        }
1145:                    } else {
1146:                        throw animationError(
1147:                                idRef,
1148:                                traitNamespace,
1149:                                traitName,
1150:                                targetElement.getNamespaceURI(),
1151:                                targetElement.getLocalName(),
1152:                                getId(),
1153:                                getNamespaceURI(),
1154:                                getLocalName(),
1155:                                Messages
1156:                                        .formatMessage(
1157:                                                Messages.ERROR_INVALID_ANIMATION_FROM_ANIM,
1158:                                                null));
1159:                    }
1160:                } else if (by != null) {
1161:                    // by animation
1162:                    if (!byRefValues.getSegment(0).isAdditive()) {
1163:                        throw new DOMException(
1164:                                DOMException.NOT_SUPPORTED_ERR,
1165:                                Messages
1166:                                        .formatMessage(
1167:                                                Messages.ERROR_ATTRIBUTE_NOT_ADDITIVE_BY,
1168:                                                new Object[] { traitName,
1169:                                                        traitNamespace,
1170:                                                        getLocalName(),
1171:                                                        getNamespaceURI() }));
1172:                    }
1173:                    refValues = byRefValues;
1174:                    refValues.getSegment(0).setZeroStart();
1175:                    additive = true;
1176:                } else if (to != null) {
1177:                    // to animation
1178:                    // We cannot compute the base value yet so we can only set the 
1179:                    // refValues to the toRefValues and delay computing the segment's 
1180:                    // begin until we actually have a baseValue. This will have to be 
1181:                    // updated on each computing cycle because the base value may change
1182:                    // over time.
1183:                    isToAnimation = true;
1184:                    refValues = toRefValues;
1185:                } else {
1186:                    // SMIL Animation
1187:                    // specification:
1188:                    // http://www.w3.org/TR/2001/REC-smil-animation-20010904/#AnimFuncValues
1189:                    // "similarly, if none of the from, to, by or values attributes are
1190:                    // specified, the animation will have no effect."
1191:                    hasNoEffect = true;
1192:                }
1193:            }
1194:
1195:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.