コード例 #1
0
ファイル: SVGElement.cpp プロジェクト: ychaim/chromium.bb
void SVGElement::updateRelativeLengthsInformation(bool clientHasRelativeLengths, SVGElement* clientElement)
{
    // If we're not yet in a document, this function will be called again from insertedInto(). Do nothing now.
    if (!inDocument())
        return;

    // An element wants to notify us that its own relative lengths state changed.
    // Register it in the relative length map, and register us in the parent relative length map.
    // Register the parent in the grandparents map, etc. Repeat procedure until the root of the SVG tree.
    for (ContainerNode* currentNode = this; currentNode && currentNode->isSVGElement(); currentNode = currentNode->parentNode()) {
        SVGElement* currentElement = toSVGElement(currentNode);
        ASSERT(!currentElement->m_inRelativeLengthClientsInvalidation);

        bool hadRelativeLengths = currentElement->hasRelativeLengths();
        if (clientHasRelativeLengths)
            currentElement->m_elementsWithRelativeLengths.add(clientElement);
        else
            currentElement->m_elementsWithRelativeLengths.remove(clientElement);

        // If the relative length state hasn't changed, we can stop propagating the notfication.
        if (hadRelativeLengths == currentElement->hasRelativeLengths())
            break;

        clientElement = currentElement;
        clientHasRelativeLengths = clientElement->hasRelativeLengths();
    }
}
コード例 #2
0
ファイル: SVGElement.cpp プロジェクト: cheekiatng/webkit
void SVGElement::updateRelativeLengthsInformation(bool hasRelativeLengths, SVGElement* element)
{
    // If we're not yet in a document, this function will be called again from insertedInto(). Do nothing now.
    if (!inDocument())
        return;

    // An element wants to notify us that its own relative lengths state changed.
    // Register it in the relative length map, and register us in the parent relative length map.
    // Register the parent in the grandparents map, etc. Repeat procedure until the root of the SVG tree.

    if (hasRelativeLengths)
        m_elementsWithRelativeLengths.add(element);
    else {
        if (!m_elementsWithRelativeLengths.contains(element)) {
            // We were never registered. Do nothing.
            return;
        }

        m_elementsWithRelativeLengths.remove(element);
    }

    if (!element->isSVGGraphicsElement())
        return;

    // Find first styled parent node, and notify it that we've changed our relative length state.
    ContainerNode* node = parentNode();
    while (node) {
        if (!node->isSVGElement())
            break;

        // Register us in the parent element map.
        downcast<SVGElement>(*node).updateRelativeLengthsInformation(hasRelativeLengths, this);
        break;
    }
}
コード例 #3
0
bool SVGUseElement::hasCycleUseReferencing(SVGUseElement* use, ContainerNode* targetInstance, SVGElement*& newTarget)
{
    ASSERT(referencedScope());
    Element* targetElement = SVGURIReference::targetElementFromIRIString(use->hrefString(), *referencedScope());
    newTarget = 0;
    if (targetElement && targetElement->isSVGElement())
        newTarget = toSVGElement(targetElement);

    if (!newTarget)
        return false;

    // Shortcut for self-references
    if (newTarget == this)
        return true;

    AtomicString targetId = newTarget->getIdAttribute();
    ContainerNode* instance = targetInstance->parentNode();
    while (instance && instance->isSVGElement()) {
        SVGElement* element = toSVGElement(instance);
        if (element->hasID() && element->getIdAttribute() == targetId && element->document() == newTarget->document())
            return true;

        instance = instance->parentNode();
    }
    return false;
}
コード例 #4
0
SVGElement* SVGSMILElement::targetElement()
{
    if (m_targetElement)
        return m_targetElement;

    String href = xlinkHref();
    ContainerNode* target = href.isEmpty() ? parentNode() : SVGURIReference::targetElementFromIRIString(href, document());
    if (!target || !target->isSVGElement())
        return 0;
    
    m_targetElement = static_cast<SVGElement*>(target);
    document()->accessSVGExtensions()->addAnimationElementToTarget(this, m_targetElement);
    return m_targetElement;
}
コード例 #5
0
String SVGStyledElement::title() const
{
    // According to spec, we should not return titles when hovering over root <svg> elements (those
    // <title> elements are the title of the document, not a tooltip) so we instantly return.
    if (hasTagName(SVGNames::svgTag)) {
        const SVGSVGElement* svg = static_cast<const SVGSVGElement*>(this);
        if (svg->isOutermostSVG())
            return String();
    }
    
    // Walk up the tree, to find out whether we're inside a <use> shadow tree, to find the right title.
    Node* parent = const_cast<SVGStyledElement*>(this);
    while (parent) {
        if (!parent->isShadowRoot()) {
            parent = parent->parentNodeGuaranteedHostFree();
            continue;
        }
        
        // Get the <use> element.
        ContainerNode* shadowParent = parent->shadowParentNode();
        if (shadowParent && shadowParent->isSVGElement() && shadowParent->hasTagName(SVGNames::useTag)) {
            SVGUseElement* useElement = static_cast<SVGUseElement*>(shadowParent);
            // If the <use> title is not empty we found the title to use.
            String useTitle(useElement->title());
            if (useTitle.isEmpty())
                break;
            return useTitle;
        }
        parent = parent->parentNode();
    }
    
    // If we aren't an instance in a <use> or the <use> title was not found, then find the first
    // <title> child of this element.
    Element* titleElement = firstElementChild();
    for (; titleElement; titleElement = titleElement->nextElementSibling()) {
        if (titleElement->hasTagName(SVGNames::titleTag) && titleElement->isSVGElement())
            break;
    }

    // If a title child was found, return the text contents.
    if (titleElement)
        return titleElement->innerText();
    
    // Otherwise return a null/empty string.
    return String();
}
コード例 #6
0
PassRefPtr<JSLazyEventListener> JSLazyEventListener::createForNode(ContainerNode& node, const QualifiedName& attributeName, const AtomicString& attributeValue)
{
    if (attributeValue.isNull())
        return nullptr;

    TextPosition position = TextPosition::minimumPosition();
    String sourceURL;

    // FIXME: We should be able to provide source information for frameless documents too (e.g. for importing nodes from XMLHttpRequest.responseXML).
    if (Frame* frame = node.document().frame()) {
        if (!frame->script().canExecuteScripts(AboutToExecuteScript))
            return nullptr;

        position = frame->script().eventHandlerPosition();
        sourceURL = node.document().url().string();
    }

    return adoptRef(new JSLazyEventListener(attributeName.localName().string(),
        eventParameterName(node.isSVGElement()), attributeValue,
        &node, sourceURL, position, nullptr, mainThreadNormalWorld()));
}
コード例 #7
0
void SVGUseElement::updateContainerOffsets()
{
    if (!m_targetElementInstance)
        return;

    // Update root container offset (not reachable through instance tree)
    SVGElement* shadowRoot = m_targetElementInstance->shadowTreeElement();
    ASSERT(shadowRoot);

    ContainerNode* parentNode = shadowRoot->parentNode();
    ASSERT(parentNode);
    ASSERT(parentNode->isSVGElement());
    ASSERT(parentNode->hasTagName(SVGNames::gTag));
    ASSERT(static_cast<SVGGElement*>(parentNode)->isShadowTreeContainerElement());

    SVGShadowTreeContainerElement* containerElement = static_cast<SVGShadowTreeContainerElement*>(parentNode);
    containerElement->setContainerOffset(x(), y());

    // Update whole subtree, scanning for shadow container elements, marking a cloned use subtree
    updateContainerOffset(m_targetElementInstance.get());

    if (RenderObject* object = renderer())
        RenderSVGResource::markForLayoutAndParentResourceInvalidation(object);
}
bool EventTargetNode::dispatchGenericEvent(PassRefPtr<Event> prpEvent)
{
    RefPtr<Event> event(prpEvent);

    ASSERT(!eventDispatchForbidden());
    ASSERT(event->target());
    ASSERT(!event->type().isNull()); // JavaScript code can create an event with an empty name, but not null.

    // Make a vector of ancestors to send the event to.
    // If the node is not in a document just send the event to it.
    // Be sure to ref all of nodes since event handlers could result in the last reference going away.
    RefPtr<EventTargetNode> thisNode(this);
    Vector<RefPtr<ContainerNode> > ancestors;
    if (inDocument()) {
        for (ContainerNode* ancestor = eventParentNode(); ancestor; ancestor = ancestor->eventParentNode()) {
#if ENABLE(SVG)
            // Skip <use> shadow tree elements.
            if (ancestor->isSVGElement() && ancestor->isShadowNode())
                continue;
#endif
            ancestors.append(ancestor);
        }
    }

    // Set up a pointer to indicate whether to dispatch window events.
    // We don't dispatch load events to the window. That quirk was originally
    // added because Mozilla doesn't propagate load events to the window object.
    Document* documentForWindowEvents = 0;
    if (event->type() != eventNames().loadEvent) {
        EventTargetNode* topLevelContainer = ancestors.isEmpty() ? this : ancestors.last().get();
        if (topLevelContainer->isDocumentNode())
            documentForWindowEvents = static_cast<Document*>(topLevelContainer);
    }

    // Give the target node a chance to do some work before DOM event handlers get a crack.
    void* data = preDispatchEventHandler(event.get());
    if (event->propagationStopped())
        goto doneDispatching;

    // Trigger capturing event handlers, starting at the top and working our way down.
    event->setEventPhase(Event::CAPTURING_PHASE);

    if (documentForWindowEvents) {
        event->setCurrentTarget(documentForWindowEvents);
        documentForWindowEvents->handleWindowEvent(event.get(), true);
        if (event->propagationStopped())
            goto doneDispatching;
    }
    for (size_t i = ancestors.size(); i; --i) {
        ContainerNode* ancestor = ancestors[i - 1].get();
        event->setCurrentTarget(eventTargetRespectingSVGTargetRules(ancestor));
        ancestor->handleLocalEvents(event.get(), true);
        if (event->propagationStopped())
            goto doneDispatching;
    }

    event->setEventPhase(Event::AT_TARGET);

    // We do want capturing event listeners to be invoked here, even though
    // that violates some versions of the DOM specification; Mozilla does it.
    event->setCurrentTarget(eventTargetRespectingSVGTargetRules(this));
    handleLocalEvents(event.get(), true);
    if (event->propagationStopped())
        goto doneDispatching;
    handleLocalEvents(event.get(), false);
    if (event->propagationStopped())
        goto doneDispatching;

    if (event->bubbles() && !event->cancelBubble()) {
        // Trigger bubbling event handlers, starting at the bottom and working our way up.
        event->setEventPhase(Event::BUBBLING_PHASE);

        size_t size = ancestors.size();
        for (size_t i = 0; i < size; ++i) {
            ContainerNode* ancestor = ancestors[i].get();
            event->setCurrentTarget(eventTargetRespectingSVGTargetRules(ancestor));
            ancestor->handleLocalEvents(event.get(), false);
            if (event->propagationStopped() || event->cancelBubble())
                goto doneDispatching;
        }
        if (documentForWindowEvents) {
            event->setCurrentTarget(documentForWindowEvents);
            documentForWindowEvents->handleWindowEvent(event.get(), false);
            if (event->propagationStopped() || event->cancelBubble())
                goto doneDispatching;
        }
    }

doneDispatching:
    event->setCurrentTarget(0);
    event->setEventPhase(0);

    // Pass the data from the preDispatchEventHandler to the postDispatchEventHandler.
    postDispatchEventHandler(event.get(), data);

    // Call default event handlers. While the DOM does have a concept of preventing
    // default handling, the detail of which handlers are called is an internal
    // implementation detail and not part of the DOM.
    if (!event->defaultPrevented() && !event->defaultHandled()) {
        // Non-bubbling events call only one default event handler, the one for the target.
        defaultEventHandler(event.get());
        ASSERT(!event->defaultPrevented());
        if (event->defaultHandled())
            goto doneWithDefault;
        // For bubbling events, call default event handlers on the same targets in the
        // same order as the bubbling phase.
        if (event->bubbles()) {
            size_t size = ancestors.size();
            for (size_t i = 0; i < size; ++i) {
                ContainerNode* ancestor = ancestors[i].get();
                ancestor->defaultEventHandler(event.get());
                ASSERT(!event->defaultPrevented());
                if (event->defaultHandled())
                    goto doneWithDefault;
            }
        }
    }

doneWithDefault:
    Document::updateDocumentsRendering();

    return !event->defaultPrevented();
}