⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 markup.cpp

📁 linux下开源浏览器WebKit的源码,市面上的很多商用浏览器都是移植自WebKit
💻 CPP
📖 第 1 页 / 共 4 页
字号:
            Element* e = static_cast<Element*>(n);            NamedAttrMap* attrs = e->attributes();            unsigned length = attrs->length();            for (unsigned i = 0; i < length; i++) {                Attribute* attr = attrs->attributeItem(i);                if (e->isURLAttribute(attr))                    changes.append(AttributeChange(e, attr->name(), KURL(parsedBaseURL, attr->value()).string()));            }        }    }    size_t numChanges = changes.size();    for (size_t i = 0; i < numChanges; ++i)        changes[i].apply();}static bool needInterchangeNewlineAfter(const VisiblePosition& v){    VisiblePosition next = v.next();    Node* upstreamNode = next.deepEquivalent().upstream().node();    Node* downstreamNode = v.deepEquivalent().downstream().node();    // Add an interchange newline if a paragraph break is selected and a br won't already be added to the markup to represent it.    return isEndOfParagraph(v) && isStartOfParagraph(next) && !(upstreamNode->hasTagName(brTag) && upstreamNode == downstreamNode);}static PassRefPtr<CSSMutableStyleDeclaration> styleFromMatchedRulesAndInlineDecl(const Node* node){    if (!node->isHTMLElement())        return 0;        // FIXME: Having to const_cast here is ugly, but it is quite a bit of work to untangle    // the non-const-ness of styleFromMatchedRulesForElement.    HTMLElement* element = const_cast<HTMLElement*>(static_cast<const HTMLElement*>(node));    RefPtr<CSSMutableStyleDeclaration> style = styleFromMatchedRulesForElement(element);    RefPtr<CSSMutableStyleDeclaration> inlineStyleDecl = element->getInlineStyleDecl();    style->merge(inlineStyleDecl.get());    return style.release();}static bool propertyMissingOrEqualToNone(CSSMutableStyleDeclaration* style, int propertyID){    if (!style)        return false;    RefPtr<CSSValue> value = style->getPropertyCSSValue(propertyID);    if (!value)        return true;    if (!value->isPrimitiveValue())        return false;    return static_cast<CSSPrimitiveValue*>(value.get())->getIdent() == CSSValueNone;}static bool elementHasTextDecorationProperty(const Node* node){    RefPtr<CSSMutableStyleDeclaration> style = styleFromMatchedRulesAndInlineDecl(node);    if (!style)        return false;    return !propertyMissingOrEqualToNone(style.get(), CSSPropertyTextDecoration);}static String joinMarkups(const Vector<String>& preMarkups, const Vector<String>& postMarkups){    size_t length = 0;    size_t preCount = preMarkups.size();    for (size_t i = 0; i < preCount; ++i)        length += preMarkups[i].length();    size_t postCount = postMarkups.size();    for (size_t i = 0; i < postCount; ++i)        length += postMarkups[i].length();    Vector<UChar> result;    result.reserveInitialCapacity(length);    for (size_t i = preCount; i > 0; --i)        append(result, preMarkups[i - 1]);    for (size_t i = 0; i < postCount; ++i)        append(result, postMarkups[i]);    return String::adopt(result);}static bool isSpecialAncestorBlock(Node* node){    if (!node || !isBlock(node))        return false;            return node->hasTagName(listingTag) ||           node->hasTagName(olTag) ||           node->hasTagName(preTag) ||           node->hasTagName(tableTag) ||           node->hasTagName(ulTag) ||           node->hasTagName(xmpTag) ||           node->hasTagName(h1Tag) ||           node->hasTagName(h2Tag) ||           node->hasTagName(h3Tag) ||           node->hasTagName(h4Tag) ||           node->hasTagName(h5Tag);}// FIXME: Shouldn't we omit style info when annotate == DoNotAnnotateForInterchange? // FIXME: At least, annotation and style info should probably not be included in range.markupString()String createMarkup(const Range* range, Vector<Node*>* nodes, EAnnotateForInterchange annotate, bool convertBlocksToInlines){    DEFINE_STATIC_LOCAL(const String, interchangeNewlineString, ("<br class=\"" AppleInterchangeNewline "\">"));    if (!range)        return "";    Document* document = range->ownerDocument();    if (!document)        return "";    bool documentIsHTML = document->isHTMLDocument();    // Disable the delete button so it's elements are not serialized into the markup,    // but make sure neither endpoint is inside the delete user interface.    Frame* frame = document->frame();    DeleteButtonController* deleteButton = frame ? frame->editor()->deleteButtonController() : 0;    RefPtr<Range> updatedRange = avoidIntersectionWithNode(range, deleteButton ? deleteButton->containerElement() : 0);    if (!updatedRange)        return "";    if (deleteButton)        deleteButton->disable();    ExceptionCode ec = 0;    bool collapsed = updatedRange->collapsed(ec);    ASSERT(ec == 0);    if (collapsed)        return "";    Node* commonAncestor = updatedRange->commonAncestorContainer(ec);    ASSERT(ec == 0);    if (!commonAncestor)        return "";    document->updateLayoutIgnorePendingStylesheets();    Vector<String> markups;    Vector<String> preMarkups;    Node* pastEnd = updatedRange->pastLastNode();    Node* lastClosed = 0;    Vector<Node*> ancestorsToClose;        Node* startNode = updatedRange->firstNode();    VisiblePosition visibleStart(updatedRange->startPosition(), VP_DEFAULT_AFFINITY);    VisiblePosition visibleEnd(updatedRange->endPosition(), VP_DEFAULT_AFFINITY);    if (annotate && needInterchangeNewlineAfter(visibleStart)) {        if (visibleStart == visibleEnd.previous()) {            if (deleteButton)                deleteButton->enable();            return interchangeNewlineString;        }        markups.append(interchangeNewlineString);        startNode = visibleStart.next().deepEquivalent().node();    }    Node* next;    for (Node* n = startNode; n != pastEnd; n = next) {            // According to <rdar://problem/5730668>, it is possible for n to blow past pastEnd and become null here.  This         // shouldn't be possible.  This null check will prevent crashes (but create too much markup) and the ASSERT will         // hopefully lead us to understanding the problem.        ASSERT(n);        if (!n)            break;            next = n->traverseNextNode();        bool skipDescendants = false;        bool addMarkupForNode = true;                if (!n->renderer() && !enclosingNodeWithTag(Position(n, 0), selectTag)) {            skipDescendants = true;            addMarkupForNode = false;            next = n->traverseNextSibling();            // Don't skip over pastEnd.            if (pastEnd && pastEnd->isDescendantOf(n))                next = pastEnd;        }        if (isBlock(n) && canHaveChildrenForEditing(n) && next == pastEnd)            // Don't write out empty block containers that aren't fully selected.            continue;                // Add the node to the markup.        if (addMarkupForNode) {            markups.append(getStartMarkup(n, updatedRange.get(), annotate));            if (nodes)                nodes->append(n);        }                if (n->firstChild() == 0 || skipDescendants) {            // Node has no children, or we are skipping it's descendants, add its close tag now.            if (addMarkupForNode) {                markups.append(getEndMarkup(n));                lastClosed = n;            }                        // Check if the node is the last leaf of a tree.            if (!n->nextSibling() || next == pastEnd) {                if (!ancestorsToClose.isEmpty()) {                    // Close up the ancestors.                    do {                        Node *ancestor = ancestorsToClose.last();                        if (next != pastEnd && next->isDescendantOf(ancestor))                            break;                        // Not at the end of the range, close ancestors up to sibling of next node.                        markups.append(getEndMarkup(ancestor));                        lastClosed = ancestor;                        ancestorsToClose.removeLast();                    } while (!ancestorsToClose.isEmpty());                }                                // Surround the currently accumulated markup with markup for ancestors we never opened as we leave the subtree(s) rooted at those ancestors.                Node* nextParent = next ? next->parentNode() : 0;                if (next != pastEnd && n != nextParent) {                    Node* lastAncestorClosedOrSelf = n->isDescendantOf(lastClosed) ? lastClosed : n;                    for (Node *parent = lastAncestorClosedOrSelf->parent(); parent != 0 && parent != nextParent; parent = parent->parentNode()) {                        // All ancestors that aren't in the ancestorsToClose list should either be a) unrendered:                        if (!parent->renderer())                            continue;                        // or b) ancestors that we never encountered during a pre-order traversal starting at startNode:                        ASSERT(startNode->isDescendantOf(parent));                        preMarkups.append(getStartMarkup(parent, updatedRange.get(), annotate));                        markups.append(getEndMarkup(parent));                        if (nodes)                            nodes->append(parent);                        lastClosed = parent;                    }                }            }        } else if (addMarkupForNode && !skipDescendants)            // We added markup for this node, and we're descending into it.  Set it to close eventually.            ancestorsToClose.append(n);    }        // Include ancestors that aren't completely inside the range but are required to retain     // the structure and appearance of the copied markup.    Node* specialCommonAncestor = 0;    Node* commonAncestorBlock = commonAncestor ? enclosingBlock(commonAncestor) : 0;    if (annotate && commonAncestorBlock) {        if (commonAncestorBlock->hasTagName(tbodyTag) || commonAncestorBlock->hasTagName(trTag)) {            Node* table = commonAncestorBlock->parentNode();            while (table && !table->hasTagName(tableTag))                table = table->parentNode();            if (table)                specialCommonAncestor = table;        } else if (isSpecialAncestorBlock(commonAncestorBlock))            specialCommonAncestor = commonAncestorBlock;    }                                          // Retain the Mail quote level by including all ancestor mail block quotes.    if (lastClosed && annotate) {        for (Node *ancestor = lastClosed->parentNode(); ancestor; ancestor = ancestor->parentNode())            if (isMailBlockquote(ancestor))                specialCommonAncestor = ancestor;    }        Node* checkAncestor = specialCommonAncestor ? specialCommonAncestor : commonAncestor;    if (checkAncestor->renderer()) {        RefPtr<CSSMutableStyleDeclaration> checkAncestorStyle = computedStyle(checkAncestor)->copyInheritableProperties();        if (!propertyMissingOrEqualToNone(checkAncestorStyle.get(), CSSPropertyWebkitTextDecorationsInEffect))            specialCommonAncestor = enclosingNodeOfType(Position(checkAncestor, 0), &elementHasTextDecorationProperty);    }        // If a single tab is selected, commonAncestor will be a text node inside a tab span.    // If two or more tabs are selected, commonAncestor will be the tab span.    // In either case, if there is a specialCommonAncestor already, it will necessarily be above     // any tab span that needs to be included.    if (!specialCommonAncestor && isTabSpanTextNode(commonAncestor))        specialCommonAncestor = commonAncestor->parentNode();    if (!specialCommonAncestor && isTabSpanNode(commonAncestor))        specialCommonAncestor = commonAncestor;            if (Node *enclosingAnchor = enclosingNodeWithTag(Position(specialCommonAncestor ? specialCommonAncestor : commonAncestor, 0), aTag))        specialCommonAncestor = enclosingAnchor;        Node* body = enclosingNodeWithTag(Position(commonAncestor, 0), bodyTag);    // FIXME: Only include markup for a fully selected root (and ancestors of lastClosed up to that root) if    // there are styles/attributes on those nodes that need to be included to preserve the appearance of the copied markup.    // FIXME: Do this for all fully selected blocks, not just the body.    Node* fullySelectedRoot = body && *VisibleSelection::selectionFromContentsOfNode(body).toNormalizedRange() == *updatedRange ? body : 0;    if (annotate && fullySelectedRoot)        specialCommonAncestor = fullySelectedRoot;            if (specialCommonAncestor && lastClosed) {        // Also include all of the ancestors of lastClosed up to this special ancestor.        for (Node* ancestor = lastClosed->parentNode(); ancestor; ancestor = ancestor->parentNode()) {            if (ancestor == fullySelectedRoot && !convertBlocksToInlines) {                RefPtr<CSSMutableStyleDeclaration> style = 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 (!style->getPropertyCSSValue(CSSPropertyBackgroundImage) && static_cast<Element*>(fullySelectedRoot)->hasAttribute(backgroundAttr))                    style->setProperty(CSSPropertyBackgroundImage, "url('" + static_cast<Element*>(fullySelectedRoot)->getAttribute(backgroundAttr) + "')");                                if (style->length()) {                    Vector<UChar> openTag;                    DEFINE_STATIC_LOCAL(const String, divStyle, ("<div style=\""));                    append(openTag, divStyle);                    appendAttributeValue(openTag, style->cssText(), documentIsHTML);                    openTag.append('\"');                    openTag.append('>');                    preMarkups.append(String::adopt(openTag));                    DEFINE_STATIC_LOCAL(const String, divCloseTag, ("</div>"));                    markups.append(divCloseTag);                }

⌨️ 快捷键说明

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