in batik-anim/src/main/java/org/apache/batik/anim/timing/TimedElement.java [601:833]
protected float sampleAt(float parentSimpleTime, boolean hyperlinking) {
// Trace.enter(this, "sampleAt", new Object[] { Float.valueOf(parentSimpleTime) } ); try {
isSampling = true;
float time = parentSimpleTime; // No time containers in SVG.
// First, process any events that occurred since the last sampling,
// taking into account event sensitivity.
for (Object o : handledEvents.entrySet()) {
Map.Entry e = (Map.Entry) o;
Event evt = (Event) e.getKey();
Set ts = (Set) e.getValue();
Iterator j = ts.iterator();
boolean hasBegin = false, hasEnd = false;
while (j.hasNext() && !(hasBegin && hasEnd)) {
EventLikeTimingSpecifier t =
(EventLikeTimingSpecifier) j.next();
if (t.isBegin()) {
hasBegin = true;
} else {
hasEnd = true;
}
}
boolean useBegin, useEnd;
if (hasBegin && hasEnd) {
useBegin = !isActive || restartMode == RESTART_ALWAYS;
useEnd = !useBegin;
} else if (hasBegin && (!isActive ||
restartMode == RESTART_ALWAYS)) {
useBegin = true;
useEnd = false;
} else if (hasEnd && isActive) {
useBegin = false;
useEnd = true;
} else {
continue;
}
j = ts.iterator();
while (j.hasNext()) {
EventLikeTimingSpecifier t =
(EventLikeTimingSpecifier) j.next();
boolean isBegin = t.isBegin();
if (isBegin && useBegin || !isBegin && useEnd) {
t.resolve(evt);
shouldUpdateCurrentInterval = true;
}
}
}
handledEvents.clear();
// Now process intervals.
if (currentInterval != null) {
float begin = currentInterval.getBegin();
if (lastSampleTime < begin && time >= begin) {
if (!isActive) {
toActive(begin);
}
isActive = true;
isFrozen = false;
lastRepeatTime = begin;
fireTimeEvent
(SMIL_BEGIN_EVENT_NAME, currentInterval.getBegin(), 0);
}
}
// For each sample, we might need to update the current interval's
// begin and end times, or end the current interval and compute
// a new one.
boolean hasEnded = currentInterval != null
&& time >= currentInterval.getEnd();
// Fire any repeat events that should have been fired since the
// last sample.
if (currentInterval != null) {
float begin = currentInterval.getBegin();
if (time >= begin) {
float d = getSimpleDur();
while (time - lastRepeatTime >= d
&& lastRepeatTime + d < begin + repeatDuration) {
lastRepeatTime += d;
currentRepeatIteration++;
fireTimeEvent(root.getRepeatEventName(), lastRepeatTime,
currentRepeatIteration);
}
}
}
// Trace.print("begin loop");
float dependentMinTime = Float.POSITIVE_INFINITY;
if (hyperlinking) {
shouldUpdateCurrentInterval = true;
}
while (shouldUpdateCurrentInterval || hasEnded) {
if (hasEnded) {
// previousIntervals.add(currentInterval);
previousInterval = currentInterval;
isActive = false;
isFrozen = fillMode == FILL_FREEZE;
toInactive(false, isFrozen);
fireTimeEvent(SMIL_END_EVENT_NAME, currentInterval.getEnd(), 0);
}
boolean first =
// currentInterval == null && previousIntervals.isEmpty();
currentInterval == null && previousInterval == null;
if (currentInterval != null && hyperlinking) {
// Hyperlinking, so remove the current interval and force a new
// one to be computed.
isActive = false;
isFrozen = false;
toInactive(false, false);
currentInterval = null;
// fireTimeEvent(SMIL_END_EVENT_NAME, currentInterval.getEnd(), 0);
}
if (currentInterval == null || hasEnded) {
if (first || hyperlinking || restartMode != RESTART_NEVER) {
float beginAfter;
boolean incl = true;
if (first || hyperlinking) {
beginAfter = Float.NEGATIVE_INFINITY;
} else {
// beginAfter = ((Interval) previousIntervals.getLast()).getEnd();
beginAfter = previousInterval.getEnd();
incl = beginAfter != previousInterval.getBegin();
}
Interval interval =
computeInterval(first, false, beginAfter, incl);
if (interval == null) {
currentInterval = null;
} else {
float dmt = selectNewInterval(time, interval);
if (dmt < dependentMinTime) {
dependentMinTime = dmt;
}
}
} else {
currentInterval = null;
}
} else {
float currentBegin = currentInterval.getBegin();
if (currentBegin > time) {
// Interval hasn't started yet.
float beginAfter;
boolean incl = true;
// if (previousIntervals.isEmpty()) {
if (previousInterval == null) {
beginAfter = Float.NEGATIVE_INFINITY;
} else {
// beginAfter = ((Interval) previousIntervals.getLast()).getEnd();
beginAfter = previousInterval.getEnd();
incl = beginAfter != previousInterval.getBegin();
}
Interval interval =
computeInterval(false, false, beginAfter, incl);
float dmt = notifyRemoveInterval(currentInterval);
if (dmt < dependentMinTime) {
dependentMinTime = dmt;
}
if (interval == null) {
currentInterval = null;
} else {
dmt = selectNewInterval(time, interval);
if (dmt < dependentMinTime) {
dependentMinTime = dmt;
}
}
} else {
// Interval has already started.
Interval interval =
computeInterval(false, true, currentBegin, true);
float newEnd = interval.getEnd();
if (currentInterval.getEnd() != newEnd) {
float dmt =
currentInterval.setEnd
(newEnd, interval.getEndInstanceTime());
if (dmt < dependentMinTime) {
dependentMinTime = dmt;
}
}
}
}
shouldUpdateCurrentInterval = false;
hyperlinking = false;
hasEnded = currentInterval != null && time >= currentInterval.getEnd();
}
// Trace.print("end loop");
float d = getSimpleDur();
if (isActive && !isFrozen) {
if (time - currentInterval.getBegin() >= repeatDuration) {
// Trace.print("element between repeat and active duration");
isFrozen = fillMode == FILL_FREEZE;
toInactive(true, isFrozen);
} else {
// Trace.print("element active, sampling at simple time " + (time - lastRepeatTime));
sampledAt(time - lastRepeatTime, d, currentRepeatIteration);
}
}
if (isFrozen) {
float t;
boolean atLast;
if (isActive) {
t = currentInterval.getBegin() + repeatDuration - lastRepeatTime;
atLast = lastRepeatTime + d == currentInterval.getBegin() + repeatDuration; // cam, given that d can
} else { // be infinite, nan or value
// Interval previousInterval = (Interval) previousIntervals.getLast(); // does this always make sense?
t = previousInterval.getEnd() - lastRepeatTime; // at least i would use >=
atLast = lastRepeatTime + d == previousInterval.getEnd(); // <- same here
}
if (atLast) {
// Trace.print("element frozen" + (isActive ? " (but still active)" : "") + ", sampling last value");
sampledLastValue(currentRepeatIteration);
} else {
// Trace.print("element frozen" + (isActive ? " (but still active)" : "") + ", sampling at simple time " + (t % d));
sampledAt(t % d, d, currentRepeatIteration);
}
} else if (!isActive) {
// Trace.print("element not sampling");
}
isSampling = false;
lastSampleTime = time;
if (currentInterval != null) {
float t = currentInterval.getBegin() - time;
if (t <= 0) {
t = isConstantAnimation() || isFrozen ? currentInterval.getEnd() - time : 0;
}
if (dependentMinTime < t) {
return dependentMinTime;
}
return t;
}
return dependentMinTime;
// } finally { Trace.exit(); }
}