void Element::cloneAttributesFromElement(const Element& other) { other.synchronizeAllAttributes(); if (!other.m_elementData) { m_elementData.clear(); return; } const AtomicString& oldID = getIdAttribute(); const AtomicString& newID = other.getIdAttribute(); if (!oldID.isNull() || !newID.isNull()) updateId(oldID, newID); // If 'other' has a mutable ElementData, convert it to an immutable one so we can share it between both elements. // We can only do this if there are no presentation attributes and sharing the data won't result in different case sensitivity of class or id. if (other.m_elementData->isUnique()) const_cast<Element&>(other).m_elementData = toUniqueElementData(other.m_elementData)->makeShareableCopy(); if (!other.m_elementData->isUnique()) m_elementData = other.m_elementData; else m_elementData = other.m_elementData->makeUniqueCopy(); AttributeCollection attributes = m_elementData->attributes(); AttributeCollection::iterator end = attributes.end(); for (AttributeCollection::iterator it = attributes.begin(); it != end; ++it) attributeChangedFromParserOrByCloning(it->name(), it->value(), ModifiedByCloning); }
void StyledMarkupAccumulator::appendElement(StringBuilder& out, Element& element, bool addDisplayInline) { const bool documentIsHTML = element.document().isHTMLDocument(); appendOpenTag(out, element, 0); const bool shouldAnnotateOrForceInline = element.isHTMLElement() && (shouldAnnotate() || addDisplayInline); const bool shouldOverrideStyleAttr = shouldAnnotateOrForceInline || shouldApplyWrappingStyle(element); AttributeCollection attributes = element.attributes(); AttributeCollection::iterator end = attributes.end(); for (AttributeCollection::iterator it = attributes.begin(); it != end; ++it) { // We'll handle the style attribute separately, below. if (it->name() == HTMLNames::styleAttr && shouldOverrideStyleAttr) continue; appendAttribute(out, element, *it, 0); } if (shouldOverrideStyleAttr) { RefPtr<EditingStyle> newInlineStyle = nullptr; if (shouldApplyWrappingStyle(element)) { newInlineStyle = m_wrappingStyle->copy(); newInlineStyle->removePropertiesInElementDefaultStyle(&element); newInlineStyle->removeStyleConflictingWithStyleOfElement(&element); } else newInlineStyle = EditingStyle::create(); if (element.isStyledElement() && element.inlineStyle()) newInlineStyle->overrideWithStyle(element.inlineStyle()); if (shouldAnnotateOrForceInline) { if (shouldAnnotate()) newInlineStyle->mergeStyleFromRulesForSerialization(&toHTMLElement(element)); if (&element == m_highestNodeToBeSerialized && m_shouldAnnotate == AnnotateForNavigationTransition) newInlineStyle->addAbsolutePositioningFromElement(element); if (addDisplayInline) newInlineStyle->forceInline(); } if (!newInlineStyle->isEmpty()) { out.appendLiteral(" style=\""); appendAttributeValue(out, newInlineStyle->style()->asText(), documentIsHTML); out.append('\"'); } } appendCloseTag(out, element); }
bool ElementData::isEquivalent(const ElementData* other) const { AttributeCollection attributes = this->attributes(); if (!other) return attributes.isEmpty(); AttributeCollection otherAttributes = other->attributes(); if (attributes.size() != otherAttributes.size()) return false; AttributeCollection::iterator end = attributes.end(); for (AttributeCollection::iterator it = attributes.begin(); it != end; ++it) { const Attribute* otherAttr = otherAttributes.find(it->name()); if (!otherAttr || it->value() != otherAttr->value()) return false; } return true; }
// TODO(yosin): We should utilize |MarkupFormatter| here to share code, // especially escaping attribute values, done by |WebEntities| |m_htmlEntities| // and |m_xmlEntities|. void WebPageSerializerImpl::openTagToString(Element* element, SerializeDomParam* param) { bool needSkip; StringBuilder result; // Do pre action for open tag. result.append(preActionBeforeSerializeOpenTag(element, param, &needSkip)); if (needSkip) return; // Add open tag result.append('<'); result.append(element->nodeName().lower()); // Go through all attributes and serialize them. AttributeCollection attributes = element->attributes(); AttributeCollection::iterator end = attributes.end(); for (AttributeCollection::iterator it = attributes.begin(); it != end; ++it) { result.append(' '); // Add attribute pair result.append(it->name().toString()); result.appendLiteral("=\""); if (!it->value().isEmpty()) { const String& attrValue = it->value(); // Check whether we need to replace some resource links // with local resource paths. const QualifiedName& attrName = it->name(); if (element->hasLegalLinkAttribute(attrName)) { // For links start with "javascript:", we do not change it. if (attrValue.startsWith("javascript:", TextCaseInsensitive)) { result.append(m_htmlEntities.convertEntitiesInString(attrValue)); } else { // Get the absolute link WebLocalFrameImpl* subFrame = WebLocalFrameImpl::fromFrameOwnerElement(element); String completeURL = subFrame ? subFrame->frame()->document()->url() : param->document->completeURL(attrValue); // Check whether we have local files for those link. if (m_localLinks.contains(completeURL)) { if (!param->directoryName.isEmpty()) { result.appendLiteral("./"); result.append(param->directoryName); result.append('/'); } result.append(m_htmlEntities.convertEntitiesInString(m_localLinks.get(completeURL))); } else { result.append(m_htmlEntities.convertEntitiesInString(completeURL)); } } } else { if (param->isHTMLDocument) result.append(m_htmlEntities.convertEntitiesInString(attrValue)); else result.append(m_xmlEntities.convertEntitiesInString(attrValue)); } } result.append('\"'); } // Do post action for open tag. String addedContents = postActionAfterSerializeOpenTag(element, param); // Complete the open tag for element when it has child/children. if (element->hasChildren() || param->haveAddedContentsBeforeEnd) result.append('>'); // Append the added contents generate in post action of open tag. result.append(addedContents); // Save the result to data buffer. saveHTMLContentToBuffer(result.toString(), param); }
// Result nodes are ordered in axis order. Node test (including merged // predicates) is applied. void Step::nodesInAxis(EvaluationContext& evaluationContext, Node* context, NodeSet& nodes) const { ASSERT(nodes.isEmpty()); switch (m_axis) { case ChildAxis: // In XPath model, attribute nodes do not have children. if (context->isAttributeNode()) return; for (Node* n = context->firstChild(); n; n = n->nextSibling()) { if (nodeMatches(evaluationContext, n, ChildAxis, nodeTest())) nodes.append(n); } return; case DescendantAxis: // In XPath model, attribute nodes do not have children. if (context->isAttributeNode()) return; for (Node* n = context->firstChild(); n; n = NodeTraversal::next(*n, context)) { if (nodeMatches(evaluationContext, n, DescendantAxis, nodeTest())) nodes.append(n); } return; case ParentAxis: if (context->isAttributeNode()) { Element* n = toAttr(context)->ownerElement(); if (nodeMatches(evaluationContext, n, ParentAxis, nodeTest())) nodes.append(n); } else { ContainerNode* n = context->parentNode(); if (n && nodeMatches(evaluationContext, n, ParentAxis, nodeTest())) nodes.append(n); } return; case AncestorAxis: { Node* n = context; if (context->isAttributeNode()) { n = toAttr(context)->ownerElement(); if (nodeMatches(evaluationContext, n, AncestorAxis, nodeTest())) nodes.append(n); } for (n = n->parentNode(); n; n = n->parentNode()) { if (nodeMatches(evaluationContext, n, AncestorAxis, nodeTest())) nodes.append(n); } nodes.markSorted(false); return; } case FollowingSiblingAxis: if (context->nodeType() == Node::ATTRIBUTE_NODE) return; for (Node* n = context->nextSibling(); n; n = n->nextSibling()) { if (nodeMatches(evaluationContext, n, FollowingSiblingAxis, nodeTest())) nodes.append(n); } return; case PrecedingSiblingAxis: if (context->nodeType() == Node::ATTRIBUTE_NODE) return; for (Node* n = context->previousSibling(); n; n = n->previousSibling()) { if (nodeMatches(evaluationContext, n, PrecedingSiblingAxis, nodeTest())) nodes.append(n); } nodes.markSorted(false); return; case FollowingAxis: if (context->isAttributeNode()) { for (Node* p = NodeTraversal::next(*toAttr(context)->ownerElement()); p; p = NodeTraversal::next(*p)) { if (nodeMatches(evaluationContext, p, FollowingAxis, nodeTest())) nodes.append(p); } } else { for (Node* p = context; !isRootDomNode(p); p = p->parentNode()) { for (Node* n = p->nextSibling(); n; n = n->nextSibling()) { if (nodeMatches(evaluationContext, n, FollowingAxis, nodeTest())) nodes.append(n); for (Node* c = n->firstChild(); c; c = NodeTraversal::next(*c, n)) { if (nodeMatches(evaluationContext, c, FollowingAxis, nodeTest())) nodes.append(c); } } } } return; case PrecedingAxis: { if (context->isAttributeNode()) context = toAttr(context)->ownerElement(); Node* n = context; while (ContainerNode* parent = n->parentNode()) { for (n = NodeTraversal::previous(*n); n != parent; n = NodeTraversal::previous(*n)) { if (nodeMatches(evaluationContext, n, PrecedingAxis, nodeTest())) nodes.append(n); } n = parent; } nodes.markSorted(false); return; } case AttributeAxis: { if (!context->isElementNode()) return; Element* contextElement = toElement(context); // Avoid lazily creating attribute nodes for attributes that we do not // need anyway. if (nodeTest().kind() == NodeTest::NameTest && nodeTest().data() != starAtom) { RefPtrWillBeRawPtr<Node> n = contextElement->getAttributeNodeNS(nodeTest().namespaceURI(), nodeTest().data()); // In XPath land, namespace nodes are not accessible on the attribute axis. if (n && n->namespaceURI() != XMLNSNames::xmlnsNamespaceURI) { // Still need to check merged predicates. if (nodeMatches(evaluationContext, n.get(), AttributeAxis, nodeTest())) nodes.append(n.release()); } return; } AttributeCollection attributes = contextElement->attributes(); AttributeCollection::iterator end = attributes.end(); for (AttributeCollection::iterator it = attributes.begin(); it != end; ++it) { RefPtrWillBeRawPtr<Attr> attr = contextElement->ensureAttr(it->name()); if (nodeMatches(evaluationContext, attr.get(), AttributeAxis, nodeTest())) nodes.append(attr.release()); } return; } case NamespaceAxis: // XPath namespace nodes are not implemented. return; case SelfAxis: if (nodeMatches(evaluationContext, context, SelfAxis, nodeTest())) nodes.append(context); return; case DescendantOrSelfAxis: if (nodeMatches(evaluationContext, context, DescendantOrSelfAxis, nodeTest())) nodes.append(context); // In XPath model, attribute nodes do not have children. if (context->isAttributeNode()) return; for (Node* n = context->firstChild(); n; n = NodeTraversal::next(*n, context)) { if (nodeMatches(evaluationContext, n, DescendantOrSelfAxis, nodeTest())) nodes.append(n); } return; case AncestorOrSelfAxis: { if (nodeMatches(evaluationContext, context, AncestorOrSelfAxis, nodeTest())) nodes.append(context); Node* n = context; if (context->isAttributeNode()) { n = toAttr(context)->ownerElement(); if (nodeMatches(evaluationContext, n, AncestorOrSelfAxis, nodeTest())) nodes.append(n); } for (n = n->parentNode(); n; n = n->parentNode()) { if (nodeMatches(evaluationContext, n, AncestorOrSelfAxis, nodeTest())) nodes.append(n); } nodes.markSorted(false); return; } } ASSERT_NOT_REACHED(); }