static String imageToMarkup(const String& url, Element* element) { StringBuilder markup; markup.append("<img src=\""); markup.append(url); markup.append("\""); // Copy over attributes. If we are dragging an image, we expect things like // the id to be copied as well. NamedAttrMap* attrs = element->attributes(); unsigned length = attrs->length(); for (unsigned i = 0; i < length; ++i) { Attribute* attr = attrs->attributeItem(i); if (attr->localName() == "src") continue; markup.append(" "); markup.append(attr->localName()); markup.append("=\""); String escapedAttr = attr->value(); escapedAttr.replace("\"", """); markup.append(escapedAttr); markup.append("\""); } markup.append("/>"); return markup.toString(); }
Value FunLang::doEvaluate() const { String lang = arg(0)->evaluate().toString(); RefPtr<Node> langNode = 0; Node* node = evaluationContext().node.get(); String xmsnsURI = node->lookupNamespaceURI("xms"); while (node) { NamedAttrMap* attrs = node->attributes(); langNode = attrs->getNamedItemNS(xmsnsURI, "lang"); if (langNode) break; node = node->parentNode(); } if (!langNode) return false; String langNodeValue = langNode->nodeValue(); // extract 'en' out of 'en-us' int index = langNodeValue.find('-'); if (index != -1) langNodeValue = langNodeValue.left(index); return equalIgnoringCase(langNodeValue, lang); }
bool Element::hasAttributeNS(const String& namespaceURI, const String& localName) const { NamedAttrMap* attrs = attributes(true); if (!attrs) return false; return attrs->getAttributeItem(QualifiedName(nullAtom, localName, namespaceURI)); }
void NamedAttrMap::setAttributes(const NamedAttrMap& other) { // clone all attributes in the other map, but attach to our element if (!m_element) return; // If assigning the map changes the id attribute, we need to call // updateId. Attribute *oldId = getAttributeItem(idAttr); Attribute *newId = other.getAttributeItem(idAttr); if (oldId || newId) m_element->updateId(oldId ? oldId->value() : nullAtom, newId ? newId->value() : nullAtom); clearAttributes(); unsigned newLength = other.length(); m_attributes.resize(newLength); for (unsigned i = 0; i < newLength; i++) m_attributes[i] = other.m_attributes[i]->clone(); // FIXME: This is wasteful. The class list could be preserved on a copy, and we // wouldn't have to waste time reparsing the attribute. // The derived class, HTMLNamedAttrMap, which manages a parsed class list for the CLASS attribute, // will update its member variable when parse attribute is called. for (unsigned i = 0; i < newLength; i++) m_element->attributeChanged(m_attributes[i].get(), true); }
PassRefPtr<Attr> Element::getAttributeNodeNS(const String& namespaceURI, const String& localName) { NamedAttrMap* attrs = attributes(true); if (!attrs) return 0; return static_pointer_cast<Attr>(attrs->getNamedItem(QualifiedName(nullAtom, localName, namespaceURI))); }
Value FunLang::evaluate() const { String lang = arg(0)->evaluate().toString(); RefPtr<Node> langNode = 0; Node* node = evaluationContext().node.get(); while (node) { NamedAttrMap* attrs = node->attributes(); if (attrs) langNode = attrs->getNamedItemNS(XMLNames::xmlNamespaceURI, "lang"); if (langNode) break; node = node->parentNode(); } if (!langNode) return false; String langNodeValue = langNode->nodeValue(); while (true) { if (equalIgnoringCase(langNodeValue, lang)) return true; // Remove suffixes one by one. int index = langNodeValue.reverseFind('-'); if (index == -1) break; langNodeValue = langNodeValue.left(index); } return false; }
PassRefPtr<Attr> Element::getAttributeNode(const String& name) { NamedAttrMap* attrs = attributes(true); if (!attrs) return 0; String localName = shouldIgnoreAttributeCase(this) ? name.lower() : name; return static_pointer_cast<Attr>(attrs->getNamedItem(localName)); }
bool Element::hasAttribute(const String& name) const { NamedAttrMap* attrs = attributes(true); if (!attrs) return false; // This call to String::lower() seems to be required but // there may be a way to remove it. String localName = shouldIgnoreAttributeCase(this) ? name.lower() : name; return attrs->getAttributeItem(localName, false); }
PassRefPtr<Attr> Element::removeAttributeNode(Attr* attr, ExceptionCode& ec) { if (!attr) { ec = TYPE_MISMATCH_ERR; return 0; } if (attr->ownerElement() != this) { ec = NOT_FOUND_ERR; return 0; } if (document() != attr->document()) { ec = WRONG_DOCUMENT_ERR; return 0; } NamedAttrMap *attrs = attributes(true); if (!attrs) return 0; return static_pointer_cast<Attr>(attrs->removeNamedItem(attr->qualifiedName(), ec)); }
String Element::openTagStartToString() const { String result = "<" + nodeName(); NamedAttrMap *attrMap = attributes(true); if (attrMap) { unsigned numAttrs = attrMap->length(); for (unsigned i = 0; i < numAttrs; i++) { result += " "; Attribute *attribute = attrMap->attributeItem(i); result += attribute->name().toString(); if (!attribute->value().isNull()) { result += "=\""; // FIXME: substitute entities for any instances of " or ' result += attribute->value(); result += "\""; } } } return result; }
void RenderPartObject::updateWidget(bool onlyCreateNonNetscapePlugins) { String url; String serviceType; Vector<String> paramNames; Vector<String> paramValues; Frame* frame = m_view->frame(); if (element()->hasTagName(objectTag)) { HTMLObjectElement* o = static_cast<HTMLObjectElement*>(element()); o->setNeedWidgetUpdate(false); if (!o->isFinishedParsingChildren()) return; // Check for a child EMBED tag. HTMLEmbedElement* embed = 0; for (Node* child = o->firstChild(); child;) { if (child->hasTagName(embedTag)) { embed = static_cast<HTMLEmbedElement*>(child); break; } else if (child->hasTagName(objectTag)) child = child->nextSibling(); // Don't descend into nested OBJECT tags else child = child->traverseNextNode(o); // Otherwise descend (EMBEDs may be inside COMMENT tags) } // Use the attributes from the EMBED tag instead of the OBJECT tag including WIDTH and HEIGHT. HTMLElement *embedOrObject; if (embed) { embedOrObject = (HTMLElement *)embed; url = embed->url(); serviceType = embed->serviceType(); } else embedOrObject = (HTMLElement *)o; // If there was no URL or type defined in EMBED, try the OBJECT tag. if (url.isEmpty()) url = o->m_url; if (serviceType.isEmpty()) serviceType = o->m_serviceType; HashSet<StringImpl*, CaseFoldingHash> uniqueParamNames; // Scan the PARAM children. // Get the URL and type from the params if we don't already have them. // Get the attributes from the params if there is no EMBED tag. Node *child = o->firstChild(); while (child && (url.isEmpty() || serviceType.isEmpty() || !embed)) { if (child->hasTagName(paramTag)) { HTMLParamElement* p = static_cast<HTMLParamElement*>(child); String name = p->name().lower(); if (url.isEmpty() && (name == "src" || name == "movie" || name == "code" || name == "url")) url = p->value(); if (serviceType.isEmpty() && name == "type") { serviceType = p->value(); int pos = serviceType.find(";"); if (pos != -1) serviceType = serviceType.left(pos); } if (!embed && !name.isEmpty()) { uniqueParamNames.add(p->name().impl()); paramNames.append(p->name()); paramValues.append(p->value()); } } child = child->nextSibling(); } // When OBJECT is used for an applet via Sun's Java plugin, the CODEBASE attribute in the tag // points to the Java plugin itself (an ActiveX component) while the actual applet CODEBASE is // in a PARAM tag. See <http://java.sun.com/products/plugin/1.2/docs/tags.html>. This means // we have to explicitly suppress the tag's CODEBASE attribute if there is none in a PARAM, // else our Java plugin will misinterpret it. [4004531] String codebase; if (!embed && MIMETypeRegistry::isJavaAppletMIMEType(serviceType)) { codebase = "codebase"; uniqueParamNames.add(codebase.impl()); // pretend we found it in a PARAM already } // Turn the attributes of either the EMBED tag or OBJECT tag into arrays, but don't override PARAM values. NamedAttrMap* attributes = embedOrObject->attributes(); if (attributes) { for (unsigned i = 0; i < attributes->length(); ++i) { Attribute* it = attributes->attributeItem(i); const AtomicString& name = it->name().localName(); if (embed || !uniqueParamNames.contains(name.impl())) { paramNames.append(name.string()); paramValues.append(it->value().string()); } } } // If we still don't have a type, try to map from a specific CLASSID to a type. if (serviceType.isEmpty() && !o->m_classId.isEmpty()) mapClassIdToServiceType(o->m_classId, serviceType); if (!isURLAllowed(document(), url)) return; // Find out if we support fallback content. m_hasFallbackContent = false; for (Node *child = o->firstChild(); child && !m_hasFallbackContent; child = child->nextSibling()) { if ((!child->isTextNode() && !child->hasTagName(embedTag) && !child->hasTagName(paramTag)) || // Discount <embed> and <param> (child->isTextNode() && !static_cast<Text*>(child)->containsOnlyWhitespace())) m_hasFallbackContent = true; } if (onlyCreateNonNetscapePlugins) { KURL completedURL; if (!url.isEmpty()) completedURL = frame->loader()->completeURL(url); if (frame->loader()->client()->objectContentType(completedURL, serviceType) == ObjectContentNetscapePlugin) return; } bool success = frame->loader()->requestObject(this, url, AtomicString(o->name()), serviceType, paramNames, paramValues); if (!success && m_hasFallbackContent) o->renderFallbackContent(); } else if (element()->hasTagName(embedTag)) { HTMLEmbedElement *o = static_cast<HTMLEmbedElement*>(element()); o->setNeedWidgetUpdate(false); url = o->url(); serviceType = o->serviceType(); if (url.isEmpty() && serviceType.isEmpty()) return; if (!isURLAllowed(document(), url)) return; // add all attributes set on the embed object NamedAttrMap* a = o->attributes(); if (a) { for (unsigned i = 0; i < a->length(); ++i) { Attribute* it = a->attributeItem(i); paramNames.append(it->name().localName().string()); paramValues.append(it->value().string()); } } if (onlyCreateNonNetscapePlugins) { KURL completedURL; if (!url.isEmpty()) completedURL = frame->loader()->completeURL(url); if (frame->loader()->client()->objectContentType(completedURL, serviceType) == ObjectContentNetscapePlugin) return; } frame->loader()->requestObject(this, url, o->getAttribute(nameAttr), serviceType, paramNames, paramValues); } }
void Step::nodesInAxis(Node* context, NodeSet& nodes) const { ASSERT(nodes.isEmpty()); switch (m_axis) { case ChildAxis: if (context->isAttributeNode()) // In XPath model, attribute nodes do not have children. return; for (Node* n = context->firstChild(); n; n = n->nextSibling()) if (nodeMatches(n)) nodes.append(n); return; case DescendantAxis: if (context->isAttributeNode()) // In XPath model, attribute nodes do not have children. return; for (Node* n = context->firstChild(); n; n = n->traverseNextNode(context)) if (nodeMatches(n)) nodes.append(n); return; case ParentAxis: if (context->isAttributeNode()) { Node* n = static_cast<Attr*>(context)->ownerElement(); if (nodeMatches(n)) nodes.append(n); } else { Node* n = context->parentNode(); if (n && nodeMatches(n)) nodes.append(n); } return; case AncestorAxis: { Node* n = context; if (context->isAttributeNode()) { n = static_cast<Attr*>(context)->ownerElement(); if (nodeMatches(n)) nodes.append(n); } for (n = n->parentNode(); n; n = n->parentNode()) if (nodeMatches(n)) nodes.append(n); nodes.reverse(); return; } case FollowingSiblingAxis: if (context->nodeType() == Node::ATTRIBUTE_NODE || context->nodeType() == Node::XPATH_NAMESPACE_NODE) return; for (Node* n = context->nextSibling(); n; n = n->nextSibling()) if (nodeMatches(n)) nodes.append(n); return; case PrecedingSiblingAxis: if (context->nodeType() == Node::ATTRIBUTE_NODE || context->nodeType() == Node::XPATH_NAMESPACE_NODE) return; for (Node* n = context->previousSibling(); n; n = n->previousSibling()) if (nodeMatches(n)) nodes.append(n); nodes.reverse(); return; case FollowingAxis: if (context->isAttributeNode()) { Node* p = static_cast<Attr*>(context)->ownerElement(); while ((p = p->traverseNextNode())) if (nodeMatches(p)) nodes.append(p); } else { for (Node* p = context; !isRootDomNode(p); p = p->parentNode()) { for (Node* n = p->nextSibling(); n; n = n->nextSibling()) { if (nodeMatches(n)) nodes.append(n); for (Node* c = n->firstChild(); c; c = c->traverseNextNode(n)) if (nodeMatches(c)) nodes.append(c); } } } return; case PrecedingAxis: if (context->isAttributeNode()) context = static_cast<Attr*>(context)->ownerElement(); for (Node* p = context; !isRootDomNode(p); p = p->parentNode()) { for (Node* n = p->previousSibling(); n ; n = n->previousSibling()) { if (nodeMatches(n)) nodes.append(n); for (Node* c = n->firstChild(); c; c = c->traverseNextNode(n)) if (nodeMatches(c)) nodes.append(c); } } nodes.markSorted(false); return; case AttributeAxis: { if (context->nodeType() != Node::ELEMENT_NODE) return; // Avoid lazily creating attribute nodes for attributes that we do not need anyway. if (m_nodeTest.kind() == NodeTest::NameTest && m_nodeTest.data() != "*") { RefPtr<Node> n = static_cast<Element*>(context)->getAttributeNodeNS(m_nodeTest.namespaceURI(), m_nodeTest.data()); if (n && n->namespaceURI() != "http://www.w3.org/2000/xmlns/") // In XPath land, namespace nodes are not accessible on the attribute axis. nodes.append(n.release()); return; } NamedAttrMap* attrs = context->attributes(); if (!attrs) return; for (unsigned long i = 0; i < attrs->length(); ++i) { RefPtr<Node> n = attrs->item(i); if (nodeMatches(n.get())) nodes.append(n.release()); } return; } case NamespaceAxis: // XPath namespace nodes are not implemented yet. return; case SelfAxis: if (nodeMatches(context)) nodes.append(context); return; case DescendantOrSelfAxis: if (nodeMatches(context)) nodes.append(context); if (context->isAttributeNode()) // In XPath model, attribute nodes do not have children. return; for (Node* n = context->firstChild(); n; n = n->traverseNextNode(context)) if (nodeMatches(n)) nodes.append(n); return; case AncestorOrSelfAxis: { if (nodeMatches(context)) nodes.append(context); Node* n = context; if (context->isAttributeNode()) { n = static_cast<Attr*>(context)->ownerElement(); if (nodeMatches(n)) nodes.append(n); } for (n = n->parentNode(); n; n = n->parentNode()) if (nodeMatches(n)) nodes.append(n); nodes.reverse(); return; } } ASSERT_NOT_REACHED(); }