void StyledMarkupTraverser<Strategy>::appendStartMarkup(Node& node) { if (!m_accumulator) return; switch (node.getNodeType()) { case Node::TEXT_NODE: { Text& text = toText(node); if (text.parentElement() && isHTMLTextAreaElement(text.parentElement())) { m_accumulator->appendText(text); break; } RawPtr<EditingStyle> inlineStyle = nullptr; if (shouldApplyWrappingStyle(text)) { inlineStyle = m_wrappingStyle->copy(); // FIXME: <rdar://problem/5371536> Style rules that match pasted content can change it's appearance // Make sure spans are inline style in paste side e.g. span { display: block }. inlineStyle->forceInline(); // FIXME: Should this be included in forceInline? inlineStyle->style()->setProperty(CSSPropertyFloat, CSSValueNone); } m_accumulator->appendTextWithInlineStyle(text, inlineStyle); break; } case Node::ELEMENT_NODE: { Element& element = toElement(node); if ((element.isHTMLElement() && shouldAnnotate()) || shouldApplyWrappingStyle(element)) { RawPtr<EditingStyle> inlineStyle = createInlineStyle(element); m_accumulator->appendElementWithInlineStyle(element, inlineStyle); break; } m_accumulator->appendElement(element); break; } default: m_accumulator->appendStartMarkup(node); break; } }
String StyledMarkupSerializer<Strategy>::createMarkup() { StyledMarkupAccumulator markupAccumulator(m_shouldResolveURLs, toTextOffset(m_start.parentAnchoredEquivalent()), toTextOffset(m_end.parentAnchoredEquivalent()), m_start.document(), m_shouldAnnotate, m_convertBlocksToInlines); Node* pastEnd = m_end.nodeAsRangePastLastNode(); Node* firstNode = m_start.nodeAsRangeFirstNode(); const VisiblePositionTemplate<Strategy> visibleStart = createVisiblePosition(m_start); const VisiblePositionTemplate<Strategy> visibleEnd = createVisiblePosition(m_end); if (shouldAnnotate() && needInterchangeNewlineAfter(visibleStart)) { markupAccumulator.appendInterchangeNewline(); if (visibleStart.deepEquivalent() == previousPositionOf(visibleEnd).deepEquivalent()) return markupAccumulator.takeResults(); firstNode = nextPositionOf(visibleStart).deepEquivalent().anchorNode(); if (pastEnd && PositionTemplate<Strategy>::beforeNode(firstNode).compareTo(PositionTemplate<Strategy>::beforeNode(pastEnd)) >= 0) { // This condition hits in editing/pasteboard/copy-display-none.html. return markupAccumulator.takeResults(); } } if (!m_lastClosed) m_lastClosed = StyledMarkupTraverser<Strategy>().traverse(firstNode, pastEnd); StyledMarkupTraverser<Strategy> traverser(&markupAccumulator, m_lastClosed); Node* lastClosed = traverser.traverse(firstNode, pastEnd); if (m_highestNodeToBeSerialized && lastClosed) { // TODO(hajimehoshi): This is calculated at createMarkupInternal too. Node* commonAncestor = Strategy::commonAncestor(*m_start.computeContainerNode(), *m_end.computeContainerNode()); ASSERT(commonAncestor); HTMLBodyElement* body = toHTMLBodyElement(enclosingElementWithTag(firstPositionInNode(commonAncestor), bodyTag)); HTMLBodyElement* fullySelectedRoot = nullptr; // FIXME: Do this for all fully selected blocks, not just the body. if (body && areSameRanges(body, m_start, m_end)) fullySelectedRoot = body; // Also include all of the ancestors of lastClosed up to this special ancestor. // FIXME: What is ancestor? for (ContainerNode* ancestor = Strategy::parent(*lastClosed); ancestor; ancestor = Strategy::parent(*ancestor)) { if (ancestor == fullySelectedRoot && !markupAccumulator.convertBlocksToInlines()) { RawPtr<EditingStyle> fullySelectedRootStyle = styleFromMatchedRulesAndInlineDecl(fullySelectedRoot); // Bring the background attribute over, but not as an attribute because a background attribute on a div // appears to have no effect. if ((!fullySelectedRootStyle || !fullySelectedRootStyle->style() || !fullySelectedRootStyle->style()->getPropertyCSSValue(CSSPropertyBackgroundImage)) && fullySelectedRoot->hasAttribute(backgroundAttr)) fullySelectedRootStyle->style()->setProperty(CSSPropertyBackgroundImage, "url('" + fullySelectedRoot->getAttribute(backgroundAttr) + "')"); if (fullySelectedRootStyle->style()) { // Reset the CSS properties to avoid an assertion error in addStyleMarkup(). // This assertion is caused at least when we select all text of a <body> element whose // 'text-decoration' property is "inherit", and copy it. if (!propertyMissingOrEqualToNone(fullySelectedRootStyle->style(), CSSPropertyTextDecoration)) fullySelectedRootStyle->style()->setProperty(CSSPropertyTextDecoration, CSSValueNone); if (!propertyMissingOrEqualToNone(fullySelectedRootStyle->style(), CSSPropertyWebkitTextDecorationsInEffect)) fullySelectedRootStyle->style()->setProperty(CSSPropertyWebkitTextDecorationsInEffect, CSSValueNone); markupAccumulator.wrapWithStyleNode(fullySelectedRootStyle->style()); } } else { RawPtr<EditingStyle> style = traverser.createInlineStyleIfNeeded(*ancestor); // Since this node and all the other ancestors are not in the selection we want // styles that affect the exterior of the node not to be not included. // If the node is not fully selected by the range, then we don't want to keep styles that affect its relationship to the nodes around it // only the ones that affect it and the nodes within it. if (style && style->style()) style->style()->removeProperty(CSSPropertyFloat); traverser.wrapWithNode(*ancestor, style); } if (ancestor == m_highestNodeToBeSerialized) break; } } // FIXME: The interchange newline should be placed in the block that it's in, not after all of the content, unconditionally. if (shouldAnnotate() && needInterchangeNewlineAt(visibleEnd)) markupAccumulator.appendInterchangeNewline(); return markupAccumulator.takeResults(); }