markup.cpp

来自「最新Nokia手机浏览器全套源代码完美版。」· C++ 代码 · 共 632 行 · 第 1/2 页

CPP
632
字号

    int exceptionCode = 0;
    NodeImpl *commonAncestor = range->commonAncestorContainer(exceptionCode);
    ASSERT(exceptionCode == 0);

    DocumentImpl *doc = commonAncestor->getDocument();
    doc->updateLayout();

    NodeImpl *commonAncestorBlock = 0;
    if (commonAncestor != 0) {
        commonAncestorBlock = commonAncestor->enclosingBlockFlowElement();
    }
    if (commonAncestorBlock == 0) {
        return "";
    }

    QStringList markups;
    NodeImpl *pastEnd = range->pastEndNode();
    NodeImpl *lastClosed = 0;
    QPtrList<NodeImpl> ancestorsToClose;

    // calculate the "default style" for this markup
    Position pos(doc->documentElement(), 0);
    CSSComputedStyleDeclarationImpl *computedStyle = pos.computedStyle();
    computedStyle->ref();
    CSSMutableStyleDeclarationImpl *defaultStyle = computedStyle->copyInheritableProperties();
    computedStyle->deref();

    defaultStyle->ref();

    NodeImpl *startNode = range->startNode();
    VisiblePosition visibleStart(range->startPosition(), VP_DEFAULT_AFFINITY);
    VisiblePosition visibleEnd(range->endPosition(), VP_DEFAULT_AFFINITY);
    if (isEndOfBlock(visibleStart)) {
        if (visibleStart == visibleEnd.previous()) {
            defaultStyle->deref();
            return interchangeNewlineString;
        }
        markups.append(interchangeNewlineString);
        startNode = startNode->traverseNextNode();
    }

    // Iterate through the nodes of the range.
    NodeImpl *next;
    for (NodeImpl *n = startNode; n != pastEnd; n = next) {
        next = n->traverseNextNode();

        if (n->isBlockFlow() && next == pastEnd) {
            // Don't write out an empty block.
            continue;
        }

        // Add the node to the markup.
        if (n->renderer()) {
            markups.append(startMarkup(n, range, annotate, defaultStyle));
            if (nodes) {
                nodes->append(n);
            }
        }

        if (n->firstChild() == 0) {
            // Node has no children, add its close tag now.
            if (n->renderer()) {
                markups.append(endMarkup(n));
                lastClosed = n;
            }

            // Check if the node is the last leaf of a tree.
            if (n->nextSibling() == 0 || next == pastEnd) {
                if (!ancestorsToClose.isEmpty()) {
                    // Close up the ancestors.
                    while (NodeImpl *ancestor = ancestorsToClose.last()) {
                        if (next != pastEnd && ancestor == next->parentNode()) {
                            break;
                        }
                        // Not at the end of the range, close ancestors up to sibling of next node.
                        markups.append(endMarkup(ancestor));
                        lastClosed = ancestor;
                        ancestorsToClose.removeLast();
                    }
                } else {
                    // No ancestors to close, but need to add ancestors not in range since next node is in another tree.
                    if (next != pastEnd) {
                        NodeImpl *nextParent = next->parentNode();
                        if (n != nextParent) {
                            for (NodeImpl *parent = n->parent(); parent != 0 && parent != nextParent; parent = parent->parentNode()) {
                                markups.prepend(startMarkup(parent, range, annotate, defaultStyle));
                                markups.append(endMarkup(parent));
                                if (nodes) {
                                    nodes->append(parent);
                                }
                                lastClosed = parent;
                            }
                        }
                    }
                }
            }
        } else if (n->renderer()) {
            // Node is an ancestor, set it to close eventually.
            ancestorsToClose.append(n);
        }
    }

    NodeImpl *rangeStartNode = range->startNode();
    int rangeStartOffset = range->startOffset(exceptionCode);
    ASSERT(exceptionCode == 0);

    // Add ancestors up to the common ancestor block so inline ancestors such as FONT and B are part of the markup.
    if (lastClosed) {
        for (NodeImpl *ancestor = lastClosed->parentNode(); ancestor; ancestor = ancestor->parentNode()) {
            if (RangeImpl::compareBoundaryPoints(ancestor, 0, rangeStartNode, rangeStartOffset) >= 0) {
                // we have already added markup for this node
                continue;
            }
            bool breakAtEnd = false;
            if (commonAncestorBlock == ancestor) {
                NodeImpl::Id id = ancestor->id();
                // Include ancestors that are required to retain the appearance of the copied markup.
                if (id == ID_PRE || id == ID_TABLE || id == ID_OL || id == ID_UL) {
                    breakAtEnd = true;
                } else {
                    break;
                }
            }
            markups.prepend(startMarkup(ancestor, range, annotate, defaultStyle));
            markups.append(endMarkup(ancestor));
            if (nodes) {
                nodes->append(ancestor);
            }
            if (breakAtEnd) {
                break;
            }
        }
    }

    if (annotate) {
        Position pos(endPosition(range));
        NodeImpl *block = pos.node()->enclosingBlockFlowElement();
        NodeImpl *upstreamBlock = pos.upstream().node()->enclosingBlockFlowElement();
        if (block != upstreamBlock) {
            markups.append(interchangeNewlineString);
        }
    }

    // Retain the Mail quote level by including all ancestor mail block quotes.
    for (NodeImpl *ancestor = commonAncestorBlock; ancestor; ancestor = ancestor->parentNode()) {
        if (isMailBlockquote(ancestor)) {
            markups.prepend(startMarkup(ancestor, range, annotate, defaultStyle));
            markups.append(endMarkup(ancestor));
        }
    }

    // add in the "default style" for this markup
    // FIXME: Handle case where value has illegal characters in it, like "
    QString openTag = QString("<span class=\"") + AppleStyleSpanClass + "\" style=\"" + defaultStyle->cssText().string() + "\">";
    markups.prepend(openTag);
    markups.append("</span>");
    defaultStyle->deref();

    return markups.join("");
}

