nsIContent* SVGUseElement::CreateAnonymousContent() { mClone = nullptr; if (mSource.get()) { mSource.get()->RemoveMutationObserver(this); } LookupHref(); nsIContent* targetContent = mSource.get(); if (!targetContent || !targetContent->IsSVG()) return nullptr; // make sure target is valid type for <use> // QIable nsSVGGraphicsElement would eliminate enumerating all elements nsIAtom *tag = targetContent->Tag(); if (tag != nsGkAtoms::svg && tag != nsGkAtoms::symbol && tag != nsGkAtoms::g && tag != nsGkAtoms::path && tag != nsGkAtoms::text && tag != nsGkAtoms::rect && tag != nsGkAtoms::circle && tag != nsGkAtoms::ellipse && tag != nsGkAtoms::line && tag != nsGkAtoms::polyline && tag != nsGkAtoms::polygon && tag != nsGkAtoms::image && tag != nsGkAtoms::use) return nullptr; // circular loop detection // check 1 - check if we're a document descendent of the target if (nsContentUtils::ContentIsDescendantOf(this, targetContent)) return nullptr; // check 2 - check if we're a clone, and if we already exist in the hierarchy if (GetParent() && mOriginal) { for (nsCOMPtr<nsIContent> content = GetParent(); content; content = content->GetParent()) { if (content->IsSVG(nsGkAtoms::use) && static_cast<SVGUseElement*>(content.get())->mOriginal == mOriginal) { return nullptr; } } } nsCOMPtr<nsINode> newnode; nsCOMArray<nsINode> unused; nsNodeInfoManager* nodeInfoManager = targetContent->OwnerDoc() == OwnerDoc() ? nullptr : OwnerDoc()->NodeInfoManager(); nsNodeUtils::Clone(targetContent, true, nodeInfoManager, unused, getter_AddRefs(newnode)); nsCOMPtr<nsIContent> newcontent = do_QueryInterface(newnode); if (!newcontent) return nullptr; if (newcontent->IsSVG(nsGkAtoms::symbol)) { nsIDocument *document = GetComposedDoc(); if (!document) return nullptr; nsNodeInfoManager *nodeInfoManager = document->NodeInfoManager(); if (!nodeInfoManager) return nullptr; nsRefPtr<mozilla::dom::NodeInfo> nodeInfo; nodeInfo = nodeInfoManager->GetNodeInfo(nsGkAtoms::svg, nullptr, kNameSpaceID_SVG, nsIDOMNode::ELEMENT_NODE); nsCOMPtr<nsIContent> svgNode; NS_NewSVGSVGElement(getter_AddRefs(svgNode), nodeInfo.forget(), NOT_FROM_PARSER); if (!svgNode) return nullptr; // copy attributes const nsAttrName* name; uint32_t i; for (i = 0; (name = newcontent->GetAttrNameAt(i)); i++) { nsAutoString value; int32_t nsID = name->NamespaceID(); nsIAtom* lname = name->LocalName(); newcontent->GetAttr(nsID, lname, value); svgNode->SetAttr(nsID, lname, name->GetPrefix(), value, false); } // move the children over uint32_t num = newcontent->GetChildCount(); for (i = 0; i < num; i++) { nsCOMPtr<nsIContent> child = newcontent->GetFirstChild(); newcontent->RemoveChildAt(0, false); svgNode->InsertChildAt(child, i, true); } newcontent = svgNode; } if (newcontent->IsSVG() && (newcontent->Tag() == nsGkAtoms::svg || newcontent->Tag() == nsGkAtoms::symbol)) { nsSVGElement *newElement = static_cast<nsSVGElement*>(newcontent.get()); if (mLengthAttributes[ATTR_WIDTH].IsExplicitlySet()) newElement->SetLength(nsGkAtoms::width, mLengthAttributes[ATTR_WIDTH]); if (mLengthAttributes[ATTR_HEIGHT].IsExplicitlySet()) newElement->SetLength(nsGkAtoms::height, mLengthAttributes[ATTR_HEIGHT]); } // Set up its base URI correctly nsCOMPtr<nsIURI> baseURI = targetContent->GetBaseURI(); if (!baseURI) return nullptr; newcontent->SetExplicitBaseURI(baseURI); targetContent->AddMutationObserver(this); mClone = newcontent; return mClone; }
nsresult NS_NewSVGElement(nsIContent** aResult, nsINodeInfo *aNodeInfo, PRBool aFromParser) { NS_PRECONDITION(NS_SVGEnabled(), "creating an SVG element while SVG disabled"); static const char kSVGStyleSheetURI[] = "resource://gre/res/svg.css"; // this bit of code is to load svg.css on demand nsIDocument *doc = aNodeInfo->GetDocument(); if (doc) doc->EnsureCatalogStyleSheet(kSVGStyleSheetURI); nsIAtom *name = aNodeInfo->NameAtom(); if (name == nsGkAtoms::a) return NS_NewSVGAElement(aResult, aNodeInfo); if (name == nsGkAtoms::polyline) return NS_NewSVGPolylineElement(aResult, aNodeInfo); if (name == nsGkAtoms::polygon) return NS_NewSVGPolygonElement(aResult, aNodeInfo); if (name == nsGkAtoms::circle) return NS_NewSVGCircleElement(aResult, aNodeInfo); if (name == nsGkAtoms::ellipse) return NS_NewSVGEllipseElement(aResult, aNodeInfo); if (name == nsGkAtoms::line) return NS_NewSVGLineElement(aResult, aNodeInfo); if (name == nsGkAtoms::rect) return NS_NewSVGRectElement(aResult, aNodeInfo); if (name == nsGkAtoms::svg) return NS_NewSVGSVGElement(aResult, aNodeInfo, aFromParser); if (name == nsGkAtoms::g) return NS_NewSVGGElement(aResult, aNodeInfo); if (name == nsGkAtoms::foreignObject) return NS_NewSVGForeignObjectElement(aResult, aNodeInfo); if (name == nsGkAtoms::path) return NS_NewSVGPathElement(aResult, aNodeInfo); if (name == nsGkAtoms::text) return NS_NewSVGTextElement(aResult, aNodeInfo); if (name == nsGkAtoms::tspan) return NS_NewSVGTSpanElement(aResult, aNodeInfo); if (name == nsGkAtoms::image) return NS_NewSVGImageElement(aResult, aNodeInfo); if (name == nsGkAtoms::style) return NS_NewSVGStyleElement(aResult, aNodeInfo); if (name == nsGkAtoms::linearGradient) return NS_NewSVGLinearGradientElement(aResult, aNodeInfo); if (name == nsGkAtoms::metadata) return NS_NewSVGMetadataElement(aResult, aNodeInfo); if (name == nsGkAtoms::radialGradient) return NS_NewSVGRadialGradientElement(aResult, aNodeInfo); if (name == nsGkAtoms::stop) return NS_NewSVGStopElement(aResult, aNodeInfo); if (name == nsGkAtoms::defs) return NS_NewSVGDefsElement(aResult, aNodeInfo); if (name == nsGkAtoms::desc) return NS_NewSVGDescElement(aResult, aNodeInfo); if (name == nsGkAtoms::script) return NS_NewSVGScriptElement(aResult, aNodeInfo); if (name == nsGkAtoms::use) return NS_NewSVGUseElement(aResult, aNodeInfo); if (name == nsGkAtoms::symbol) return NS_NewSVGSymbolElement(aResult, aNodeInfo); if (name == nsGkAtoms::marker) return NS_NewSVGMarkerElement(aResult, aNodeInfo); if (name == nsGkAtoms::title) return NS_NewSVGTitleElement(aResult, aNodeInfo); if (name == nsGkAtoms::clipPath) return NS_NewSVGClipPathElement(aResult, aNodeInfo); if (name == nsGkAtoms::textPath) return NS_NewSVGTextPathElement(aResult, aNodeInfo); if (name == nsGkAtoms::filter) return NS_NewSVGFilterElement(aResult, aNodeInfo); if (name == nsGkAtoms::feBlend) return NS_NewSVGFEBlendElement(aResult, aNodeInfo); if (name == nsGkAtoms::feColorMatrix) return NS_NewSVGFEColorMatrixElement(aResult, aNodeInfo); if (name == nsGkAtoms::feComponentTransfer) return NS_NewSVGFEComponentTransferElement(aResult, aNodeInfo); if (name == nsGkAtoms::feComposite) return NS_NewSVGFECompositeElement(aResult, aNodeInfo); if (name == nsGkAtoms::feFuncR) return NS_NewSVGFEFuncRElement(aResult, aNodeInfo); if (name == nsGkAtoms::feFuncG) return NS_NewSVGFEFuncGElement(aResult, aNodeInfo); if (name == nsGkAtoms::feFuncB) return NS_NewSVGFEFuncBElement(aResult, aNodeInfo); if (name == nsGkAtoms::feFuncA) return NS_NewSVGFEFuncAElement(aResult, aNodeInfo); if (name == nsGkAtoms::feGaussianBlur) return NS_NewSVGFEGaussianBlurElement(aResult, aNodeInfo); if (name == nsGkAtoms::feMerge) return NS_NewSVGFEMergeElement(aResult, aNodeInfo); if (name == nsGkAtoms::feMergeNode) return NS_NewSVGFEMergeNodeElement(aResult, aNodeInfo); if (name == nsGkAtoms::feMorphology) return NS_NewSVGFEMorphologyElement(aResult, aNodeInfo); if (name == nsGkAtoms::feOffset) return NS_NewSVGFEOffsetElement(aResult, aNodeInfo); if (name == nsGkAtoms::feFlood) return NS_NewSVGFEFloodElement(aResult, aNodeInfo); if (name == nsGkAtoms::feTile) return NS_NewSVGFETileElement(aResult, aNodeInfo); if (name == nsGkAtoms::feTurbulence) return NS_NewSVGFETurbulenceElement(aResult, aNodeInfo); if (name == nsGkAtoms::feConvolveMatrix) return NS_NewSVGFEConvolveMatrixElement(aResult, aNodeInfo); if (name == nsGkAtoms::feDistantLight) return NS_NewSVGFEDistantLightElement(aResult, aNodeInfo); if (name == nsGkAtoms::fePointLight) return NS_NewSVGFEPointLightElement(aResult, aNodeInfo); if (name == nsGkAtoms::feSpotLight) return NS_NewSVGFESpotLightElement(aResult, aNodeInfo); if (name == nsGkAtoms::feDiffuseLighting) return NS_NewSVGFEDiffuseLightingElement(aResult, aNodeInfo); if (name == nsGkAtoms::feSpecularLighting) return NS_NewSVGFESpecularLightingElement(aResult, aNodeInfo); if (name == nsGkAtoms::feImage) return NS_NewSVGFEImageElement(aResult, aNodeInfo); if (name == nsGkAtoms::feDisplacementMap) return NS_NewSVGFEDisplacementMapElement(aResult, aNodeInfo); if (name == nsGkAtoms::pattern) return NS_NewSVGPatternElement(aResult, aNodeInfo); if (name == nsGkAtoms::mask) return NS_NewSVGMaskElement(aResult, aNodeInfo); if (name == nsGkAtoms::svgSwitch) return NS_NewSVGSwitchElement(aResult, aNodeInfo); #ifdef MOZ_SMIL if (NS_SMILEnabled()) { if (name == nsGkAtoms::animate) return NS_NewSVGAnimateElement(aResult, aNodeInfo); if (name == nsGkAtoms::animateTransform) return NS_NewSVGAnimateTransformElement(aResult, aNodeInfo); if (name == nsGkAtoms::set) return NS_NewSVGSetElement(aResult, aNodeInfo); } #endif // MOZ_SMIL // if we don't know what to create, just create a standard xml element: return NS_NewXMLElement(aResult, aNodeInfo); }