Exemple #1
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();
}
void SMILTimeContainer::updateAnimations(SMILTime elapsed, bool seekToTime)
{
    SMILTime earliersFireTime = SMILTime::unresolved();

    Vector<SVGSMILElement*> toAnimate;
    copyToVector(m_scheduledAnimations, toAnimate);

    // 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 pair<SVGElement*, QualifiedName> ElementAttributePair;
    typedef HashMap<ElementAttributePair, RefPtr<SVGSMILElement> > ResultElementMap;
    ResultElementMap resultsElements;
    HashSet<SVGSMILElement*> contributingElements;
    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 and contributes to a particular element/attribute pair.
        ElementAttributePair key(targetElement, attributeName); 
        SVGSMILElement* resultElement = resultsElements.get(key).get();
        bool accumulatedResultElement = false;
        if (!resultElement) {
            if (!animation->hasValidAttributeType())
                continue;
            resultElement = animation;
            resultsElements.add(key, resultElement);
            accumulatedResultElement = true;
        }

        // This will calculate the contribution from the animation and add it to the resultsElement.
        if (animation->progress(elapsed, resultElement, seekToTime))
            contributingElements.add(resultElement);
        else if (accumulatedResultElement)
            resultsElements.remove(key);

        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) {
        SVGSMILElement* animation = it->second.get();
        if (contributingElements.contains(animation))
            animationsToApply.append(animation);
    }

    unsigned animationsToApplySize = animationsToApply.size();
    if (!animationsToApplySize) {
        startTimer(earliersFireTime, animationFrameDelay);
        return;
    }

    // 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 i = 0; i < animationsToApplySize; ++i)
        animationsToApply[i]->applyResultsToTarget();

    startTimer(earliersFireTime, animationFrameDelay);
    Document::updateStyleForAllDocuments();
}