SMILTime SVGSMILElement::parseClockValue(const String& data) { if (data.isNull()) return SMILTime::unresolved(); String parse = data.stripWhiteSpace(); DEFINE_STATIC_LOCAL(const AtomicString, indefiniteValue, ("indefinite")); if (parse == indefiniteValue) return SMILTime::indefinite(); double result = 0; bool ok; size_t doublePointOne = parse.find(':'); size_t doublePointTwo = parse.find(':', doublePointOne + 1); if (doublePointOne == 2 && doublePointTwo == 5 && parse.length() >= 8) { result += parse.substring(0, 2).toUIntStrict(&ok) * 60 * 60; if (!ok) return SMILTime::unresolved(); result += parse.substring(3, 2).toUIntStrict(&ok) * 60; if (!ok) return SMILTime::unresolved(); result += parse.substring(6).toDouble(&ok); } else if (doublePointOne == 2 && doublePointTwo == kNotFound && parse.length() >= 5) { result += parse.substring(0, 2).toUIntStrict(&ok) * 60; if (!ok) return SMILTime::unresolved(); result += parse.substring(3).toDouble(&ok); } else return parseOffsetValue(parse); if (!ok || !SMILTime(result).isFinite()) return SMILTime::unresolved(); return result; }
void SMILTimeContainer::begin() { RELEASE_ASSERT(!m_beginTime); if (!handleAnimationPolicy(RestartOnceTimerIfNotPaused)) return; double now = currentTime(); // If 'm_presetStartTime' is set, the timeline was modified via setElapsed() before the document began. // In this case pass on 'seekToTime=true' to updateAnimations(). m_beginTime = now - m_presetStartTime; #if !ENABLE(OILPAN) DiscardScope discardScope(m_ownerSVGElement); #endif SMILTime earliestFireTime = updateAnimations(SMILTime(m_presetStartTime), m_presetStartTime ? true : false); m_presetStartTime = 0; if (m_pauseTime) { m_pauseTime = now; // If updateAnimations() caused new syncbase instance to be generated, // we don't want to cancel those. Excepting that, no frame should've // been scheduled at this point. ASSERT(m_frameSchedulingState == Idle || m_frameSchedulingState == SynchronizeAnimations); } else if (!hasPendingSynchronization()) { ASSERT(isTimelineRunning()); // If the timeline is running, and there's pending animation updates, // always perform the first update after the timeline was started using // the wake-up mechanism. if (earliestFireTime.isFinite()) { SMILTime delay = earliestFireTime - elapsed(); scheduleWakeUp(std::max(initialFrameDelay, delay.value()), SynchronizeAnimations); } } }
void SMILTimeContainer::scheduleAnimationFrame(SMILTime fireTime) { if (!isTimelineRunning()) return; if (!fireTime.isFinite()) return; SMILTime delay = max(fireTime - elapsed(), SMILTime(animationFrameDelay)); m_timer.startOneShot(delay.value()); }
void SMILTimeContainer::begin() { ASSERT(!m_beginTime); double now = currentTime(); m_beginTime = now - m_presetStartTime; updateAnimations(SMILTime(m_presetStartTime)); m_presetStartTime = 0; if (m_pauseTime) { m_pauseTime = now; m_timer.stop(); } }
void SMILTimeContainer::begin() { ASSERT(!m_beginTime); double now = currentTime(); // If 'm_presetStartTime' is set, the timeline was modified via setElapsed() before the document began. // In this case pass on 'seekToTime=true' to updateAnimations(). m_beginTime = now - m_presetStartTime; updateAnimations(SMILTime(m_presetStartTime), m_presetStartTime ? true : false); m_presetStartTime = 0; if (m_pauseTime) { m_pauseTime = now; m_timer.stop(); } }
SMILTime SVGSMILElement::parseOffsetValue(const String& data) { bool ok; double result = 0; String parse = data.stripWhiteSpace(); if (parse.endsWith('h')) result = parse.left(parse.length() - 1).toDouble(&ok) * 60 * 60; else if (parse.endsWith("min")) result = parse.left(parse.length() - 3).toDouble(&ok) * 60; else if (parse.endsWith("ms")) result = parse.left(parse.length() - 2).toDouble(&ok) / 1000; else if (parse.endsWith('s')) result = parse.left(parse.length() - 1).toDouble(&ok); else result = parse.toDouble(&ok); if (!ok || !SMILTime(result).isFinite()) return SMILTime::unresolved(); return result; }
void SMILTimeContainer::updateAnimations(SMILTime elapsed, double nextManualSampleTime, const String& nextSamplingTarget) { SMILTime earliersFireTime = SMILTime::unresolved(); Vector<SVGSMILElement*> toAnimate; copyToVector(m_scheduledAnimations, toAnimate); if (nextManualSampleTime) { SMILTime samplingDiff; for (unsigned n = 0; n < toAnimate.size(); ++n) { SVGSMILElement* animation = toAnimate[n]; ASSERT(animation->timeContainer() == this); SVGElement* targetElement = animation->targetElement(); // FIXME: This should probably be using getIdAttribute instead of idForStyleResolution. if (!targetElement || !targetElement->hasID() || targetElement->idForStyleResolution() != nextSamplingTarget) continue; samplingDiff = animation->intervalBegin(); break; } elapsed = SMILTime(nextManualSampleTime) + samplingDiff; } // Sort according to priority. Elements with later begin time have higher priority. // In case of a tie, document order decides. // FIXME: This should also consider timing relationships between the elements. Dependents // have higher priority. sortByPriority(toAnimate, elapsed); // Calculate animation contributions. typedef HashMap<ElementAttributePair, RefPtr<SVGSMILElement> > ResultElementMap; ResultElementMap resultsElements; for (unsigned n = 0; n < toAnimate.size(); ++n) { SVGSMILElement* animation = toAnimate[n]; ASSERT(animation->timeContainer() == this); SVGElement* targetElement = animation->targetElement(); if (!targetElement) continue; QualifiedName attributeName = animation->attributeName(); if (attributeName == anyQName()) { if (animation->hasTagName(SVGNames::animateMotionTag)) attributeName = SVGNames::animateMotionTag; else continue; } // Results are accumulated to the first animation that animates a particular element/attribute pair. ElementAttributePair key(targetElement, attributeName); SVGSMILElement* resultElement = resultsElements.get(key).get(); if (!resultElement) { if (!animation->hasValidAttributeType()) continue; resultElement = animation; resultElement->resetToBaseValue(baseValueFor(key)); resultsElements.add(key, resultElement); } // This will calculate the contribution from the animation and add it to the resultsElement. animation->progress(elapsed, resultElement); SMILTime nextFireTime = animation->nextProgressTime(); if (nextFireTime.isFinite()) earliersFireTime = min(nextFireTime, earliersFireTime); } Vector<SVGSMILElement*> animationsToApply; ResultElementMap::iterator end = resultsElements.end(); for (ResultElementMap::iterator it = resultsElements.begin(); it != end; ++it) animationsToApply.append(it->second.get()); // Sort <animateTranform> to be the last one to be applied. <animate> may change transform attribute as // well (directly or indirectly by modifying <use> x/y) and this way transforms combine properly. sortByApplyOrder(animationsToApply); // Apply results to target elements. for (unsigned n = 0; n < animationsToApply.size(); ++n) animationsToApply[n]->applyResultsToTarget(); startTimer(earliersFireTime, animationFrameDelay); Document::updateStyleForAllDocuments(); }