📄 svguseelement.cpp
字号:
}#if ENABLE(SVG) && ENABLE(SVG_USE)void SVGUseElement::expandUseElementsInShadowTree(Node* element){ // Why expand the <use> elements in the shadow tree here, and not just // do this directly in buildShadowTree, if we encounter a <use> element? // // Short answer: Because we may miss to expand some elements. Ie. if a <symbol> // contains <use> tags, we'd miss them. So once we're done with settin' up the // actual shadow tree (after the special case modification for svg/symbol) we have // to walk it completely and expand all <use> elements. if (element->hasTagName(SVGNames::useTag)) { SVGUseElement* use = static_cast<SVGUseElement*>(element); String id = SVGURIReference::getTarget(use->href()); Element* targetElement = document()->getElementById(id); SVGElement* target = 0; if (targetElement && targetElement->isSVGElement()) target = static_cast<SVGElement*>(targetElement); // Don't ASSERT(target) here, it may be "pending", too. if (target) { // Setup sub-shadow tree root node RefPtr<SVGElement> cloneParent = new SVGGElement(SVGNames::gTag, document()); // Spec: In the generated content, the 'use' will be replaced by 'g', where all attributes from the // 'use' element except for x, y, width, height and xlink:href are transferred to the generated 'g' element. transferUseAttributesToReplacedElement(use, cloneParent.get()); // Spec: An additional transformation translate(x,y) is appended to the end // (i.e., right-side) of the transform attribute on the generated 'g', where x // and y represent the values of the x and y attributes on the 'use' element. if (use->x().value(this) != 0.0 || use->y().value(this) != 0.0) { if (!cloneParent->hasAttribute(SVGNames::transformAttr)) { String transformString = String::format("translate(%f, %f)", use->x().value(this), use->y().value(this)); cloneParent->setAttribute(SVGNames::transformAttr, transformString); } else { String transformString = String::format(" translate(%f, %f)", use->x().value(this), use->y().value(this)); const AtomicString& transformAttribute = cloneParent->getAttribute(SVGNames::transformAttr); cloneParent->setAttribute(SVGNames::transformAttr, transformAttribute + transformString); } } ExceptionCode ec = 0; // For instance <use> on <foreignObject> (direct case). if (isDisallowedElement(target)) { // We still have to setup the <use> replacment (<g>). Otherwhise // associateInstancesWithShadowTreeElements() makes wrong assumptions. // Replace <use> with referenced content. ASSERT(use->parentNode()); use->parentNode()->replaceChild(cloneParent.release(), use, ec); ASSERT(ec == 0); return; } RefPtr<Node> newChild = target->cloneNode(true); // We don't walk the target tree element-by-element, and clone each element, // but instead use cloneNode(deep=true). This is an optimization for the common // case where <use> doesn't contain disallowed elements (ie. <foreignObject>). // Though if there are disallowed elements in the subtree, we have to remove them. // For instance: <use> on <g> containing <foreignObject> (indirect case). if (subtreeContainsDisallowedElement(newChild.get())) removeDisallowedElementsFromSubtree(newChild.get()); SVGElement* newChildPtr = 0; if (newChild->isSVGElement()) newChildPtr = static_cast<SVGElement*>(newChild.get()); ASSERT(newChildPtr); cloneParent->appendChild(newChild.release(), ec); ASSERT(ec == 0); // Replace <use> with referenced content. ASSERT(use->parentNode()); use->parentNode()->replaceChild(cloneParent.release(), use, ec); ASSERT(ec == 0); // Handle use referencing <svg> special case if (target->hasTagName(SVGNames::svgTag)) alterShadowTreeForSVGTag(newChildPtr); // Immediately stop here, and restart expanding. expandUseElementsInShadowTree(m_shadowTreeRootElement.get()); return; } } for (RefPtr<Node> child = element->firstChild(); child; child = child->nextSibling()) expandUseElementsInShadowTree(child.get());}void SVGUseElement::expandSymbolElementsInShadowTree(Node* element){ if (element->hasTagName(SVGNames::symbolTag)) { // Spec: The referenced 'symbol' and its contents are deep-cloned into the generated tree, // with the exception that the 'symbol' is replaced by an 'svg'. This generated 'svg' will // always have explicit values for attributes width and height. If attributes width and/or // height are provided on the 'use' element, then these attributes will be transferred to // the generated 'svg'. If attributes width and/or height are not specified, the generated // 'svg' element will use values of 100% for these attributes. RefPtr<SVGSVGElement> svgElement = new SVGSVGElement(SVGNames::svgTag, document()); // Transfer all attributes from <symbol> to the new <svg> element svgElement->attributes()->setAttributes(*element->attributes()); // Explicitly re-set width/height values String widthString = String::number(width().value(this)); String heightString = String::number(height().value(this)); svgElement->setAttribute(SVGNames::widthAttr, hasAttribute(SVGNames::widthAttr) ? widthString : "100%"); svgElement->setAttribute(SVGNames::heightAttr, hasAttribute(SVGNames::heightAttr) ? heightString : "100%"); ExceptionCode ec = 0; // Only clone symbol children, and add them to the new <svg> element for (Node* child = element->firstChild(); child; child = child->nextSibling()) { RefPtr<Node> newChild = child->cloneNode(true); svgElement->appendChild(newChild.release(), ec); ASSERT(ec == 0); } // We don't walk the target tree element-by-element, and clone each element, // but instead use cloneNode(deep=true). This is an optimization for the common // case where <use> doesn't contain disallowed elements (ie. <foreignObject>). // Though if there are disallowed elements in the subtree, we have to remove them. // For instance: <use> on <g> containing <foreignObject> (indirect case). if (subtreeContainsDisallowedElement(svgElement.get())) removeDisallowedElementsFromSubtree(svgElement.get()); // Replace <symbol> with <svg>. ASSERT(element->parentNode()); element->parentNode()->replaceChild(svgElement.release(), element, ec); ASSERT(ec == 0); // Immediately stop here, and restart expanding. expandSymbolElementsInShadowTree(m_shadowTreeRootElement.get()); return; } for (RefPtr<Node> child = element->firstChild(); child; child = child->nextSibling()) expandSymbolElementsInShadowTree(child.get());}#endif void SVGUseElement::attachShadowTree(){ if (!m_shadowTreeRootElement || m_shadowTreeRootElement->attached() || !document()->shouldCreateRenderers() || !attached() || !renderer()) return; // Inspired by RenderTextControl::createSubtreeIfNeeded(). if (renderer()->canHaveChildren() && childShouldCreateRenderer(m_shadowTreeRootElement.get())) { RefPtr<RenderStyle> style = m_shadowTreeRootElement->styleForRenderer(); if (m_shadowTreeRootElement->rendererIsNeeded(style.get())) { m_shadowTreeRootElement->setRenderer(m_shadowTreeRootElement->createRenderer(document()->renderArena(), style.get())); if (RenderObject* shadowRenderer = m_shadowTreeRootElement->renderer()) { shadowRenderer->setStyle(style.release()); renderer()->addChild(shadowRenderer, m_shadowTreeRootElement->nextRenderer()); m_shadowTreeRootElement->setAttached(); } } // This will take care of attaching all shadow tree child nodes. for (Node* child = m_shadowTreeRootElement->firstChild(); child; child = child->nextSibling()) child->attach(); }} void SVGUseElement::transferEventListenersToShadowTree(SVGElementInstance* target){ if (!target) return; SVGElement* originalElement = target->correspondingElement(); ASSERT(originalElement); if (SVGElement* shadowTreeElement = target->shadowTreeElement()) { const RegisteredEventListenerVector& listeners = originalElement->eventListeners(); size_t size = listeners.size(); for (size_t i = 0; i < size; ++i) { const RegisteredEventListener& r = *listeners[i]; EventListener* listener = r.listener(); ASSERT(listener); // Event listeners created from markup have already been transfered to the shadow tree during cloning! if (listener->wasCreatedFromMarkup()) continue; shadowTreeElement->addEventListener(r.eventType(), listener, r.useCapture()); } } for (SVGElementInstance* instance = target->firstChild(); instance; instance = instance->nextSibling()) transferEventListenersToShadowTree(instance);}void SVGUseElement::associateInstancesWithShadowTreeElements(Node* target, SVGElementInstance* targetInstance){ if (!target || !targetInstance) return; SVGElement* originalElement = targetInstance->correspondingElement(); if (originalElement->hasTagName(SVGNames::useTag)) {#if ENABLE(SVG) && ENABLE(SVG_USE) // <use> gets replaced by <g> ASSERT(target->nodeName() == SVGNames::gTag);#else ASSERT(target->nodeName() == SVGNames::gTag || target->nodeName() == SVGNames::useTag);#endif } else if (originalElement->hasTagName(SVGNames::symbolTag)) { // <symbol> gets replaced by <svg>#if ENABLE(SVG) && ENABLE(SVG_USE) && ENABLE(SVG_FOREIGN_OBJECT) ASSERT(target->nodeName() == SVGNames::svgTag);#endif } else ASSERT(target->nodeName() == originalElement->nodeName()); SVGElement* element = 0; if (target->isSVGElement()) element = static_cast<SVGElement*>(target); ASSERT(!targetInstance->shadowTreeElement()); targetInstance->setShadowTreeElement(element); Node* node = target->firstChild(); for (SVGElementInstance* instance = targetInstance->firstChild(); node && instance; instance = instance->nextSibling()) { // Skip any non-svg elements in shadow tree while (node && !node->isSVGElement()) node = node->nextSibling(); associateInstancesWithShadowTreeElements(node, instance); node = node->nextSibling(); }}SVGElementInstance* SVGUseElement::instanceForShadowTreeElement(Node* element) const{ return instanceForShadowTreeElement(element, m_targetElementInstance.get());}SVGElementInstance* SVGUseElement::instanceForShadowTreeElement(Node* element, SVGElementInstance* instance) const{ ASSERT(element); ASSERT(instance); ASSERT(instance->shadowTreeElement()); if (element == instance->shadowTreeElement()) return instance; for (SVGElementInstance* current = instance->firstChild(); current; current = current->nextSibling()) { SVGElementInstance* search = instanceForShadowTreeElement(element, current); if (search) return search; } return 0;}void SVGUseElement::transferUseAttributesToReplacedElement(SVGElement* from, SVGElement* to) const{ ASSERT(from); ASSERT(to); to->attributes()->setAttributes(*from->attributes()); ExceptionCode ec = 0; to->removeAttribute(SVGNames::xAttr, ec); ASSERT(ec == 0); to->removeAttribute(SVGNames::yAttr, ec); ASSERT(ec == 0); to->removeAttribute(SVGNames::widthAttr, ec); ASSERT(ec == 0); to->removeAttribute(SVGNames::heightAttr, ec); ASSERT(ec == 0); to->removeAttribute(XLinkNames::hrefAttr, ec); ASSERT(ec == 0);}}#endif // ENABLE(SVG)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -