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

📄 htmlediting.cpp

📁 最新Nokia手机浏览器全套源代码完美版。
💻 CPP
📖 第 1 页 / 共 5 页
字号:
    if (pos.isNull())
        return;

    document()->updateLayout();

    VisiblePosition visiblePos(pos, VP_DEFAULT_AFFINITY);
    VisiblePosition visibleParagraphStart(startOfParagraph(visiblePos));
    VisiblePosition visibleParagraphEnd(endOfParagraph(visiblePos, IncludeLineBreak));
    Position paragraphStart = visibleParagraphStart.deepEquivalent().upstream(StayInBlock);
    Position paragraphEnd = visibleParagraphEnd.deepEquivalent().upstream(StayInBlock);
    Position beforeParagraphStart = paragraphStart.upstream(DoNotStayInBlock);

    // Perform some checks to see if we need to perform work in this function.
    if (paragraphStart.node()->isBlockFlow()) {
        if (paragraphEnd.node()->isBlockFlow()) {
            if (!paragraphEnd.node()->isAncestor(paragraphStart.node())) {
                // If the paragraph end is a descendant of paragraph start, then we need to run
                // the rest of this function. If not, we can bail here.
                return;
            }
        }
        else if (paragraphEnd.node()->enclosingBlockFlowElement() != paragraphStart.node()) {
            // The paragraph end is in another block that is an ancestor of the paragraph start.
            // We can bail as we have a full block to work with.
            ASSERT(paragraphStart.node()->isAncestor(paragraphEnd.node()->enclosingBlockFlowElement()));
            return;
        }
        else if (isEndOfDocument(visibleParagraphEnd)) {
            // At the end of the document. We can bail here as well.
            return;
        }
    }

    // Create the block to insert. Most times, this will be a shallow clone of the block containing
    // the start of the selection (the start block), except for two cases:
    //    1) When the start block is a body element.
    //    2) When the start block is a mail blockquote and we are not in a position to insert
    //       the new block as a peer of the start block. This prevents creating an unwanted
    //       additional level of quoting.
    NodeImpl *startBlock = paragraphStart.node()->enclosingBlockFlowElement();
    NodeImpl *newBlock = 0;
    if (startBlock->id() == ID_BODY || (isMailBlockquote(startBlock) && paragraphStart.node() != startBlock))
        newBlock = createDefaultParagraphElement(document());
    else
        newBlock = startBlock->cloneNode(false);

    NodeImpl *moveNode = paragraphStart.node();
    if (paragraphStart.offset() >= paragraphStart.node()->caretMaxOffset())
        moveNode = moveNode->traverseNextNode();
    NodeImpl *endNode = paragraphEnd.node();

    if (paragraphStart.node()->id() == ID_BODY) {
        insertNodeAt(newBlock, paragraphStart.node(), 0);
    }
    else if (paragraphStart.node()->id() == ID_BR) {
        insertNodeAfter(newBlock, paragraphStart.node());
    }
    else if (paragraphStart.node()->isBlockFlow()) {
        insertNodeBefore(newBlock, paragraphStart.node());
    }
    else if (beforeParagraphStart.node()->enclosingBlockFlowElement()->id() != ID_BODY) {
        insertNodeAfter(newBlock, beforeParagraphStart.node()->enclosingBlockFlowElement());
    }
    else {
        insertNodeAfter(newBlock, beforeParagraphStart.node());
    }

    while (moveNode && !moveNode->isBlockFlow()) {
        NodeImpl *next = moveNode->traverseNextSibling();
        removeNode(moveNode);
        appendNode(moveNode, newBlock);
        if (moveNode == endNode)
            break;
        moveNode = next;
    }
}

bool isSpecialElement(const NodeImpl *n)
{
    if (!n)
        return false;

    if (!n->isHTMLElement())
        return false;

    if (n->id() == ID_A && n->hasAnchor())
        return true;

    if (n->id() == ID_UL || n->id() == ID_OL || n->id() == ID_DL)
        return true;

    RenderObject *renderer = n->renderer();
    if (!renderer)
        return false;

    if (renderer->style()->display() == TABLE || renderer->style()->display() == INLINE_TABLE)
        return true;

    if (renderer->style()->isFloating())
        return true;

    if (renderer->style()->position() != STATIC)
        return true;

    return false;
}

// This version of the function is meant to be called on positions in a document fragment,
// so it does not check for a root editable element, it is assumed these nodes will be put
// somewhere editable in the future
static bool isFirstVisiblePositionInSpecialElementInFragment(const Position& pos)
{
    VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM);

    for (NodeImpl *n = pos.node(); n; n = n->parentNode()) {
        if (VisiblePosition(n, 0, DOWNSTREAM) != vPos)
            return false;
        if (isSpecialElement(n))
            return true;
    }

    return false;
}

static bool isFirstVisiblePositionInSpecialElement(const Position& pos)
{
    VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM);

    for (NodeImpl *n = pos.node(); n; n = n->parentNode()) {
        if (VisiblePosition(n, 0, DOWNSTREAM) != vPos)
            return false;
        if (n->rootEditableElement() == NULL)
            return false;
        if (isSpecialElement(n))
            return true;
    }

    return false;
}

Position positionBeforeNode(const NodeImpl *node)
{
    return Position(node->parentNode(), node->nodeIndex());
}

static Position positionBeforeContainingSpecialElement(const Position& pos)
{
    ASSERT(isFirstVisiblePositionInSpecialElement(pos));

    VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM);

    NodeImpl *outermostSpecialElement = NULL;

    for (NodeImpl *n = pos.node(); n; n = n->parentNode()) {
        if (VisiblePosition(n, 0, DOWNSTREAM) != vPos)
            break;
        if (n->rootEditableElement() == NULL)
            break;
        if (isSpecialElement(n))
            outermostSpecialElement = n;
    }

    ASSERT(outermostSpecialElement);

    Position result = positionBeforeNode(outermostSpecialElement);
    if (result.isNull() || !result.node()->rootEditableElement())
        return pos;

    return result;
}

static bool isLastVisiblePositionInSpecialElement(const Position& pos)
{
    // make sure to get a range-compliant version of the position
    Position rangePos = VisiblePosition(pos, DOWNSTREAM).position();

    VisiblePosition vPos = VisiblePosition(rangePos, DOWNSTREAM);

    for (NodeImpl *n = rangePos.node(); n; n = n->parentNode()) {
        if (VisiblePosition(n, maxRangeOffset(n), DOWNSTREAM) != vPos)
            return false;
        if (n->rootEditableElement() == NULL)
            return false;
        if (isSpecialElement(n))
            return true;
    }

    return false;
}

Position positionAfterNode(const NodeImpl *node)
{
    return Position(node->parentNode(), node->nodeIndex() + 1);
}

static Position positionAfterContainingSpecialElement(const Position& pos)
{
    ASSERT(isLastVisiblePositionInSpecialElement(pos));

    // make sure to get a range-compliant version of the position
    Position rangePos = VisiblePosition(pos, DOWNSTREAM).position();

    VisiblePosition vPos = VisiblePosition(rangePos, DOWNSTREAM);

    NodeImpl *outermostSpecialElement = NULL;

    for (NodeImpl *n = rangePos.node(); n; n = n->parentNode()) {
        if (VisiblePosition(n, maxRangeOffset(n), DOWNSTREAM) != vPos)
            break;
        if (n->rootEditableElement() == NULL)
            break;
        if (isSpecialElement(n))
            outermostSpecialElement = n;
    }

    ASSERT(outermostSpecialElement);

    Position result = positionAfterNode(outermostSpecialElement);
    if (result.isNull() || !result.node()->rootEditableElement())
        return pos;

    return result;
}

static Position positionOutsideContainingSpecialElement(const Position &pos)
{
    if (isFirstVisiblePositionInSpecialElement(pos)) {
        return positionBeforeContainingSpecialElement(pos);
    } else if (isLastVisiblePositionInSpecialElement(pos)) {
        return positionAfterContainingSpecialElement(pos);
    }

    return pos;
}

static Position positionBeforePossibleContainingSpecialElement(const Position &pos)
{
    if (isFirstVisiblePositionInSpecialElement(pos)) {
        return positionBeforeContainingSpecialElement(pos);
    }

    return pos;
}

static Position positionAfterPossibleContainingSpecialElement(const Position &pos)
{
    if (isLastVisiblePositionInSpecialElement(pos)) {
        return positionAfterContainingSpecialElement(pos);
    }

    return pos;
}

//==========================================================================================
// Concrete commands
//------------------------------------------------------------------------------------------
// AppendNodeCommand

AppendNodeCommand::AppendNodeCommand(DocumentImpl *document, NodeImpl *appendChild, NodeImpl *parentNode)
    : EditCommand(document), m_appendChild(appendChild), m_parentNode(parentNode)
{
    ASSERT(m_appendChild);
    m_appendChild->ref();

    ASSERT(m_parentNode);
    m_parentNode->ref();
}

