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();
}