Example #1
0
void SVGSMILElement::connectConditions()
{
    if (m_conditionsConnected)
        disconnectConditions();
    m_conditionsConnected = true;
    for (unsigned n = 0; n < m_conditions.size(); ++n) {
        Condition& condition = m_conditions[n];
        if (condition.m_type == Condition::EventBase) {
            ASSERT(!condition.m_syncbase);
            Element* eventBase = eventBaseFor(condition);
            if (!eventBase)
                continue;
            ASSERT(!condition.m_eventListener);
            condition.m_eventListener = ConditionEventListener::create(this, &condition);
            eventBase->addEventListener(condition.m_name, condition.m_eventListener, false);
        } else if (condition.m_type == Condition::Syncbase) {
            ASSERT(!condition.m_baseID.isEmpty());
            condition.m_syncbase = treeScope()->getElementById(condition.m_baseID);
            if (!isSMILElement(condition.m_syncbase.get())) {
                condition.m_syncbase = 0;
                continue;
            }
            SVGSMILElement* syncbase = static_cast<SVGSMILElement*>(condition.m_syncbase.get());
            syncbase->addTimeDependent(this);
        }
    }
}
Example #2
0
void SVGAElement::defaultEventHandler(Event* evt)
{
    if (isLink() && (evt->type() == clickEvent || (evt->type() == keydownEvent && focused()))) {
        MouseEvent* e = 0;
        if (evt->type() == clickEvent && evt->isMouseEvent())
            e = static_cast<MouseEvent*>(evt);
        
        KeyboardEvent* k = 0;
        if (evt->type() == keydownEvent && evt->isKeyboardEvent())
            k = static_cast<KeyboardEvent*>(evt);
        
        if (e && e->button() == RightButton) {
            SVGStyledTransformableElement::defaultEventHandler(evt);
            return;
        }
        
        if (k) {
            if (k->keyIdentifier() != "Enter") {
                SVGStyledTransformableElement::defaultEventHandler(evt);
                return;
            }
            evt->setDefaultHandled();
            dispatchSimulatedClick(evt);
            return;
        }
        
        String target = this->target();
        if (e && e->button() == MiddleButton)
            target = "_blank";
        else if (target.isEmpty()) // if target is empty, default to "_self" or use xlink:target if set
            target = (getAttribute(XLinkNames::showAttr) == "new") ? "_blank" : "_self";

        if (!evt->defaultPrevented()) {
            String url = parseURL(href());
#if ENABLE(SVG_ANIMATION)
            if (url.startsWith("#")) {
                Element* targetElement = document()->getElementById(url.substring(1));
                if (SVGSMILElement::isSMILElement(targetElement)) {
                    SVGSMILElement* timed = static_cast<SVGSMILElement*>(targetElement);
                    timed->beginByLinkActivation();
                    evt->setDefaultHandled();
                    SVGStyledTransformableElement::defaultEventHandler(evt);
                    return;
                }
            }
#endif
            if (document()->frame())
                document()->frame()->loader()->urlSelected(document()->completeURL(url), target, evt, false, true);
        }

        evt->setDefaultHandled();
    }

    SVGStyledTransformableElement::defaultEventHandler(evt);
}
Example #3
0
void SVGSMILElement::notifyDependentsIntervalChanged(NewOrExistingInterval newOrExisting)
{
    ASSERT(m_intervalBegin.isFinite());
    DEFINE_STATIC_LOCAL(HashSet<SVGSMILElement*>, loopBreaker, ());
    if (loopBreaker.contains(this))
        return;
    loopBreaker.add(this);
    
    TimeDependentSet::iterator end = m_timeDependents.end();
    for (TimeDependentSet::iterator it = m_timeDependents.begin(); it != end; ++it) {
        SVGSMILElement* dependent = *it;
        dependent->createInstanceTimesFromSyncbase(this, newOrExisting);
    }

    loopBreaker.remove(this);
}
void SVGSMILElement::connectSyncBaseConditions()
{
    if (m_syncBaseConditionsConnected)
        disconnectSyncBaseConditions();
    m_syncBaseConditionsConnected = true;
    for (unsigned n = 0; n < m_conditions.size(); ++n) {
        Condition* condition = m_conditions[n].get();
        if (condition->getType() == Condition::Syncbase) {
            ASSERT(!condition->baseID().isEmpty());
            Element* element = treeScope().getElementById(AtomicString(condition->baseID()));
            if (!element || !isSVGSMILElement(*element)) {
                condition->setSyncBase(0);
                continue;
            }
            SVGSMILElement* svgSMILElement = toSVGSMILElement(element);
            condition->setSyncBase(svgSMILElement);
            svgSMILElement->addSyncBaseDependent(this);
        }
    }
}
Example #5
0
void SMILTimeContainer::updateAnimations(SMILTime elapsed, bool seekToTime)
{
    SMILTime earliestFireTime = SMILTime::unresolved();

#ifndef NDEBUG
    // This boolean will catch any attempts to schedule/unschedule scheduledAnimations during this critical section.
    // Similarly, any elements removed will unschedule themselves, so this will catch modification of animationsToApply.
    m_preventScheduledAnimationsChanges = true;
#endif

    AnimationsVector animationsToApply;
    GroupedAnimationsMap::iterator end = m_scheduledAnimations.end();
    for (GroupedAnimationsMap::iterator it = m_scheduledAnimations.begin(); it != end; ++it) {
        AnimationsVector* scheduled = it->second;

        // 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(*scheduled, elapsed);

        SVGSMILElement* resultElement = 0;
        unsigned size = scheduled->size();
        for (unsigned n = 0; n < size; n++) {
            SVGSMILElement* animation = scheduled->at(n);
            ASSERT(animation->timeContainer() == this);
            ASSERT(animation->targetElement());
            ASSERT(animation->hasValidAttributeName());

            // Results are accumulated to the first animation that animates and contributes to a particular element/attribute pair.
            if (!resultElement) {
                if (!animation->hasValidAttributeType())
                    continue;
                resultElement = animation;
            }

            // This will calculate the contribution from the animation and add it to the resultsElement.
            if (!animation->progress(elapsed, resultElement, seekToTime) && resultElement == animation)
                resultElement = 0;

            SMILTime nextFireTime = animation->nextProgressTime();
            if (nextFireTime.isFinite())
                earliestFireTime = min(nextFireTime, earliestFireTime);
        }

        if (resultElement)
            animationsToApply.append(resultElement);
    }

    unsigned animationsToApplySize = animationsToApply.size();
    if (!animationsToApplySize) {
#ifndef NDEBUG
        m_preventScheduledAnimationsChanges = false;
#endif
        startTimer(earliestFireTime, animationFrameDelay);
        return;
    }

    // Apply results to target elements.
    for (unsigned i = 0; i < animationsToApplySize; ++i)
        animationsToApply[i]->applyResultsToTarget();

#ifndef NDEBUG
    m_preventScheduledAnimationsChanges = false;
#endif

    startTimer(earliestFireTime, animationFrameDelay);
    Document::updateStyleForAllDocuments();
}
Example #6
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();
}
void ConditionEventListener::handleEvent(ExecutionContext*, Event* event)
{
    if (!m_animation)
        return;
    m_animation->handleConditionEvent(event, m_condition);
}
void SMILTimeContainer::updateAnimations(SMILTime elapsed, bool seekToTime)
{
    SMILTime earliestFireTime = SMILTime::unresolved();

#ifndef NDEBUG
    // This boolean will catch any attempts to schedule/unschedule scheduledAnimations during this critical section.
    // Similarly, any elements removed will unschedule themselves, so this will catch modification of animationsToApply.
    m_preventScheduledAnimationsChanges = true;
#endif

    if (m_documentOrderIndexesDirty)
        updateDocumentOrderIndexes();

    Vector<RefPtr<SVGSMILElement> >  animationsToApply;
    GroupedAnimationsMap::iterator end = m_scheduledAnimations.end();
    for (GroupedAnimationsMap::iterator it = m_scheduledAnimations.begin(); it != end; ++it) {
        AnimationsVector* scheduled = it->value.get();

        // 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.
        std::sort(scheduled->begin(), scheduled->end(), PriorityCompare(elapsed));

        SVGSMILElement* resultElement = 0;
        unsigned size = scheduled->size();
        for (unsigned n = 0; n < size; n++) {
            SVGSMILElement* animation = scheduled->at(n);
            ASSERT(animation->timeContainer() == this);
            ASSERT(animation->targetElement());
            ASSERT(animation->hasValidAttributeName());

            // Results are accumulated to the first animation that animates and contributes to a particular element/attribute pair.
            // FIXME: we should ensure that resultElement is of an appropriate type.
            if (!resultElement) {
                if (!animation->hasValidAttributeType())
                    continue;
                resultElement = animation;
            }

            // This will calculate the contribution from the animation and add it to the resultsElement.
            if (!animation->progress(elapsed, resultElement, seekToTime) && resultElement == animation)
                resultElement = 0;

            SMILTime nextFireTime = animation->nextProgressTime();
            if (nextFireTime.isFinite())
                earliestFireTime = min(nextFireTime, earliestFireTime);
        }

        if (resultElement)
            animationsToApply.append(resultElement);
    }

    std::sort(animationsToApply.begin(), animationsToApply.end(), PriorityCompare(elapsed));

    unsigned animationsToApplySize = animationsToApply.size();
    if (!animationsToApplySize) {
#ifndef NDEBUG
        m_preventScheduledAnimationsChanges = false;
#endif
        scheduleAnimationFrame(earliestFireTime);
        return;
    }

    // Apply results to target elements.
    for (unsigned i = 0; i < animationsToApplySize; ++i)
        animationsToApply[i]->applyResultsToTarget();

#ifndef NDEBUG
    m_preventScheduledAnimationsChanges = false;
#endif

    scheduleAnimationFrame(earliestFireTime);

    for (unsigned i = 0; i < animationsToApplySize; ++i) {
        if (animationsToApply[i]->inDocument() && animationsToApply[i]->isSVGDiscardElement()) {
            RefPtr<SVGSMILElement> animDiscard = animationsToApply[i];
            RefPtr<SVGElement> targetElement = animDiscard->targetElement();
            if (targetElement && targetElement->inDocument()) {
                targetElement->remove(IGNORE_EXCEPTION);
                ASSERT(!targetElement->inDocument());
            }

            if (animDiscard->inDocument()) {
                animDiscard->remove(IGNORE_EXCEPTION);
                ASSERT(!animDiscard->inDocument());
            }
        }
    }
}
Example #10
0
SMILTime SMILTimeContainer::updateAnimations(SMILTime elapsed, bool seekToTime)
{
    SMILTime earliestFireTime = SMILTime::unresolved();

#if ENABLE(ASSERT)
    // This boolean will catch any attempts to schedule/unschedule scheduledAnimations during this critical section.
    // Similarly, any elements removed will unschedule themselves, so this will catch modification of animationsToApply.
    m_preventScheduledAnimationsChanges = true;
#endif

    if (m_documentOrderIndexesDirty)
        updateDocumentOrderIndexes();

    WillBeHeapHashSet<ElementAttributePair> invalidKeys;
    using AnimationsVector = WillBeHeapVector<RefPtrWillBeMember<SVGSMILElement>>;
    AnimationsVector animationsToApply;
    for (const auto& entry : m_scheduledAnimations) {
        if (!entry.key.first || entry.value->isEmpty()) {
            invalidKeys.add(entry.key);
            continue;
        }

        AnimationsLinkedHashSet* scheduled = entry.value.get();

        // 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.
        AnimationsVector scheduledAnimations;
        copyToVector(*scheduled, scheduledAnimations);
        std::sort(scheduledAnimations.begin(), scheduledAnimations.end(), PriorityCompare(elapsed));

        SVGSMILElement* resultElement = nullptr;
        for (const auto& itAnimation : scheduledAnimations) {
            SVGSMILElement* animation = itAnimation.get();
            ASSERT(animation->timeContainer() == this);
            ASSERT(animation->targetElement());
            ASSERT(animation->hasValidAttributeName());

            // Results are accumulated to the first animation that animates and contributes to a particular element/attribute pair.
            // FIXME: we should ensure that resultElement is of an appropriate type.
            if (!resultElement) {
                if (!animation->hasValidAttributeType())
                    continue;
                resultElement = animation;
            }

            // This will calculate the contribution from the animation and add it to the resultsElement.
            if (!animation->progress(elapsed, resultElement, seekToTime) && resultElement == animation)
                resultElement = nullptr;

            SMILTime nextFireTime = animation->nextProgressTime();
            if (nextFireTime.isFinite())
                earliestFireTime = std::min(nextFireTime, earliestFireTime);
        }

        if (resultElement)
            animationsToApply.append(resultElement);
    }
    m_scheduledAnimations.removeAll(invalidKeys);

    std::sort(animationsToApply.begin(), animationsToApply.end(), PriorityCompare(elapsed));

    unsigned animationsToApplySize = animationsToApply.size();
    if (!animationsToApplySize) {
#if ENABLE(ASSERT)
        m_preventScheduledAnimationsChanges = false;
#endif
        return earliestFireTime;
    }

    // Apply results to target elements.
    for (unsigned i = 0; i < animationsToApplySize; ++i)
        animationsToApply[i]->applyResultsToTarget();

#if ENABLE(ASSERT)
    m_preventScheduledAnimationsChanges = false;
#endif

    for (unsigned i = 0; i < animationsToApplySize; ++i) {
        if (animationsToApply[i]->inDocument() && animationsToApply[i]->isSVGDiscardElement()) {
            RefPtrWillBeRawPtr<SVGSMILElement> animDiscard = animationsToApply[i];
            RefPtrWillBeRawPtr<SVGElement> targetElement = animDiscard->targetElement();
            if (targetElement && targetElement->inDocument()) {
                targetElement->remove(IGNORE_EXCEPTION);
                ASSERT(!targetElement->inDocument());
            }

            if (animDiscard->inDocument()) {
                animDiscard->remove(IGNORE_EXCEPTION);
                ASSERT(!animDiscard->inDocument());
            }
        }
    }
    return earliestFireTime;
}