Source Code Cross Referenced for TimedElement.java in  » Graphic-Library » batik » org » apache » batik » anim » timing » 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 » Graphic Library » batik » org.apache.batik.anim.timing 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:
0003:           Licensed to the Apache Software Foundation (ASF) under one or more
0004:           contributor license agreements.  See the NOTICE file distributed with
0005:           this work for additional information regarding copyright ownership.
0006:           The ASF licenses this file to You under the Apache License, Version 2.0
0007:           (the "License"); you may not use this file except in compliance with
0008:           the License.  You may obtain a copy of the License at
0009:
0010:               http://www.apache.org/licenses/LICENSE-2.0
0011:
0012:           Unless required by applicable law or agreed to in writing, software
0013:           distributed under the License is distributed on an "AS IS" BASIS,
0014:           WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0015:           See the License for the specific language governing permissions and
0016:           limitations under the License.
0017:
0018:         */
0019:        package org.apache.batik.anim.timing;
0020:
0021:        import java.util.*;
0022:
0023:        import org.apache.batik.anim.AnimationException;
0024:        import org.apache.batik.i18n.LocalizableSupport;
0025:        import org.apache.batik.parser.ClockHandler;
0026:        import org.apache.batik.parser.ClockParser;
0027:        import org.apache.batik.parser.ParseException;
0028:        import org.apache.batik.util.SMILConstants;
0029:
0030:        import org.w3c.dom.Element;
0031:        import org.w3c.dom.events.Event;
0032:        import org.w3c.dom.events.EventTarget;
0033:
0034:        /**
0035:         * An abstract base class for elements that can have timing applied to them.
0036:         * The concrete versions of this class do not necessarily have to be the
0037:         * same as the DOM class, and in fact, this will mostly be impossible unless
0038:         * creating new DOM classes that inherit from these elements.
0039:         *
0040:         * @author <a href="mailto:cam%40mcc%2eid%2eau">Cameron McCormack</a>
0041:         * @version $Id: TimedElement.java 522271 2007-03-25 14:42:45Z dvholten $
0042:         */
0043:        public abstract class TimedElement implements  SMILConstants {
0044:
0045:            // Constants for fill mode.
0046:            public static final int FILL_REMOVE = 0;
0047:            public static final int FILL_FREEZE = 1;
0048:
0049:            // Constants for restart mode.
0050:            public static final int RESTART_ALWAYS = 0;
0051:            public static final int RESTART_WHEN_NOT_ACTIVE = 1;
0052:            public static final int RESTART_NEVER = 2;
0053:
0054:            // Constants for time values.
0055:            public static final float INDEFINITE = Float.POSITIVE_INFINITY;
0056:            public static final float UNRESOLVED = Float.NaN;
0057:
0058:            /**
0059:             * The root time container.
0060:             */
0061:            protected TimedDocumentRoot root;
0062:
0063:            /**
0064:             * The parent time container.
0065:             */
0066:            protected TimeContainer parent;
0067:
0068:            /**
0069:             * Timing specifiers for the begin times of this element.
0070:             */
0071:            protected TimingSpecifier[] beginTimes;
0072:
0073:            /**
0074:             * Timing specifiers for the end times of this element.
0075:             */
0076:            protected TimingSpecifier[] endTimes;
0077:
0078:            /**
0079:             * Duration of this element, if {@link #durMedia} <code>= false</code>.
0080:             * If unspecified, it will be {@link #UNRESOLVED}.
0081:             */
0082:            protected float simpleDur;
0083:
0084:            /**
0085:             * Whether the simple duration of this element should be equal
0086:             * to the implicit duration.
0087:             */
0088:            protected boolean durMedia;
0089:
0090:            /**
0091:             * The number of repeats.  If unspecified, it will be
0092:             * {@link #UNRESOLVED}.
0093:             */
0094:            protected float repeatCount;
0095:
0096:            /**
0097:             * The duration of repeats.  If unspecified, it will be
0098:             * {@link #UNRESOLVED}.
0099:             */
0100:            protected float repeatDur;
0101:
0102:            /**
0103:             * The current repeat iteration.
0104:             */
0105:            protected int currentRepeatIteration;
0106:
0107:            /**
0108:             * The local active time of the last repeat.
0109:             */
0110:            protected float lastRepeatTime;
0111:
0112:            /**
0113:             * The fill mode for this element.  Uses the FILL_* constants
0114:             * defined in this class.
0115:             */
0116:            protected int fillMode;
0117:
0118:            /**
0119:             * The restart mode for this element.  Uses the RESTART_* constants
0120:             * defined in this class.
0121:             */
0122:            protected int restartMode;
0123:
0124:            /**
0125:             * The minimum active duration of this element.  If {@link #minMedia}
0126:             * <code>= true</code>, it will be <code>0f</code>.
0127:             */
0128:            protected float min;
0129:
0130:            /**
0131:             * Whether the min value was specified as 'media'.
0132:             */
0133:            protected boolean minMedia;
0134:
0135:            /**
0136:             * The maximum active duration of this element.  If {@link #maxMedia}
0137:             * <code>= true</code>, it will be {@link #INDEFINITE}.
0138:             */
0139:            protected float max;
0140:
0141:            /**
0142:             * Whether the max value was specified as 'media'.
0143:             */
0144:            protected boolean maxMedia;
0145:
0146:            /**
0147:             * Whether the element is currently active.
0148:             */
0149:            protected boolean isActive;
0150:
0151:            /**
0152:             * Whether the element is currently frozen.
0153:             */
0154:            protected boolean isFrozen;
0155:
0156:            /**
0157:             * The current time of this element in local active time.
0158:             */
0159:            protected float lastSampleTime;
0160:
0161:            /**
0162:             * The computed repeat duration of the element.
0163:             */
0164:            protected float repeatDuration;
0165:
0166:            /**
0167:             * List of begin InstanceTimes.
0168:             */
0169:            protected List beginInstanceTimes = new ArrayList();
0170:
0171:            /**
0172:             * List of end InstanceTimes.
0173:             */
0174:            protected List endInstanceTimes = new ArrayList();
0175:
0176:            /**
0177:             * The current Interval.
0178:             */
0179:            protected Interval currentInterval;
0180:
0181:            /**
0182:             * The end time of the previous interval, initially
0183:             * {@link Float#NEGATIVE_INFINITY}.
0184:             */
0185:            protected float lastIntervalEnd;
0186:
0187:            /**
0188:             * List of previous intervals.
0189:             */
0190:            protected LinkedList previousIntervals = new LinkedList();
0191:
0192:            /**
0193:             * List of TimingSpecifiers on other elements that depend on this
0194:             * element's begin times.
0195:             */
0196:            protected LinkedList beginDependents = new LinkedList();
0197:
0198:            /**
0199:             * List of TimingSpecifiers on other elements that depend on this
0200:             * element's end times.
0201:             */
0202:            protected LinkedList endDependents = new LinkedList();
0203:
0204:            /**
0205:             * Whether the list of instance times should be checked to update
0206:             * the current interval.
0207:             */
0208:            protected boolean shouldUpdateCurrentInterval = true;
0209:
0210:            /**
0211:             * Whether this timed element has parsed its timing attributes yet.
0212:             */
0213:            protected boolean hasParsed;
0214:
0215:            /**
0216:             * Map of {@link Event} objects to {@link HashSet}s of {@link
0217:             * TimingSpecifier}s that caught them.
0218:             */
0219:            protected Map handledEvents = new HashMap();
0220:
0221:            /**
0222:             * Whether this timed element is currently being sampled.
0223:             */
0224:            protected boolean isSampling;
0225:
0226:            /**
0227:             * Whether an instance time update message has already been propagated to
0228:             * this timed element.
0229:             */
0230:            protected boolean hasPropagated;
0231:
0232:            /**
0233:             * Creates a new TimedElement.
0234:             */
0235:            public TimedElement() {
0236:                beginTimes = new TimingSpecifier[0];
0237:                endTimes = beginTimes;
0238:                simpleDur = UNRESOLVED;
0239:                repeatCount = UNRESOLVED;
0240:                repeatDur = UNRESOLVED;
0241:                lastRepeatTime = UNRESOLVED;
0242:                max = INDEFINITE;
0243:                lastSampleTime = UNRESOLVED;
0244:                lastIntervalEnd = Float.NEGATIVE_INFINITY;
0245:            }
0246:
0247:            /**
0248:             * Returns the root time container of this timed element.
0249:             */
0250:            public TimedDocumentRoot getRoot() {
0251:                return root;
0252:            }
0253:
0254:            /**
0255:             * Returns the current active time of this element.
0256:             */
0257:            public float getActiveTime() {
0258:                return lastSampleTime;
0259:            }
0260:
0261:            /**
0262:             * Returns the current simple time of this element.
0263:             */
0264:            public float getSimpleTime() {
0265:                return lastSampleTime - lastRepeatTime;
0266:            }
0267:
0268:            /**
0269:             * Called by a TimingSpecifier of this element when a new
0270:             * InstanceTime is created.  This will be in response to an event
0271:             * firing, a DOM method being called or a new Instance being
0272:             * created by a syncbase element.
0273:             */
0274:            protected float addInstanceTime(InstanceTime time, boolean isBegin) {
0275:                // Trace.enter(this, "addInstanceTime", new Object[] { time, new Boolean(isBegin) } ); try {
0276:                hasPropagated = true;
0277:                List instanceTimes = isBegin ? beginInstanceTimes
0278:                        : endInstanceTimes;
0279:                int index = Collections.binarySearch(instanceTimes, time);
0280:                if (index < 0) {
0281:                    index = -(index + 1);
0282:                }
0283:                instanceTimes.add(index, time);
0284:                shouldUpdateCurrentInterval = true;
0285:                float ret;
0286:                if (root.isSampling() && !isSampling) {
0287:                    ret = sampleAt(root.getCurrentTime(), root.isHyperlinking());
0288:                } else {
0289:                    ret = Float.POSITIVE_INFINITY;
0290:                }
0291:                hasPropagated = false;
0292:                return ret;
0293:                // } finally { Trace.exit(); }
0294:            }
0295:
0296:            /**
0297:             * Called by a TimingSpecifier of this element when an InstanceTime
0298:             * should be removed.  This will be in response to the pruning of an
0299:             * Interval.
0300:             */
0301:            protected float removeInstanceTime(InstanceTime time,
0302:                    boolean isBegin) {
0303:                // Trace.enter(this, "removeInstanceTime", new Object[] { time, new Boolean(isBegin) } ); try {
0304:                hasPropagated = true;
0305:                List instanceTimes = isBegin ? beginInstanceTimes
0306:                        : endInstanceTimes;
0307:                int index = Collections.binarySearch(instanceTimes, time);
0308:                for (int i = index; i >= 0; i--) {
0309:                    InstanceTime it = (InstanceTime) instanceTimes.get(i);
0310:                    if (it == time) {
0311:                        instanceTimes.remove(i);
0312:                        break;
0313:                    }
0314:                    if (it.compareTo(time) != 0) {
0315:                        break;
0316:                    }
0317:                }
0318:                int len = instanceTimes.size();
0319:                for (int i = index + 1; i < len; i++) {
0320:                    InstanceTime it = (InstanceTime) instanceTimes.get(i);
0321:                    if (it == time) {
0322:                        instanceTimes.remove(i);
0323:                        break;
0324:                    }
0325:                    if (it.compareTo(time) != 0) {
0326:                        break;
0327:                    }
0328:                }
0329:                shouldUpdateCurrentInterval = true;
0330:                float ret;
0331:                if (root.isSampling() && !isSampling) {
0332:                    ret = sampleAt(root.getCurrentTime(), root.isHyperlinking());
0333:                } else {
0334:                    ret = Float.POSITIVE_INFINITY;
0335:                }
0336:                hasPropagated = false;
0337:                return ret;
0338:                // } finally { Trace.exit(); }
0339:            }
0340:
0341:            /**
0342:             * Called by a TimingSpecifier of this element when an InstanceTime
0343:             * has been updated.  This will be in response to a dependent
0344:             * syncbase change.
0345:             */
0346:            protected float instanceTimeChanged(InstanceTime time,
0347:                    boolean isBegin) {
0348:                // Trace.enter(this, "instanceTimeChanged", new Object[] { time, new Boolean(isBegin) } ); try {
0349:                hasPropagated = true;
0350:                shouldUpdateCurrentInterval = true;
0351:                float ret;
0352:                if (root.isSampling() && !isSampling) {
0353:                    ret = sampleAt(root.getCurrentTime(), root.isHyperlinking());
0354:                } else {
0355:                    ret = Float.POSITIVE_INFINITY;
0356:                }
0357:                hasPropagated = false;
0358:                return ret;
0359:                // } finally { Trace.exit(); }
0360:            }
0361:
0362:            /**
0363:             * Adds a dependent TimingSpecifier for this element.
0364:             */
0365:            protected void addDependent(TimingSpecifier dependent,
0366:                    boolean forBegin) {
0367:                // Trace.enter(this, "addDependent", new Object[] { dependent, new Boolean(forBegin) } ); try {
0368:                if (forBegin) {
0369:                    beginDependents.add(dependent);
0370:                } else {
0371:                    endDependents.add(dependent);
0372:                }
0373:                // } finally { Trace.exit(); }
0374:            }
0375:
0376:            /**
0377:             * Removes a dependent TimingSpecifier for this element.
0378:             */
0379:            protected void removeDependent(TimingSpecifier dependent,
0380:                    boolean forBegin) {
0381:                // Trace.enter(this, "removeDependent", new Object[] { dependent, new Boolean(forBegin) } ); try {
0382:                if (forBegin) {
0383:                    beginDependents.remove(dependent);
0384:                } else {
0385:                    endDependents.remove(dependent);
0386:                }
0387:                // } finally { Trace.exit(); }
0388:            }
0389:
0390:            /**
0391:             * Returns the simple duration time of this element.
0392:             */
0393:            public float getSimpleDur() {
0394:                if (durMedia) {
0395:                    return getImplicitDur();
0396:                } else if (isUnresolved(simpleDur)) {
0397:                    if (isUnresolved(repeatCount) && isUnresolved(repeatDur)
0398:                            && endTimes.length > 0) {
0399:                        return INDEFINITE;
0400:                    }
0401:                    return getImplicitDur();
0402:                } else {
0403:                    return simpleDur;
0404:                }
0405:            }
0406:
0407:            /**
0408:             * Returns whether the given time value is equal to the
0409:             * {@link #UNRESOLVED} value.
0410:             */
0411:            public static boolean isUnresolved(float t) {
0412:                return Float.isNaN(t);
0413:            }
0414:
0415:            /**
0416:             * Returns the active duration time of this element.
0417:             */
0418:            public float getActiveDur(float B, float end) {
0419:                float d = getSimpleDur();
0420:                float PAD;
0421:                if (!isUnresolved(end) && d == INDEFINITE) {
0422:                    PAD = minusTime(end, B);
0423:                    repeatDuration = minTime(max, maxTime(min, PAD));
0424:                    return repeatDuration;
0425:                }
0426:
0427:                float IAD;
0428:                if (d == 0) {
0429:                    IAD = 0;
0430:                } else {
0431:                    if (isUnresolved(repeatDur) && isUnresolved(repeatCount)) {
0432:                        IAD = d;
0433:                    } else {
0434:                        float p1 = isUnresolved(repeatCount) ? INDEFINITE
0435:                                : multiplyTime(d, repeatCount);
0436:                        float p2 = isUnresolved(repeatDur) ? INDEFINITE
0437:                                : repeatDur;
0438:                        IAD = minTime(minTime(p1, p2), INDEFINITE);
0439:                    }
0440:                }
0441:                if (isUnresolved(end) || end == INDEFINITE) {
0442:                    PAD = IAD;
0443:                } else {
0444:                    PAD = minTime(IAD, minusTime(end, B));
0445:                }
0446:                repeatDuration = IAD;
0447:                return minTime(max, maxTime(min, PAD));
0448:            }
0449:
0450:            /**
0451:             * Subtracts one simple time from another.
0452:             */
0453:            protected float minusTime(float t1, float t2) {
0454:                if (isUnresolved(t1) || isUnresolved(t2)) {
0455:                    return UNRESOLVED;
0456:                }
0457:                if (t1 == INDEFINITE || t2 == INDEFINITE) {
0458:                    return INDEFINITE;
0459:                }
0460:                return t1 - t2;
0461:            }
0462:
0463:            /**
0464:             * Multiplies one simple time by n.
0465:             */
0466:            protected float multiplyTime(float t, float n) {
0467:                if (isUnresolved(t) || t == INDEFINITE) {
0468:                    return t;
0469:                }
0470:                return t * n;
0471:            }
0472:
0473:            /**
0474:             * Returns the minimum of two time values.
0475:             */
0476:            protected float minTime(float t1, float t2) {
0477:                if (t1 == 0.0f || t2 == 0.0f) {
0478:                    return 0.0f;
0479:                }
0480:                if ((t1 == INDEFINITE || isUnresolved(t1)) && t2 != INDEFINITE
0481:                        && !isUnresolved(t2)) {
0482:                    return t2;
0483:                }
0484:                if ((t2 == INDEFINITE || isUnresolved(t2)) && t1 != INDEFINITE
0485:                        && !isUnresolved(t1)) {
0486:                    return t1;
0487:                }
0488:                if (t1 == INDEFINITE && isUnresolved(t2) || isUnresolved(t1)
0489:                        && t2 == INDEFINITE) {
0490:                    return INDEFINITE;
0491:                }
0492:                if (t1 < t2) {
0493:                    return t1;
0494:                }
0495:                return t2;
0496:            }
0497:
0498:            /**
0499:             * Returns the maximum of two time values.
0500:             */
0501:            protected float maxTime(float t1, float t2) {
0502:                if ((t1 == INDEFINITE || isUnresolved(t1)) && t2 != INDEFINITE
0503:                        && !isUnresolved(t2)) {
0504:                    return t1;
0505:                }
0506:                if ((t2 == INDEFINITE || isUnresolved(t2)) && t1 != INDEFINITE
0507:                        && !isUnresolved(t1)) {
0508:                    return t2;
0509:                }
0510:                if (t1 == INDEFINITE && isUnresolved(t2) || isUnresolved(t1)
0511:                        && t2 == INDEFINITE) {
0512:                    return UNRESOLVED;
0513:                }
0514:                if (t1 > t2) {
0515:                    return t1;
0516:                }
0517:                return t2;
0518:            }
0519:
0520:            /**
0521:             * Returns the implicit duration of the element.  Currently, nested time
0522:             * containers are not supported by SVG so this just returns
0523:             * {@link #UNRESOLVED} by default.  This should be overriden in derived
0524:             * classes that play media, since they will have an implicit duration.
0525:             */
0526:            protected float getImplicitDur() {
0527:                return UNRESOLVED;
0528:            }
0529:
0530:            /**
0531:             * Notifies dependents of a new interval.
0532:             */
0533:            protected float notifyNewInterval(Interval interval) {
0534:                // Trace.enter(this, "notifyNewInterval", new Object[] { interval } ); try {
0535:                float dependentMinTime = Float.POSITIVE_INFINITY;
0536:                Iterator i = beginDependents.iterator();
0537:                while (i.hasNext()) {
0538:                    TimingSpecifier ts = (TimingSpecifier) i.next();
0539:                    // Trace.print(ts.owner + "'s " + (ts.isBegin ? "begin" : "end" ) + ": " + ts);
0540:                    float t = ts.newInterval(interval);
0541:                    if (t < dependentMinTime) {
0542:                        dependentMinTime = t;
0543:                    }
0544:                }
0545:                i = endDependents.iterator();
0546:                while (i.hasNext()) {
0547:                    TimingSpecifier ts = (TimingSpecifier) i.next();
0548:                    // Trace.print(ts.owner + "'s " + (ts.isBegin ? "begin" : "end" ) + ": " + ts);
0549:                    float t = ts.newInterval(interval);
0550:                    if (t < dependentMinTime) {
0551:                        dependentMinTime = t;
0552:                    }
0553:                }
0554:                return dependentMinTime;
0555:                // } finally { Trace.exit(); }
0556:            }
0557:
0558:            /**
0559:             * Notifies dependents of a removed interval.
0560:             */
0561:            protected float notifyRemoveInterval(Interval interval) {
0562:                // Trace.enter(this, "notifyRemoveInterval", new Object[] { interval } ); try {
0563:                float dependentMinTime = Float.POSITIVE_INFINITY;
0564:                Iterator i = beginDependents.iterator();
0565:                while (i.hasNext()) {
0566:                    TimingSpecifier ts = (TimingSpecifier) i.next();
0567:                    float t = ts.removeInterval(interval);
0568:                    if (t < dependentMinTime) {
0569:                        dependentMinTime = t;
0570:                    }
0571:                }
0572:                i = endDependents.iterator();
0573:                while (i.hasNext()) {
0574:                    TimingSpecifier ts = (TimingSpecifier) i.next();
0575:                    float t = ts.removeInterval(interval);
0576:                    if (t < dependentMinTime) {
0577:                        dependentMinTime = t;
0578:                    }
0579:                }
0580:                return dependentMinTime;
0581:                // } finally { Trace.exit(); }
0582:            }
0583:
0584:            /**
0585:             * Calculates the local simple time.  Currently the hyperlinking parameter
0586:             * is ignored, so DOM timing events are fired during hyperlinking seeks.
0587:             * If we were following SMIL 2.1 rather than SMIL Animation, then these
0588:             * events would have to be surpressed.
0589:             *
0590:             * @return the number of seconds until this element becomes active again
0591:             *         if it currently is not, {@link Float#POSITIVE_INFINITY} if this
0592:             *         element will become active at some undetermined point in the
0593:             *         future (because of unresolved begin times, for example) or
0594:             *         will never become active again, or <code>0f</code> if the
0595:             *         element is currently active.
0596:             */
0597:            protected float sampleAt(float parentSimpleTime,
0598:                    boolean hyperlinking) {
0599:                // Trace.enter(this, "sampleAt", new Object[] { new Float(parentSimpleTime) } ); try {
0600:                isSampling = true;
0601:
0602:                float time = parentSimpleTime; // No time containers in SVG.
0603:
0604:                // First, process any events that occurred since the last sampling,
0605:                // taking into account event sensitivity.
0606:                Iterator i = handledEvents.entrySet().iterator();
0607:                while (i.hasNext()) {
0608:                    Map.Entry e = (Map.Entry) i.next();
0609:                    Event evt = (Event) e.getKey();
0610:                    Set ts = (Set) e.getValue();
0611:                    Iterator j = ts.iterator();
0612:                    boolean hasBegin = false, hasEnd = false;
0613:                    while (j.hasNext() && !(hasBegin && hasEnd)) {
0614:                        EventLikeTimingSpecifier t = (EventLikeTimingSpecifier) j
0615:                                .next();
0616:                        if (t.isBegin()) {
0617:                            hasBegin = true;
0618:                        } else {
0619:                            hasEnd = true;
0620:                        }
0621:                    }
0622:                    boolean useBegin, useEnd;
0623:                    if (hasBegin && hasEnd) {
0624:                        useBegin = !isActive || restartMode == RESTART_ALWAYS;
0625:                        useEnd = !useBegin;
0626:                    } else if (hasBegin
0627:                            && (!isActive || restartMode == RESTART_ALWAYS)) {
0628:                        useBegin = true;
0629:                        useEnd = false;
0630:                    } else if (hasEnd && isActive) {
0631:                        useBegin = false;
0632:                        useEnd = true;
0633:                    } else {
0634:                        continue;
0635:                    }
0636:                    j = ts.iterator();
0637:                    while (j.hasNext()) {
0638:                        EventLikeTimingSpecifier t = (EventLikeTimingSpecifier) j
0639:                                .next();
0640:                        boolean isBegin = t.isBegin();
0641:                        if (isBegin && useBegin || !isBegin && useEnd) {
0642:                            t.resolve(evt);
0643:                            shouldUpdateCurrentInterval = true;
0644:                        }
0645:                    }
0646:                }
0647:                handledEvents.clear();
0648:
0649:                // Now process intervals.
0650:                if (currentInterval != null) {
0651:                    float begin = currentInterval.getBegin();
0652:                    if (lastSampleTime < begin && time >= begin) {
0653:                        if (!isActive) {
0654:                            toActive(begin);
0655:                        }
0656:                        isActive = true;
0657:                        isFrozen = false;
0658:                        lastRepeatTime = begin;
0659:                        fireTimeEvent(SMIL_BEGIN_EVENT_NAME, currentInterval
0660:                                .getBegin(), 0);
0661:                    }
0662:                }
0663:                // For each sample, we might need to update the current interval's
0664:                // begin and end times, or end the current interval and compute
0665:                // a new one.
0666:                boolean hasEnded = currentInterval != null
0667:                        && time >= currentInterval.getEnd();
0668:                // Fire any repeat events that should have been fired since the
0669:                // last sample.
0670:                if (currentInterval != null) {
0671:                    float begin = currentInterval.getBegin();
0672:                    if (time >= begin) {
0673:                        float d = getSimpleDur();
0674:                        while (time - lastRepeatTime >= d
0675:                                && lastRepeatTime + d < begin + repeatDuration) {
0676:                            lastRepeatTime += d;
0677:                            currentRepeatIteration++;
0678:                            fireTimeEvent(root.getRepeatEventName(),
0679:                                    lastRepeatTime, currentRepeatIteration);
0680:                        }
0681:                    }
0682:                }
0683:
0684:                // Trace.print("begin loop");
0685:                float dependentMinTime = Float.POSITIVE_INFINITY;
0686:                if (hyperlinking) {
0687:                    shouldUpdateCurrentInterval = true;
0688:                }
0689:                while (shouldUpdateCurrentInterval || hasEnded) {
0690:                    if (hasEnded) {
0691:                        previousIntervals.add(currentInterval);
0692:                        isActive = false;
0693:                        isFrozen = fillMode == FILL_FREEZE;
0694:                        toInactive(false, isFrozen);
0695:                        fireTimeEvent(SMIL_END_EVENT_NAME, currentInterval
0696:                                .getEnd(), 0);
0697:                    }
0698:                    boolean first = currentInterval == null
0699:                            && previousIntervals.isEmpty();
0700:                    if (currentInterval == null || hasEnded) {
0701:                        if (first || hyperlinking
0702:                                || restartMode != RESTART_NEVER) {
0703:                            float beginAfter;
0704:                            if (first || hyperlinking) {
0705:                                beginAfter = Float.NEGATIVE_INFINITY;
0706:                            } else {
0707:                                beginAfter = ((Interval) previousIntervals
0708:                                        .getLast()).getEnd();
0709:                            }
0710:                            Interval interval = computeInterval(first, false,
0711:                                    beginAfter);
0712:                            if (interval == null) {
0713:                                currentInterval = null;
0714:                            } else {
0715:                                float dmt = selectNewInterval(time, interval);
0716:                                if (dmt < dependentMinTime) {
0717:                                    dependentMinTime = dmt;
0718:                                }
0719:                            }
0720:                        } else {
0721:                            currentInterval = null;
0722:                        }
0723:                    } else {
0724:                        float currentBegin = currentInterval.getBegin();
0725:                        if (currentBegin > time) {
0726:                            // Interval hasn't started yet.
0727:                            float beginAfter;
0728:                            if (previousIntervals.isEmpty()) {
0729:                                beginAfter = Float.NEGATIVE_INFINITY;
0730:                            } else {
0731:                                beginAfter = ((Interval) previousIntervals
0732:                                        .getLast()).getEnd();
0733:                            }
0734:                            Interval interval = computeInterval(false, false,
0735:                                    beginAfter);
0736:                            float dmt = notifyRemoveInterval(currentInterval);
0737:                            if (dmt < dependentMinTime) {
0738:                                dependentMinTime = dmt;
0739:                            }
0740:                            if (interval == null) {
0741:                                currentInterval = null;
0742:                            } else {
0743:                                dmt = selectNewInterval(time, interval);
0744:                                if (dmt < dependentMinTime) {
0745:                                    dependentMinTime = dmt;
0746:                                }
0747:                            }
0748:                        } else {
0749:                            // Interval has already started.
0750:                            Interval interval = computeInterval(false, true,
0751:                                    currentBegin);
0752:                            float newEnd = interval.getEnd();
0753:                            if (currentInterval.getEnd() != newEnd) {
0754:                                float dmt = currentInterval.setEnd(newEnd,
0755:                                        interval.getEndInstanceTime());
0756:                                if (dmt < dependentMinTime) {
0757:                                    dependentMinTime = dmt;
0758:                                }
0759:                            }
0760:                        }
0761:                    }
0762:                    shouldUpdateCurrentInterval = false;
0763:                    hyperlinking = false;
0764:                    hasEnded = currentInterval != null
0765:                            && time >= currentInterval.getEnd();
0766:                }
0767:                // Trace.print("end loop");
0768:
0769:                float d = getSimpleDur();
0770:                if (isActive && !isFrozen) {
0771:                    if (time - currentInterval.getBegin() >= repeatDuration) {
0772:                        // Trace.print("element between repeat and active duration");
0773:                        isFrozen = fillMode == FILL_FREEZE;
0774:                        toInactive(true, isFrozen);
0775:                    } else {
0776:                        // Trace.print("element active, sampling at simple time " + (time - lastRepeatTime));
0777:                        sampledAt(time - lastRepeatTime, d,
0778:                                currentRepeatIteration);
0779:                    }
0780:                }
0781:                if (isFrozen) {
0782:                    float t;
0783:                    if (isActive) {
0784:                        t = currentInterval.getBegin() + repeatDuration
0785:                                - lastRepeatTime;
0786:                    } else {
0787:                        Interval previousInterval = (Interval) previousIntervals
0788:                                .getLast();
0789:                        t = previousInterval.getEnd() - lastRepeatTime;
0790:                    }
0791:                    if (t % d == 0) {
0792:                        // Trace.print("element frozen" + (isActive ? " (but still active)" : "") + ", sampling last value");
0793:                        sampledLastValue(currentRepeatIteration);
0794:                    } else {
0795:                        // Trace.print("element frozen" + (isActive ? " (but still active)" : "") + ", sampling at simple time " + (t % d));
0796:                        sampledAt(t % d, d, currentRepeatIteration);
0797:                    }
0798:                } else if (!isActive) {
0799:                    // Trace.print("element not sampling");
0800:                }
0801:
0802:                isSampling = false;
0803:
0804:                lastSampleTime = time;
0805:                if (currentInterval != null) {
0806:                    float t = currentInterval.getBegin() - time;
0807:                    if (t <= 0) {
0808:                        t = isConstantAnimation() || isFrozen ? currentInterval
0809:                                .getEnd()
0810:                                - time : 0;
0811:                    }
0812:                    if (dependentMinTime < t) {
0813:                        return dependentMinTime;
0814:                    }
0815:                    return t;
0816:                }
0817:                return dependentMinTime;
0818:                // } finally { Trace.exit(); }
0819:            }
0820:
0821:            /**
0822:             * Returns whether the end timing specifier list contains any eventbase,
0823:             * accesskey or repeat timing specifiers.
0824:             */
0825:            protected boolean endHasEventConditions() {
0826:                for (int i = 0; i < endTimes.length; i++) {
0827:                    if (endTimes[i].isEventCondition()) {
0828:                        return true;
0829:                    }
0830:                }
0831:                return false;
0832:            }
0833:
0834:            /**
0835:             * Sets the current interval to the one specified.  This will notify
0836:             * dependents and fire the 'begin' and any necessary 'repeat' events.
0837:             * @param time the current sampling time
0838:             * @param interval the Interval object to select to be current
0839:             * @return the minimum time the animation engine can safely wait, as
0840:             *         determined by dependents of the interval
0841:             */
0842:            protected float selectNewInterval(float time, Interval interval) {
0843:                // Trace.enter(this, "selectNewInterval", new Object[] { interval }); try {
0844:                currentInterval = interval;
0845:                float dmt = notifyNewInterval(currentInterval);
0846:                float beginEventTime = currentInterval.getBegin();
0847:                if (time >= beginEventTime) {
0848:                    lastRepeatTime = beginEventTime;
0849:                    if (beginEventTime < 0) {
0850:                        beginEventTime = 0;
0851:                    }
0852:                    toActive(beginEventTime);
0853:                    isActive = true;
0854:                    isFrozen = false;
0855:                    fireTimeEvent(SMIL_BEGIN_EVENT_NAME, beginEventTime, 0);
0856:                    float d = getSimpleDur();
0857:                    float end = currentInterval.getEnd();
0858:                    while (time - lastRepeatTime >= d
0859:                            && lastRepeatTime + d < end) {
0860:                        lastRepeatTime += d;
0861:                        currentRepeatIteration++;
0862:                        fireTimeEvent(root.getRepeatEventName(),
0863:                                lastRepeatTime, currentRepeatIteration);
0864:                    }
0865:                }
0866:                return dmt;
0867:                // } finally { Trace.exit(); }
0868:            }
0869:
0870:            /**
0871:             * Computes an interval from the begin and end instance time lists.
0872:             * @param first indicates whether this is the first interval to compute
0873:             * @param fixedBegin if true, specifies that the value given for
0874:             *                   {@code beginAfter} is taken to be the actual begin
0875:             *                   time for the interval; only the end value is computed.
0876:             * @param beginAfter the earliest possible begin time for the computed
0877:             *                   interval.
0878:             */
0879:            protected Interval computeInterval(boolean first,
0880:                    boolean fixedBegin, float beginAfter) {
0881:                // Trace.enter(this, "computeInterval", new Object[] { new Boolean(first), new Boolean(fixedBegin), new Float(beginAfter)} ); try {
0882:                // Trace.print("computing interval from begins=" + beginInstanceTimes + ", ends=" + endInstanceTimes);
0883:                Iterator beginIterator = beginInstanceTimes.iterator();
0884:                Iterator endIterator = endInstanceTimes.iterator();
0885:                float parentSimpleDur = parent.getSimpleDur();
0886:                InstanceTime endInstanceTime = endIterator.hasNext() ? (InstanceTime) endIterator
0887:                        .next()
0888:                        : null;
0889:                boolean firstEnd = true;
0890:                InstanceTime beginInstanceTime = null;
0891:                InstanceTime nextBeginInstanceTime = null;
0892:                for (;;) {
0893:                    float tempBegin;
0894:                    if (fixedBegin) {
0895:                        tempBegin = beginAfter;
0896:                        while (beginIterator.hasNext()) {
0897:                            nextBeginInstanceTime = (InstanceTime) beginIterator
0898:                                    .next();
0899:                            if (nextBeginInstanceTime.getTime() > tempBegin) {
0900:                                break;
0901:                            }
0902:                        }
0903:                    } else {
0904:                        for (;;) {
0905:                            if (!beginIterator.hasNext()) {
0906:                                // ran out of begin values
0907:                                // Trace.print("returning null interval");
0908:                                return null;
0909:                            }
0910:                            beginInstanceTime = (InstanceTime) beginIterator
0911:                                    .next();
0912:                            tempBegin = beginInstanceTime.getTime();
0913:                            if (tempBegin >= beginAfter) {
0914:                                if (beginIterator.hasNext()) {
0915:                                    nextBeginInstanceTime = (InstanceTime) beginIterator
0916:                                            .next();
0917:                                }
0918:                                break;
0919:                            }
0920:                        }
0921:                    }
0922:                    if (tempBegin >= parentSimpleDur) {
0923:                        // the begin value is after the parent has ended
0924:                        // Trace.print("returning null interval");
0925:                        return null;
0926:                    }
0927:                    float tempEnd;
0928:                    if (endTimes.length == 0) {
0929:                        // no 'end' attribute specified
0930:                        tempEnd = tempBegin
0931:                                + getActiveDur(tempBegin, INDEFINITE);
0932:                        // Trace.print("no end specified, so tempEnd = " + tempEnd);
0933:                    } else {
0934:                        if (endInstanceTimes.isEmpty()) {
0935:                            tempEnd = UNRESOLVED;
0936:                        } else {
0937:                            tempEnd = endInstanceTime.getTime();
0938:                            if (first && !firstEnd && tempEnd == tempBegin
0939:                                    || !first && currentInterval != null
0940:                                    && tempEnd == currentInterval.getEnd()
0941:                                    && beginAfter >= tempEnd) {
0942:                                for (;;) {
0943:                                    if (!endIterator.hasNext()) {
0944:                                        if (endHasEventConditions()) {
0945:                                            tempEnd = UNRESOLVED;
0946:                                            break;
0947:                                        }
0948:                                        // Trace.print("returning null interval");
0949:                                        return null;
0950:                                    }
0951:                                    endInstanceTime = (InstanceTime) endIterator
0952:                                            .next();
0953:                                    tempEnd = endInstanceTime.getTime();
0954:                                    if (tempEnd > tempBegin) {
0955:                                        break;
0956:                                    }
0957:                                }
0958:                            }
0959:                            firstEnd = false;
0960:                            for (;;) {
0961:                                if (tempEnd >= tempBegin) {
0962:                                    break;
0963:                                }
0964:                                if (!endIterator.hasNext()) {
0965:                                    if (endHasEventConditions()) {
0966:                                        tempEnd = UNRESOLVED;
0967:                                        break;
0968:                                    }
0969:                                    // Trace.print("returning null interval");
0970:                                    return null;
0971:                                }
0972:                                endInstanceTime = (InstanceTime) endIterator
0973:                                        .next();
0974:                                tempEnd = endInstanceTime.getTime();
0975:                            }
0976:                        }
0977:                        float ad = getActiveDur(tempBegin, tempEnd);
0978:                        tempEnd = tempBegin + ad;
0979:                    }
0980:                    if (!first || tempEnd > 0 || tempBegin == 0 && tempEnd == 0
0981:                            || isUnresolved(tempEnd)) {
0982:                        // Trace.print("considering restart semantics");
0983:                        if (restartMode == RESTART_ALWAYS
0984:                                && nextBeginInstanceTime != null) {
0985:                            float nextBegin = nextBeginInstanceTime.getTime();
0986:                            // Trace.print("nextBegin == " + nextBegin);
0987:                            if (nextBegin < tempEnd || isUnresolved(tempEnd)) {
0988:                                tempEnd = nextBegin;
0989:                                endInstanceTime = nextBeginInstanceTime;
0990:                            }
0991:                        }
0992:                        Interval i = new Interval(tempBegin, tempEnd,
0993:                                beginInstanceTime, endInstanceTime);
0994:                        // Trace.print("returning interval: " + i);
0995:                        return i;
0996:                    }
0997:                    if (fixedBegin) {
0998:                        // Trace.print("returning null interval");
0999:                        return null;
1000:                    }
1001:                    beginAfter = tempEnd;
1002:                }
1003:                // } finally { Trace.exit(); }
1004:            }
1005:
1006:            /**
1007:             * Resets this element.
1008:             */
1009:            protected void reset(boolean clearCurrentBegin) {
1010:                Iterator i = beginInstanceTimes.iterator();
1011:                while (i.hasNext()) {
1012:                    InstanceTime it = (InstanceTime) i.next();
1013:                    if (it.getClearOnReset()
1014:                            && (clearCurrentBegin || currentInterval == null || currentInterval
1015:                                    .getBeginInstanceTime() != it)) {
1016:                        i.remove();
1017:                    }
1018:                }
1019:                i = endInstanceTimes.iterator();
1020:                while (i.hasNext()) {
1021:                    InstanceTime it = (InstanceTime) i.next();
1022:                    if (it.getClearOnReset()) {
1023:                        i.remove();
1024:                    }
1025:                }
1026:                if (isFrozen) {
1027:                    removeFill();
1028:                }
1029:                currentRepeatIteration = 0;
1030:                lastRepeatTime = UNRESOLVED;
1031:                isActive = false;
1032:                isFrozen = false;
1033:                lastSampleTime = UNRESOLVED;
1034:                // XXX should reconvert resolved syncbase/wallclock/media-marker time
1035:                //     instances into the parent simple timespace
1036:            }
1037:
1038:            /**
1039:             * Parses the animation attributes for this timed element.
1040:             */
1041:            public void parseAttributes(String begin, String dur, String end,
1042:                    String min, String max, String repeatCount,
1043:                    String repeatDur, String fill, String restart) {
1044:                if (!hasParsed) {
1045:                    parseBegin(begin);
1046:                    parseDur(dur);
1047:                    parseEnd(end);
1048:                    parseMin(min);
1049:                    parseMax(max);
1050:                    if (this .min > this .max) {
1051:                        this .min = 0f;
1052:                        this .max = INDEFINITE;
1053:                    }
1054:                    parseRepeatCount(repeatCount);
1055:                    parseRepeatDur(repeatDur);
1056:                    parseFill(fill);
1057:                    parseRestart(restart);
1058:                    hasParsed = true;
1059:                }
1060:            }
1061:
1062:            /**
1063:             * Parses a new 'begin' attribute.
1064:             */
1065:            protected void parseBegin(String begin) {
1066:                try {
1067:                    if (begin.length() == 0) {
1068:                        begin = SMIL_BEGIN_DEFAULT_VALUE;
1069:                    }
1070:                    beginTimes = TimingSpecifierListProducer
1071:                            .parseTimingSpecifierList(TimedElement.this , true,
1072:                                    begin, root.useSVG11AccessKeys,
1073:                                    root.useSVG12AccessKeys);
1074:                } catch (ParseException ex) {
1075:                    throw createException("attribute.malformed", new Object[] {
1076:                            null, SMIL_BEGIN_ATTRIBUTE });
1077:                }
1078:            }
1079:
1080:            /**
1081:             * Parses a new 'dur' attribute.
1082:             */
1083:            protected void parseDur(String dur) {
1084:                if (dur.equals(SMIL_MEDIA_VALUE)) {
1085:                    durMedia = true;
1086:                    simpleDur = UNRESOLVED;
1087:                } else {
1088:                    durMedia = false;
1089:                    if (dur.length() == 0 || dur.equals(SMIL_INDEFINITE_VALUE)) {
1090:                        simpleDur = INDEFINITE;
1091:                    } else {
1092:                        try {
1093:                            simpleDur = parseClockValue(dur, false);
1094:                        } catch (ParseException e) {
1095:                            throw createException("attribute.malformed",
1096:                                    new Object[] { null, SMIL_DUR_ATTRIBUTE });
1097:                        }
1098:                        if (simpleDur < 0) {
1099:                            simpleDur = INDEFINITE;
1100:                        }
1101:                    }
1102:                }
1103:            }
1104:
1105:            /**
1106:             * Parses a clock value or offset and returns it as a float.
1107:             */
1108:            protected float parseClockValue(String s, boolean parseOffset)
1109:                    throws ParseException {
1110:                ClockParser p = new ClockParser(parseOffset);
1111:                class Handler implements  ClockHandler {
1112:                    protected float v = 0;
1113:
1114:                    public void clockValue(float newClockValue) {
1115:                        v = newClockValue;
1116:                    }
1117:                }
1118:
1119:                Handler h = new Handler();
1120:                p.setClockHandler(h);
1121:                p.parse(s);
1122:                return h.v;
1123:            }
1124:
1125:            /**
1126:             * Parses a new 'end' attribute.
1127:             */
1128:            protected void parseEnd(String end) {
1129:                try {
1130:                    endTimes = TimingSpecifierListProducer
1131:                            .parseTimingSpecifierList(TimedElement.this , false,
1132:                                    end, root.useSVG11AccessKeys,
1133:                                    root.useSVG12AccessKeys);
1134:                } catch (ParseException ex) {
1135:                    throw createException("attribute.malformed", new Object[] {
1136:                            null, SMIL_END_ATTRIBUTE });
1137:                }
1138:            }
1139:
1140:            /**
1141:             * Parses a new 'min' attribute.
1142:             */
1143:            protected void parseMin(String min) {
1144:                if (min.equals(SMIL_MEDIA_VALUE)) {
1145:                    this .min = 0;
1146:                    minMedia = true;
1147:                } else {
1148:                    minMedia = false;
1149:                    if (min.length() == 0) {
1150:                        this .min = 0;
1151:                    } else {
1152:                        try {
1153:                            this .min = parseClockValue(min, false);
1154:                        } catch (ParseException ex) {
1155:                            throw createException("attribute.malformed",
1156:                                    new Object[] { null, SMIL_MIN_ATTRIBUTE });
1157:                        }
1158:                        if (this .min < 0) {
1159:                            this .min = 0;
1160:                        }
1161:                    }
1162:                }
1163:            }
1164:
1165:            /**
1166:             * Parses a new 'max' attribute.
1167:             */
1168:            protected void parseMax(String max) {
1169:                if (max.equals(SMIL_MEDIA_VALUE)) {
1170:                    this .max = INDEFINITE;
1171:                    maxMedia = true;
1172:                } else {
1173:                    maxMedia = false;
1174:                    if (max.length() == 0 || max.equals(SMIL_INDEFINITE_VALUE)) {
1175:                        this .max = INDEFINITE;
1176:                    } else {
1177:                        try {
1178:                            this .max = parseClockValue(max, false);
1179:                        } catch (ParseException ex) {
1180:                            throw createException("attribute.malformed",
1181:                                    new Object[] { null, SMIL_MAX_ATTRIBUTE });
1182:                        }
1183:                        if (this .max < 0) {
1184:                            this .max = 0;
1185:                        }
1186:                    }
1187:                }
1188:            }
1189:
1190:            /**
1191:             * Parses a new 'repeatCount' attribute.
1192:             */
1193:            protected void parseRepeatCount(String repeatCount) {
1194:                if (repeatCount.length() == 0) {
1195:                    this .repeatCount = UNRESOLVED;
1196:                } else if (repeatCount.equals(SMIL_INDEFINITE_VALUE)) {
1197:                    this .repeatCount = INDEFINITE;
1198:                } else {
1199:                    try {
1200:                        this .repeatCount = Float.parseFloat(repeatCount);
1201:                        if (this .repeatCount > 0) {
1202:                            return;
1203:                        }
1204:                    } catch (NumberFormatException ex) {
1205:                        throw createException("attribute.malformed",
1206:                                new Object[] { null,
1207:                                        SMIL_REPEAT_COUNT_ATTRIBUTE });
1208:                    }
1209:                }
1210:            }
1211:
1212:            /**
1213:             * Parses a new 'repeatDur' attribute.
1214:             */
1215:            protected void parseRepeatDur(String repeatDur) {
1216:                try {
1217:                    if (repeatDur.length() == 0) {
1218:                        this .repeatDur = UNRESOLVED;
1219:                    } else if (repeatDur.equals(SMIL_INDEFINITE_VALUE)) {
1220:                        this .repeatDur = INDEFINITE;
1221:                    } else {
1222:                        this .repeatDur = parseClockValue(repeatDur, false);
1223:                    }
1224:                } catch (ParseException ex) {
1225:                    throw createException("attribute.malformed", new Object[] {
1226:                            null, SMIL_REPEAT_DUR_ATTRIBUTE });
1227:                }
1228:            }
1229:
1230:            /**
1231:             * Parses a new 'fill' attribute.
1232:             */
1233:            protected void parseFill(String fill) {
1234:                if (fill.length() == 0 || fill.equals(SMIL_REMOVE_VALUE)) {
1235:                    fillMode = FILL_REMOVE;
1236:                } else if (fill.equals(SMIL_FREEZE_VALUE)) {
1237:                    fillMode = FILL_FREEZE;
1238:                } else {
1239:                    throw createException("attribute.malformed", new Object[] {
1240:                            null, SMIL_FILL_ATTRIBUTE });
1241:                }
1242:            }
1243:
1244:            /**
1245:             * Parses a new 'restart' attribute.
1246:             */
1247:            protected void parseRestart(String restart) {
1248:                if (restart.length() == 0 || restart.equals(SMIL_ALWAYS_VALUE)) {
1249:                    restartMode = RESTART_ALWAYS;
1250:                } else if (restart.equals(SMIL_WHEN_NOT_ACTIVE_VALUE)) {
1251:                    restartMode = RESTART_WHEN_NOT_ACTIVE;
1252:                } else if (restart.equals(SMIL_NEVER_VALUE)) {
1253:                    restartMode = RESTART_NEVER;
1254:                } else {
1255:                    throw createException("attribute.malformed", new Object[] {
1256:                            null, SMIL_RESTART_ATTRIBUTE });
1257:                }
1258:            }
1259:
1260:            /**
1261:             * Initializes this timed element.
1262:             */
1263:            public void initialize() {
1264:                for (int i = 0; i < beginTimes.length; i++) {
1265:                    beginTimes[i].initialize();
1266:                }
1267:                for (int i = 0; i < endTimes.length; i++) {
1268:                    endTimes[i].initialize();
1269:                }
1270:            }
1271:
1272:            /**
1273:             * Deinitializes this timed element.
1274:             */
1275:            public void deinitialize() {
1276:                for (int i = 0; i < beginTimes.length; i++) {
1277:                    beginTimes[i].deinitialize();
1278:                }
1279:                for (int i = 0; i < endTimes.length; i++) {
1280:                    beginTimes[i].deinitialize();
1281:                }
1282:            }
1283:
1284:            /**
1285:             * Adds a time to the begin time instance list that will cause
1286:             * the element to begin immediately (if restart semantics allow it).
1287:             */
1288:            public void beginElement() {
1289:                beginElement(0);
1290:            }
1291:
1292:            /**
1293:             * Adds a time to the begin time instance list that will cause
1294:             * the element to begin at some offset to the current time (if restart
1295:             * semantics allow it).
1296:             */
1297:            public void beginElement(float offset) {
1298:                float t = root.convertWallclockTime(Calendar.getInstance());
1299:                InstanceTime it = new InstanceTime(null, t + offset, null, true);
1300:                addInstanceTime(it, true);
1301:            }
1302:
1303:            /**
1304:             * Adds a time to the end time instance list that will cause
1305:             * the element to end immediately (if restart semantics allow it).
1306:             */
1307:            public void endElement() {
1308:                endElement(0);
1309:            }
1310:
1311:            /**
1312:             * Adds a time to the end time instance list that will cause
1313:             * the element to end at some offset to the current time (if restart
1314:             * semantics allow it).
1315:             */
1316:            public void endElement(float offset) {
1317:                float t = root.convertWallclockTime(Calendar.getInstance());
1318:                InstanceTime it = new InstanceTime(null, t + offset, null, true);
1319:                addInstanceTime(it, false);
1320:            }
1321:
1322:            /**
1323:             * Returns the last sample time of this element, in local active time.
1324:             */
1325:            public float getLastSampleTime() {
1326:                return lastSampleTime;
1327:            }
1328:
1329:            /**
1330:             * Returns the begin time of the current interval, in parent simple time,
1331:             * or <code>Float.NaN</code> if the element is not active.
1332:             */
1333:            public float getCurrentBeginTime() {
1334:                float begin;
1335:                if (currentInterval == null
1336:                        || (begin = currentInterval.getBegin()) < lastSampleTime) {
1337:                    return Float.NaN;
1338:                }
1339:                return begin;
1340:            }
1341:
1342:            /**
1343:             * Returns whether this element can be begun or restarted currently.
1344:             */
1345:            public boolean canBegin() {
1346:                return currentInterval == null || isActive
1347:                        && restartMode != RESTART_NEVER;
1348:            }
1349:
1350:            /**
1351:             * Returns whether this element can be ended currently.
1352:             */
1353:            public boolean canEnd() {
1354:                return isActive;
1355:            }
1356:
1357:            /**
1358:             * Fires a TimeEvent of the given type on this element.
1359:             * @param eventType the type of TimeEvent ("beginEvent", "endEvent"
1360:             *                  or "repeatEvent").
1361:             * @param time the timestamp of the event object
1362:             * @param detail the repeat iteration, if this event is a repeat event
1363:             */
1364:            protected void fireTimeEvent(String eventType, float time,
1365:                    int detail) {
1366:                Calendar t = (Calendar) root.getDocumentBeginTime().clone();
1367:                t.add(Calendar.MILLISECOND, (int) Math.round(time * 1e3));
1368:                fireTimeEvent(eventType, t, detail);
1369:            }
1370:
1371:            /**
1372:             * Invoked by a {@link TimingSpecifier} to indicate that an event occurred
1373:             * that would create a new instance time for this timed element.  These
1374:             * will be processed at the beginning of the next tick.
1375:             */
1376:            void eventOccurred(TimingSpecifier t, Event e) {
1377:                Set ts = (HashSet) handledEvents.get(e);
1378:                if (ts == null) {
1379:                    ts = new HashSet();
1380:                    handledEvents.put(e, ts);
1381:                }
1382:                ts.add(t);
1383:                root.currentIntervalWillUpdate();
1384:            }
1385:
1386:            /**
1387:             * Fires a TimeEvent of the given type on this element.
1388:             * @param eventType the type of TimeEvent ("beginEvent", "endEvent"
1389:             *                  or "repeatEvent").
1390:             * @param time the timestamp of the event object
1391:             */
1392:            protected abstract void fireTimeEvent(String eventType,
1393:                    Calendar time, int detail);
1394:
1395:            /**
1396:             * Invoked to indicate this timed element became active at the
1397:             * specified time.
1398:             * @param begin the time the element became active, in document simple time
1399:             */
1400:            protected abstract void toActive(float begin);
1401:
1402:            /**
1403:             * Invoked to indicate that this timed element became inactive.
1404:             * @param stillActive if true, indicates that the element is still actually
1405:             *                    active, but between the end of the computed repeat
1406:             *                    duration and the end of the interval
1407:             * @param isFrozen whether the element is frozen or not
1408:             */
1409:            protected abstract void toInactive(boolean stillActive,
1410:                    boolean isFrozen);
1411:
1412:            /**
1413:             * Invoked to indicate that this timed element has had its fill removed.
1414:             */
1415:            protected abstract void removeFill();
1416:
1417:            /**
1418:             * Invoked to indicate that this timed element has been sampled at the
1419:             * given time.
1420:             * @param simpleTime the sample time in local simple time
1421:             * @param simpleDur the simple duration of the element
1422:             * @param repeatIteration the repeat iteration during which the element
1423:             *                        was sampled
1424:             */
1425:            protected abstract void sampledAt(float simpleTime,
1426:                    float simpleDur, int repeatIteration);
1427:
1428:            /**
1429:             * Invoked to indicate that this timed element has been sampled
1430:             * at the end of its active time, at an integer multiple of the
1431:             * simple duration.  This is the "last" value that will be used
1432:             * for filling, which cannot be sampled normally.
1433:             */
1434:            protected abstract void sampledLastValue(int repeatIteration);
1435:
1436:            /**
1437:             * Returns the timed element with the given ID.
1438:             */
1439:            protected abstract TimedElement getTimedElementById(String id);
1440:
1441:            /**
1442:             * Returns the event target with the given ID.
1443:             */
1444:            protected abstract EventTarget getEventTargetById(String id);
1445:
1446:            /**
1447:             * Returns the event target that should be listened to for
1448:             * access key events.
1449:             */
1450:            protected abstract EventTarget getRootEventTarget();
1451:
1452:            /**
1453:             * Returns the DOM element that corresponds to this timed element, if
1454:             * such a DOM element exists.
1455:             */
1456:            public abstract Element getElement();
1457:
1458:            /**
1459:             * Returns the target of this animation as an {@link EventTarget}.  Used
1460:             * for eventbase timing specifiers where the element ID is omitted.
1461:             */
1462:            protected abstract EventTarget getAnimationEventTarget();
1463:
1464:            /**
1465:             * Returns whether this timed element comes before the given timed element
1466:             * in document order.
1467:             */
1468:            public abstract boolean isBefore(TimedElement other);
1469:
1470:            /**
1471:             * Returns whether this timed element is for a constant animation (i.e., a
1472:             * 'set' animation.
1473:             */
1474:            protected abstract boolean isConstantAnimation();
1475:
1476:            /**
1477:             * Creates and returns a new {@link AnimationException}.
1478:             */
1479:            public AnimationException createException(String code,
1480:                    Object[] params) {
1481:                Element e = getElement();
1482:                if (e != null) {
1483:                    params[0] = e.getNodeName();
1484:                }
1485:                return new AnimationException(this , code, params);
1486:            }
1487:
1488:            /**
1489:             * The error messages bundle class name.
1490:             */
1491:            protected static final String RESOURCES = "org.apache.batik.anim.resources.Messages";
1492:
1493:            /**
1494:             * The localizable support for the error messages.
1495:             */
1496:            protected static LocalizableSupport localizableSupport = new LocalizableSupport(
1497:                    RESOURCES, TimedElement.class.getClassLoader());
1498:
1499:            /**
1500:             * Implements {@link org.apache.batik.i18n.Localizable#setLocale(java.util.Locale)}.
1501:             */
1502:            public static void setLocale(Locale l) {
1503:                localizableSupport.setLocale(l);
1504:            }
1505:
1506:            /**
1507:             * Implements {@link org.apache.batik.i18n.Localizable#getLocale()}.
1508:             */
1509:            public static Locale getLocale() {
1510:                return localizableSupport.getLocale();
1511:            }
1512:
1513:            /**
1514:             * Implements {@link
1515:             * org.apache.batik.i18n.Localizable#formatMessage(String,Object[])}.
1516:             */
1517:            public static String formatMessage(String key, Object[] args)
1518:                    throws MissingResourceException {
1519:                return localizableSupport.formatMessage(key, args);
1520:            }
1521:
1522:            /**
1523:             * Returns a string representation of the given time value.
1524:             */
1525:            public static String toString(float time) {
1526:                if (Float.isNaN(time)) {
1527:                    return "UNRESOLVED";
1528:                } else if (time == Float.POSITIVE_INFINITY) {
1529:                    return "INDEFINITE";
1530:                } else {
1531:                    return Float.toString(time);
1532:                }
1533:            }
1534:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.