DocumentFragmentImpl *createFragmentFromMarkup(DocumentImpl *document, const QString &markup, const QString &baseURL)
{
    // FIXME: What if the document element is not an HTML element?
    HTMLElementImpl *element = static_cast<HTMLElementImpl *>(document->documentElement());

    DocumentFragmentImpl *fragment = element->createContextualFragment(markup);
    ASSERT(fragment);

    if (!baseURL.isEmpty() && baseURL != document->baseURL())
        completeURLs(fragment, baseURL);

    return fragment;
}

QString createMarkup(const DOM::NodeImpl *node, EChildrenOnly includeChildren,
    QPtrList<DOM::NodeImpl> *nodes, EAnnotateForInterchange annotate)
{
    ASSERT(annotate == DoNotAnnotateForInterchange); // annotation not yet implemented for this code path

    // FIXME: We could take out this if statement if we had more time to test.
    // I'm concerned that making this crash when the document is nil might be too risky a change at the moment.
    DocumentImpl *doc = node->getDocument();
    assert(doc);
    if (doc)
        doc->updateLayout();

    return markup(node, includeChildren, false, nodes);
}

static void createParagraphContentsFromString(DOM::DocumentImpl *document, ElementImpl *paragraph, const QString &string)
{
#if !NOKIA_CHANGES
    int exceptionCode = 0;
    if (string.isEmpty()) {
        NodeImpl *placeHolder = createBlockPlaceholderElement(document);
        paragraph->appendChild(placeHolder, exceptionCode);
        ASSERT(exceptionCode == 0);
        return;
    }

    assert(string.find('\n') == -1);

    QStringList tabList = QStringList::split('\t', string, true);
    QString tabText = "";
    while (!tabList.isEmpty()) {
        QString s = tabList.first();
        tabList.pop_front();

        // append the non-tab textual part
        if (!s.isEmpty()) {
            if (tabText != "") {
                paragraph->appendChild(createTabSpanElement(document, &tabText), exceptionCode);
                ASSERT(exceptionCode == 0);
                tabText = "";
            }
            NodeImpl *textNode = document->createTextNode(s);
            paragraph->appendChild(textNode, exceptionCode);
            ASSERT(exceptionCode == 0);
        }

        // there is a tab after every entry, except the last entry
        // (if the last character is a tab, the list gets an extra empty entry)
        if (!tabList.isEmpty()) {
//#ifdef COALESCE_TAB_SPANS
#if 1
            tabText += '\t';
#else
            paragraph->appendChild(createTabSpanElement(document), exceptionCode);
            ASSERT(exceptionCode == 0);
#endif
        } else if (tabText != "") {
            paragraph->appendChild(createTabSpanElement(document, &tabText), exceptionCode);
            ASSERT(exceptionCode == 0);
        }
    }
#endif
}

DOM::DocumentFragmentImpl *createFragmentFromText(DOM::DocumentImpl *document, const QString &text)
{
    if (!document)
        return 0;

    DocumentFragmentImpl *fragment = document->createDocumentFragment();
    fragment->ref();

    if (!text.isEmpty()) {
        QString string = text;

        // FIXME: Wrap the NBSP's in a span that says "converted space".
        int offset = 0;
        int stringLength = string.length();
        while (1) {
            // FIXME: This only converts plain old spaces, and does not
            // deal with more exotic whitespace. Note that we want to
            // leave newlines and returns alone at this point anyway,
            // since those are handled specially later.
            int spacesPos = string.find("  ", offset);
            if (spacesPos < 0)
                break;

            // Found two adjoining spaces.
            // Now, lookahead to see if these two spaces are followed by:
            //   1. another space and then a non-space
            //   2. another space and then the end of the string
            // If either 1 or 2 is true, replace the three spaces found with nbsp+nbsp+space,
            // otherwise, replace the first two spaces with nbsp+space.
            if ((spacesPos + 3 < stringLength && string[spacesPos + 2] == ' ' && string[spacesPos + 3] != ' ')
                    || (spacesPos + 3 == stringLength && string[spacesPos + 2] == ' ')) {
                string.replace(spacesPos, 3, "\xA0\xA0 ");
            } else {
                string.replace(spacesPos, 2, "\xA0 ");
            }
            offset = spacesPos + 2;
        }

        // Break string into paragraphs. Extra line breaks turn into empty paragraphs.
        string.replace(QString("\r\n"), "\n");
        string.replace('\r', '\n');
        QStringList list = QStringList::split('\n', string, true); // true gets us empty strings in the list
        while (!list.isEmpty()) {
            QString s = list.first();
            list.pop_front();

            int exceptionCode = 0;
            ElementImpl *element;
            if (s.isEmpty() && list.isEmpty()) {
                // For last line, use the "magic BR" rather than a P.
                element = document->createHTMLElement("br", exceptionCode);
                ASSERT(exceptionCode == 0);
                element->ref();
                element->setAttribute(ATTR_CLASS, AppleInterchangeNewline);
            } else {
                element = createDefaultParagraphElement(document);
                element->ref();
                createParagraphContentsFromString(document, element, s);
            }
            fragment->appendChild(element, exceptionCode);
            ASSERT(exceptionCode == 0);
            element->deref();
        }
    }

    // Trick to get the fragment back to the floating state, with 0
    // refs but not destroyed.
    fragment->setParent(document);
    fragment->deref();
    fragment->setParent(0);

    return fragment;
}

}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?