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());
}
Exemple #4
0
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();
    }
}
Exemple #5
0
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();
    }
}
Exemple #6
0
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;
}
Exemple #7
0
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();
}