AppendNodeCommand::~AppendNodeCommand()
{
    ASSERT(m_appendChild);
    m_appendChild->deref();

    ASSERT(m_parentNode);
    m_parentNode->deref();
}

void AppendNodeCommand::doApply()
{
    ASSERT(m_appendChild);
    ASSERT(m_parentNode);

    int exceptionCode = 0;
    m_parentNode->appendChild(m_appendChild, exceptionCode);
    ASSERT(exceptionCode == 0);
}

void AppendNodeCommand::doUnapply()
{
    ASSERT(m_appendChild);
    ASSERT(m_parentNode);
    ASSERT(state() == Applied);

    int exceptionCode = 0;
    m_parentNode->removeChild(m_appendChild, exceptionCode);
    ASSERT(exceptionCode == 0);
}

//------------------------------------------------------------------------------------------
// ApplyStyleCommand

ApplyStyleCommand::ApplyStyleCommand(DocumentImpl *document, CSSStyleDeclarationImpl *style, EditAction editingAction, EPropertyLevel propertyLevel)
    : CompositeEditCommand(document), m_style(style->makeMutable()), m_editingAction(editingAction), m_propertyLevel(propertyLevel)
{
    ASSERT(m_style);
    m_style->ref();
}

ApplyStyleCommand::~ApplyStyleCommand()
{
    ASSERT(m_style);
    m_style->deref();
}

void ApplyStyleCommand::doApply()
{
    switch (m_propertyLevel) {
        case PropertyDefault: {
            // apply the block-centric properties of the style
            CSSMutableStyleDeclarationImpl *blockStyle = m_style->copyBlockProperties();
            blockStyle->ref();
            applyBlockStyle(blockStyle);
            // apply any remaining styles to the inline elements
            // NOTE: hopefully, this string comparison is the same as checking for a non-null diff
            if (blockStyle->length() < m_style->length()) {
                CSSMutableStyleDeclarationImpl *inlineStyle = m_style->copy();
                inlineStyle->ref();
                applyRelativeFontStyleChange(inlineStyle);
                blockStyle->diff(inlineStyle);
                applyInlineStyle(inlineStyle);
                inlineStyle->deref();
            }
            blockStyle->deref();
            break;
        }
        case ForceBlockProperties:
            // Force all properties to be applied as block styles.
            applyBlockStyle(m_style);
            break;
    }

    setEndingSelectionNeedsLayout();
}

EditAction ApplyStyleCommand::editingAction() const
{
    return m_editingAction;
}

void ApplyStyleCommand::applyBlockStyle(CSSMutableStyleDeclarationImpl *style)
{
    // update document layout once before removing styles
    // so that we avoid the expense of updating before each and every call
    // to check a computed style
    document()->updateLayout();

    // get positions we want to use for applying style
    Position start(endingSelection().start());
    Position end(endingSelection().end());

    // remove current values, if any, of the specified styles from the blocks
    // NOTE: tracks the previous block to avoid repeated processing
    // Also, gather up all the nodes we want to process in a QPtrList before
    // doing anything. This averts any bugs iterating over these nodes
    // once you start removing and applying style.
    NodeImpl *beyondEnd = end.node()->traverseNextNode();
    QPtrList<NodeImpl> nodes;
    for (NodeImpl *node = start.node(); node != beyondEnd; node = node->traverseNextNode())
        nodes.append(node);

    NodeImpl *prevBlock = 0;
    for (QPtrListIterator<NodeImpl> it(nodes); it.current(); ++it) {
        NodeImpl *block = it.current()->enclosingBlockFlowElement();
        if (block != prevBlock && block->isHTMLElement()) {
            removeCSSStyle(style, static_cast<HTMLElementImpl *>(block));
            prevBlock = block;
        }
    }

    // apply specified styles to the block flow elements in the selected range
    prevBlock = 0;
    for (QPtrListIterator<NodeImpl> it(nodes); it.current(); ++it) {
        NodeImpl *node = it.current();
        if (node->renderer()) {
            NodeImpl *block = node->enclosingBlockFlowElement();
            if (block != prevBlock) {
                addBlockStyleIfNeeded(style, node);
                prevBlock = block;
            }
        }
    }
}

#define NoFontDelta (0.0f)
#define MinimumFontSize (0.1f)

void ApplyStyleCommand::applyRelativeFontStyleChange(CSSMutableStyleDeclarationImpl *style)
{
    if (style->getPropertyCSSValue(CSS_PROP_FONT_SIZE)) {
        // Explicit font size overrides any delta.
        style->removeProperty(CSS_PROP__KHTML_FONT_SIZE_DELTA);
        return;

⌨️ 快捷键说明

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